Redis提供了客户端相关的API对其状态进行管理,我们可以利用这些api来更好的运维比如:
- 客户端连接数超过限制
- 客户端连接数缓冲区异常(可能客户端发了一个异常的请求,超过阈值)
- 客户端长时间不活动(超过idle时间,可主动断开)
- 一直阻塞(可以监控正在执行那个连接的什么命令)
本文参考《Redis开发与运维》
客户端通信协议
Redis使用RESP(Redis Serialization Protocol)实现客户端与服务端的交互,这种协议简单高效。比如命令 set hello world:
1 | *3 |
命令格式
<参数数量>CRLF $<参数1的字节数量> CRLF <参数1>CRLF
比如上的的命令,一共3个参数,分别是set、hello、world,其长度分别为3、5、5返回格式
- 状态回复:在RESP中的第一个字节为“+”
- 错误回复:第一个字节为“-”
- 整数回复:第一个字节为“:”
- 字符串回复:第一个字节为“$”
- 多条字符串回复:第一个字节为“*”
可以使用telnet命令测试,或者实现一个socket来模拟
java客户端
客户端操作比较简单重点关注两点:
- 每次执行完不需要连接的时候需要关闭连接
- Jedis的连接池使用方法
客户端API
client list
获取所有客户端列表,返回结果为多行数据,每一行代表客户端的连接信息
标识: id(客户端唯一标识)、addr(ip和端口)、fd(socket的文件描述符,如果是1代表是内部的伪客户端)、name(名称,可以设置)
输入缓冲区:qbuf、qbuf-free ,这个的作用是将客户端发送的命令临时保存,同时Redis会从输入缓冲区拉取命令并执行。没有规定大小,但有最大值1G,如果超过,则会断开连接,而且如果所有连接的缓冲区总和超过了总的内存限制,则会产生数据丢失、OOM的情况。
主要原因是,redis处理速度跟不上命令的速度,比如包含了大量的bigkey,如何解决呢?
- 通过定期执行client list命令,收集qbuf和qbuf-free找到异常的连接记录并分析,找到有问题的客户端(速度比较慢,可能阻塞)。
- 通过info clients 命令找到最大的输入缓冲区(无法精准定位到具体客户端)。
输出缓冲区:obl、oll、omem,同输入缓冲区一样,它的作用是保存执行的结果。但不同的是,可以设置client-output-buffer-limit,提供了更多的选项,内部使用动态缓冲区和固定缓冲区结合实现,obl代表固定缓冲区的长度(对象的个数,而不是字节大小),oll代表动态缓冲区列表的长度,omem代表使用的字节数。
1
2
3
4
5
6
7$ config get client-output-buffer-limit
1) "client-output-buffer-limit"
2) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
# <class> <hard limit> <soft limit> <soft seconds>
# normal 0 0 0
# slave 24M 64M 60
# pubsub 32M 8M 60上面代表了三组,分别是普通客户端、slave客户端、pubsub发布订阅客户端, hard limit 表示缓冲区超过了该值,立即关闭,soft表示,超过了该值多长时间才关闭。
处理方法与输入缓冲区类似,需要限制普通客户端的缓冲区,比如高并发下的monitor命令,但另外需要适当增大slave的输出缓冲区,如果master节点写入过大, slave如果缓冲区溢出,会导致复制重连。
客户端的存活状态:age、idle分表表示客户端已连接的时间和空闲时间(距离上一次操作)
客户端的限制:maxclients 和 timeout,一旦超过最大连接数,新的连接将被拒绝(注意连接泄露)可以使用
config get[set] :maxclients
查看或设置,使用info clients
查看当前连接数。timeout用来限制连接的最大空闲时间,也就是上面的idle最大值,如果超过则会断开,0表示不限制。客户端类型:flag=S、N、O分别代表slave、普通客户端、monitor命令。其他可能的状态:
flag 表示的类型 N 普通客户端 M master节点 S slave节点 O 当前客户端正在执行monitor命令 b 当前客户端正在等待阻塞 GETNAME 获取当前连接的名字 ID 获取当前连接的ID,每个客户端都有唯一的ID
主动关闭客户端:
client kill <ip>:<port>
暂停客户端:
client pause <timeout>
暂停(阻塞)客户端一定时间,注意这个时候所有普通和发布订阅客户端都将被阻塞,这是一个很危险的操作。monitor 监控redis状态,能够监控所有客户端的命令,一旦redis并发过大,那么该监控客户端的输出缓冲区将会非常大。
info stats:除了info clients命令和client list,
info stats
也有关于客户端的状态信息
客户端常见异常
在使用客户端的时候,无论是客户端还是服务端,使用不当就会产生一些问题
无法获取到连接
- 客户端侧连接池配置过小,导致无法拿到连接
- 客户端没有正确使用连接池,比如没有释放
- 客户端执行了慢查询,导致无法释放资源
- 服务端正在执行阻塞,导致命令或连接超时
读写超时或客户端连接超时 :
- 读写时间设置过短
- 命令不合理,导致执行时间超过阈值
- 网络不正常
- redis自身阻塞
客户端缓冲区异常:
- 输出缓冲区满,比如用get命令获取一个超大的数据,但配置的阈值较小
- 长时间空闲连接,被断开
- 不正常的并发操作连接
案例
Redis内存突增,主节点内存达到maxmemory
- 现象:客户端无法则正常调用
- 原因:1.大量数据写入,主从复制出现问题,2. 缓冲区不正常,可以排查(monitor命令等)
客户端周期性的超时
- 通过观察慢查询日志记录,发现只要有慢查询就会有大量连接超时。应尽量减少慢查询