一、慢查询分析
慢查询日志帮助开发和运维人员定位系统存在的慢操作。慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(慢查询ID,发生时间戳,耗时,命令的详细信息)记录下来。
⑴慢查询的两个配置参数
◎慢查询的预设阀值 slowlog-log-slower-than
①单位是微秒,默认值是1000;
②如果slowlog-log-slower-than的值是0,则会记录所有命令;
③如果slowlog-log-slower-than的值小于0,则任何命令都不会记录日志。
◎慢查询日志的长度slowlog-max-len
slowlog-max-len只是说明了慢查询日志最多存储多少条。Redis使用一个列表来存储慢查询日志,showlog-max-len就是列表的最大长度。
--通过修改配置文件或命令修改;
⑵基本命令
◎获取慢查询日志 slowlog get [n]
◎获取慢查询日志列表当前长度 slowlog len
◎慢查询日志重置 slowlog reset
⑶最佳实践
①slowlog-max-len的设置建议:线上环境建议调大慢查询日志的列表,记录慢查询日志时Redis会对长命令做截断操作,并不会占用大量内存。增大慢查询列表可以减缓慢查询被剔除出列表的可能性。例如线上可以设置为1000以上。
②slowlog-log-lower-than的设置建议:需要根据redis的并发量调整该值。由于redis采用单线程响应名利,对于高流量的场景,如果执行命令的时间在1毫秒以上,那么redis最多可支撑OPS(每秒操作次数)不到1000,因此高OPS场景的REDIS建议设置为1毫秒。
③慢查询只记录命令执行时间,并不包括命令排队时间和网络传输时间。
因此客户端命令的执行时间要大于redis服务器实际执行命令的时间。
因为命令执行排队极致,慢查询会导致命令级联阻塞,因此当客户端出现请求超时,需要检查该时间点是否有对应的慢查询,从而分析是否因为慢查询导致的命令级联阻塞
④慢查询日志是一个先进先出队列,慢查询较多的情况下,可能会丢失部分慢查询命令,可以定期执行slow get命令将慢查询日志持久化到其他存储中。然后制作可视化界面查询。
二、Redis Shell
⑴redis-cli讲解
◎查看redis-cli命令帮助 redis-cli help
◎按指定的次数重复执行命令 redis-cli –r count commond
◎几秒钟执行一次命令 redis-cli –i seconds command
◎从标准输入读取数据做为redis-cli的最后一个参数
echo ‘’ | redis-cli –x command
◎连接集群防止moved和ask异常 redis-cli –c
◎配置密码 redis-cli –a
◎扫描指定模式键 redis-cli –scan和-pattern
◎模拟Redis从节点 redis-cli –slave
◎生成并发送RDB持久化文件 redis-cli –rdb
◎批量命令封装 redis-cli --pipe
◎找到内存占用较大的键值 redis-cli –bigkeys
◎检测网络延迟 redis-cli –latency
---Latency有三个选型,分别是—latency,--latency-history、--latency-dist
◎实时获取redis重要统计信息 redis-cli –stat
◎命令的返回结果是否原始格式 redis-cli –raw 和 --noraw
⑵redis-server讲解
◎默认配置启动 redis-server
◎运行配置启动 redis-server --port 6389 –timeout 3000
◎配置文件启动 redis-server redis.conf
◎内存检测 redis-server–test-memory 1024
⑶redis-benchmark讲解
◎redis-benchmark [-c 并发数] [-n 总请求数] [–q][-r count]
三、PiPline
Redis客户端与Redis之间使用TCP协议进行连接,一个客户端可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client,因此当执行多条命令的时候都需要等待上一条命令执行完毕才能执行,而管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间。
⑴原理展示
⑵比较结果
/*
* 测试普通模式与PipeLine模式的效率:
* 测试方法:向redis中插入10000组数据
*/
public static void testPipeLineAndNormal(Jedis jedis) throws InterruptedException
{
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++)
{
jedis.set(String.valueOf(i), String.valueOf(i));
}
long end = System.currentTimeMillis();
System.out.println("the jedis total time is:" + (end - start));
Pipeline pipe = jedis.pipelined();// 先创建一个pipeline的链接对象
long start_pipe = System.currentTimeMillis();
for (int i = 0; i < 10000; i++)
{
pipe.set(String.valueOf(i), String.valueOf(i));
}
pipe.sync();// 获取所有的response
long end_pipe = System.currentTimeMillis();
System.out.println("the pipe total time is:" + (end_pipe - start_pipe));
BlockingQueue<String> logQueue = new LinkedBlockingQueue<String>();
long begin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++)
{
logQueue.put("i=" + i);
}
long stop = System.currentTimeMillis();
System.out.println("the BlockingQueue total time is:" + (stop - begin));
}
四、事务与Lua脚本
事务,一组动作,要么全部执行,要么就全部不执行。从而避免出现数据不一致的情况。
redis提供了简单的事务功能,将一组需要的命令放到multi和exec两个命令之间,multi代表事务开始,exec代码事务结束。
⑴事务的基本命令
◎事务开始 multi
◎事务结束 exec
◎事务乐观锁 watch
◎事务停止 discard
---在事务中如果出现命令错误或运行时错误,针对命令错误将会造成整个事务无法进行,而运行时错误由于redis无回退功能,只能由开发人员自己解决。
⑵Redis与Lua脚本的使用
在Redis中执行Lua脚本的方法主要有两种:eval和evalsha。
①eval 脚本内容 key个数 key列表 参数列表
eval ‘return “hello” .. KEYS[1] .. ARGV[1]’ 1 redis world
---如果Lua脚本较长,还可以使用redis-cli --eval直接执行文件
②evalsha
redis-cli script load “$(cat lua_get.lua)”
evalsha 脚本SHA1值 key个数 key列表 参数列表
⑶Redis管理Lua脚本
◎将Lua脚本加载到redis内存中 script load script
◎是否将sha1加载到redis内存中 scripts exists sh1 [sha1 ...]
◎清除加载到redis内存中的所有Lua脚本 script flush
◎用于杀掉正在执行的Lua脚本 script kill
五、Bitmaps
Bitmaps可以用来做独立用户统计,有效节省内存。
⑴基本命令:
◎设置值 setbit key offset value (offset从0开始)
◎获取值 getbit key offset
◎获取指定范围内值为1的个数 bitcount [start] [end] start与end代表字节数
◎bitmaps间的运算 bitop op destkey key [key ...]
--op: and or not xor 交并非异运算
◎计算bitmaps中第一个值为targetbit的偏移量
Bitpos key targetbit [start] [end]
⑵bitmaps的分析
假设网站有1亿用户,每天独立访问的用户有5千万,如果每天用集合类型和Bitmaps分别存储活跃用户,set和Bitmaps存储一天活跃用户的对比如下
数据类型 每个用户id占用空间 需要存储的用户量 全部内存量
集合类型 64位 50 000 000 64位×50 000 000 = 400MB
Bitmaps 1位 100 000 000 1位×100 000 000 = 12.5MB
很明显,这种情况下使用Bitmaps能节省很多的内存空间,尤其是随着时间推移节省的内存还是非常可观的,set和Bitmaps存储独立用户空间对比:
一天 一个月 一年
set 400M 12G 144G
Bitmaps 12.5M 375M 4.5G
Bitmaps并不是万金油,假如该网站每天的独立访问用户很少,例如只有10万(大量的僵尸用户),那么两者的对比如下,set和Bitmaps存储一天活跃用户的对比(独立用户比较少):
数据类型 每个userid占用空间 需要存储的用户量 全部内存量
集合类型 64位 100 000 64位 × 100 000 = 800KB
Bitmaps 1位 100 000 000 1位 × 100 000 000 = 12.5MB
很显然,这时候使用Bitmaps就不太合适了,因为基本上大部分位都是0。
六、HyperLogLog
HyperLogLog虽然在统计独立总量时存在一定的误差0.81%,但是节省内存量是十分惊人的。
⑴基本命令:
◎添加 pfadd key element [element ...]
◎计算独立用户数 pfcount key [key ...]
◎合并 pfmerge destkey source [source ...]
⑵性能对比(百万级用户量占用空间比)
一天 一个月 一年
set 80M 2.4G 28G
HyperLogLog 15k 450k 5M
七、发布订阅
Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。
⑴基本命令
◎发布消息 publish channel message
◎订阅消息 subscribe channel [channel ...]
◎取消消息 unsubscribe channel [channel ...]
◎按照模式订阅和取消订阅 psubscribe pattern [pattern...]
punsubscribe pattern [pattern...]
◎查看活跃频道 pubsub channels [pattern]
◎查看频道订阅数 pubsub numsub [channel ...]
◎查看模式订阅数 pubsub numspat
⑵使用场景
- 视频服务订阅video:change频道
subcribe video:change
- 视频管理系统发布消息到video:change频道
publish video:change “video1, video3, video5”
- 当视频服务收到消息,对视频信息进行更新
for video in video1, video3, video5
update{video}
八、GEO
主要用于诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
◎增加地理位置信息 geoadd key longitude latitude member [longitude latitude member ...]
◎获取地理位置信息 geopos key member [member ...]
◎获取两个地理位置的距离 geodist key member1 member2 [unit]
---unit代表返回单位:m km mi ft
◎获取指定位置范围内地理信息位置信息
georadius key longitude latitude radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
georadiusbymember key memeber radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
◎获取geohash geohash key member [member ...]
◎删除地理位置信息 zrem key member