一 慢查询
许多存储系统提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阈值,就将这条命令的相关信息记录下来。
慢查询只统计步骤3的时间,所以没有慢查询并不代表客户端没有超时问题。
1 慢查询的配置参数
对于慢查询,需要明确:
- 预设阈值怎么设置?
- 慢查询记录存放位置
redis提供了sloglog-log-slower-than(预设阈值,单位:微秒,默认10000)和slowlog-max-len(最多存储条数)配置来解决这两个问题。慢查询实际上使用一个列表来存储慢查询日志,当慢查询日志列表大于其最大长度时,最早插入的命令会被从列表中移出。
redis修改配置方法:
- 通过配置文件;
- config命令
config rewrite命令可以将配置持久化到本地文件中。
(1)获取慢查询日志
slowlog get [n]
获取指定条数的日志
慢查询日志结构:标识ID,发生时间戳,命令耗时,执行命令和参数
(2)获取漫查询日志列表当前的长度
slowlog len
(3)慢查询日志重置
slowlog reset
2 慢查询参数调优
- slowlog-max-len配置建议:线上建议调大慢查询列表,记录慢查询时redis会对长命令做截断操作,并不会占用大量内存。增大慢查询列表可以减缓慢查询被踢除的可能;
- slowlog-log-slower-than配置建议:默认超过10毫秒判定慢查询,需要根据redis并发量调整该值,由于redis采用单线程调用命令,对于高流量的场景,如果命令执行时间在1毫秒以上,那么redis最多可制成ops不到1000。因此对于高ops场景的redis建议 设为1毫秒;
- 慢查询只记录命令执行时间,不包括命令排队和网络传输时间,因此客户端执行命令时间会大于命令实际执行时间,因为命令执行排队机制,慢查询会导致其他命令级联阻塞,因此客户端出现请求超时时,需要检查该时间点是否有对应的慢查询,从而分析出是否为慢查询导致的命令级别阻塞;
- 由于慢查询日志是一个先进先出的队列,也就是慢查询比较多的情况下,可能会丢失部分查询命令,为了防止这种情况,可以定期执行slow get命令将查询日志持久化到其他存储中。
二 redis shell
1 redis-cli
命令参数:
- -r(repeat):代表将命令执行多次。 redis-cli -r 3 ping表示执行ping命令3次
- -i:表示每隔几秒执行一次命令,必须和-r一起使用
- -x:从标准输入读取数据作为redis-cli的最后一个参数。例:echo "world" | redis-cli -x set hello
- -c(cluster):连接redis cluster使用,-c选项可以防止moved和ack异常
- -a:redis配置密码时,-a是用做不用手动输入auth命令
- --scan和--pattern:用于扫描指定模式的键,相当于scan
- --slave:把当前客户端模拟成当前redis节点的从节点,可以用来获取当前redis的更新操作。
- --rdb:请求redis实例生产并发送rdb持久化文件,保存在本地。
- --pipe:将命令封装成redis通信协议定义的数据格式,批量发送给redis执行。
- --bigkeys:使用scan命令对redis的键进行采样,从中找到内存占用比较大的键值,这些键可能是系统的瓶颈。
- --eval:用于执行指定lua脚本
- --latency:用于检测网络延迟。(1)--latecy检测客户端到目标redis的网络延迟(2)--latency-history分时检测网络延时(3)--latency-dist使用统计图表的形式从控制台输出延迟统计信息
- --stat:可以实时获取redis的统计信息
- --raw和--no-raw:--no-raw要求命令的返回结果必须是原始的格式,--raw是返回格式化后的格式。
2 redis-server
命令是启动redis。
--test-memory选项用来检测当前操作系统能否稳定地分配指定容量的内存给redis,通过这种检测可以有效避免因为内存问题造成redis崩溃。
3 redis-benchmark
为redis做基准性能测试。
- -c:代表客户端的并发数量;
- -n <requests>:代表客户端请求总量(默认100000)
- -q:显示redis-benchmark的requests per second信息
- -r:在一个空的redis执行了redis-benchmark会发现只有3个键
- -P:代表每个请求pipeline的数据量
- -k <boolean>:代表客户端是否使用keepalive。1为使用,0为不使用,默认1
- -t:对指定命令进行基准测试
- --csv:将结果按照csv格式输出
三 PipeLine
1 pipeline概念
pipeline流水线机制能改善上面这类问题,它能将一组redis命令进行组装,通过一次RTT传输给redis,再将这组redis命令的执行结果按照顺序返回客户端。
pipeline执行速度一般比逐条执行要快,客户端和服务端的网络延时越大,pipeline的效果越明显。
2 原生批量命令和pipeline对比
- 原生批量命令是原子的,pipeline是非原子的;
- 原生批量命令是一个命令对应多个key,pipeline支持多个命令;
- 原生批量命令是redis服务支持实现的,pipeline需要服务端和客户端的共同实现。
pipeLine虽然好用,但是每次pipeline组装的命令个数不能没有节制,否则一次组装pipeline数据量过大,一方面会增加客户端的等待时间,另一方面会造成一定的网络阻塞,可以将一次包含大量命令的pipeline拆分成多次较小的pipeline来玩成。
pipeline只能操作一个redis实例,但是即使在分布式redis场景中,也可以作为批量操作的重要优化手段。
四 事务与Lua
为了保证多条命令组合的原子性,redis提供了简单的事务功能以及继承lua脚本来解决这个问题。
1 事务
redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和exec两个命令之间。multi代表事务开始,exec代表事务结束,他们之间的命令是原子顺序执行的。
如果要停止事务的执行,可以使用discard命令代表exec命令即可。
如果事务的命令出现错误,redis的处理机制也不尽相同:
(1)命令错误
命令写错时会造成事务无妨执行。
(2)运行时错误
redis提供了watch命令解决这些问题
五 Bitmaps
1 数据结构模型
- Bitmaps本身不是一种数据结构,实际上它就是字符串,但是它可以对字符串的位进行操作;
- Bitmaps单独提供了一套命令,所以在redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
2 命令
本节将每个独立用户是否访问过网站存放在Bitmaps中,将访问的用户记作1,未访问的用户记作,用偏移量作为用户的id。
(1)设置值
setbit key offset value
很多应用的用户id以一个指定数字开头,直接将用户id和Bitmaps的偏移量对应势必会造成一定的浪费,通常的做法是每次做setbit操作时将用户id减去这个指定数字。在第一次初始化Bitmaps时,假如偏移量非常大,那么整个初始化过程执行会比较慢,可能会造成redis阻塞。
(2)获取值
getbit key offset
(3)获取Bitmaps指定范围值为1的个数
bitcount [start] [end]
(4)Bitmaps间的运算
bitop op destkey key [key....]
bitop是一个复合操作,它可以做多个Bitmaps的and交集、or并集、not非、xor异或操作并将结果保存在destkey中。
(5)计算Bitmaps中第一个值为targetBit的偏移量
bitpos key targetBit [start] [end]
3 Bitmap分析
六 HyperLogLog
HyperLogLog并不是一种数据结构(实际类型为字符串),而是一种基数算法。通过HyperLogLog可以利用极小的内存空间完成独立总数的统计。
1 命令
(1)添加
pfadd key element [element...]
(2)计算独立用户数
pfcount key [key...]
(3)合并
pfmerge destkey sourcekey [ sourcekey...]
2 HyperLogLog分析
HyperLogLog内存占用量非常小,但是存在错误率,开发者在进行数据结构选型时只需确认如下两条即可:
- 只为了计算独立总数,不需要获取单条数据;
- 可以容忍一定误差率,毕竟HyperLogLog在内存的占用量上有很大的优势。
七 发布订阅系统
redis提供了发布订阅模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道发布消息,订阅该频道的每个客户端都可以收到该消息。
1 命令
(1)发布消息
publish channel message
(2)订阅消息
subscribe channel [channel...]
订阅者可以订阅一个到多个channel。如果发布者发布了一条消息,订阅者会收到发布者发布的消息。
如果有多个订阅者同时订阅了channel,订阅者们都会收到channel发布的消息。
订阅命令注意:
- 客户端在执行订阅命令后进入订阅状态,只能接收subscribe、psubscribe、unsubscribe、punsubscribe的四个命令;
- 新开启的客户端,无法接收该频道之前的消息,因为redis不会对发布的消息进行持久化。
(3)取消订阅
unsubscribe [channel [channel...]]
(4)按照模式订阅和取消订阅
psubscribe pattern [pattern...]
punscribe [pattern [pattern...]]
(5)查看订阅
- pubsub channels pattern:查看活跃的频道
- pubsub numsub [channel...]:查看频道订阅数
- pubsub numpat:查看模式订阅数
八 GEO(地理信息定位)
redis3.2版本提供了GEO功能,支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能,对于需要实现这些功能。
1 命令
(1)增加地理位置信息
geoadd key longitude latitude member [longitude latitude member...]
- longitude:代表地理位置的经度
- latitude:代表地理位置的纬度
- member:代表地理位置的成员
(2)获取地理位置信息
geopos key member [member....]
(3)获取两个地理位置的距离
geodist key member1 member2 [unit]
unit代表返回结果的单位,支持下面四种:
- m:米
- km:公里
- mi:英里
- ft:尺
(4)获取指定位置范围内的地理信息位置集合
georadius key longitude latitude radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
georadiusby member key member radiusm|km|ft|mi [withcoord] [withdist] [withhash] [COUNT count] [asc|desc] [store key] [storedist key]
这两个命令都是以一个地理位置为中心算出给定半径内的其他地理信息位置。
参数:
- withcoord:返回结果包含经纬度
- withdist:返回结果包含离中心借点位置的距离
- withhash:返回结果中包含geohash
- COUNT count:指定返回结果的数量
- asc|desc:返回结果按照离中心节点的距离做升序或降序
- store key:将返回结果的地理位置信息保存到指定键
- storedist key:将返回结果离中心节点的距离保存到指定键