问题:
在项目中接入redis的订阅消费功能,服务端发布消息,客户端订阅到消息后进行业务操作。结果发现在订阅端会间歇性地出现超时问题
排查:
(1)开始以为就是超时,于是调整了redis的超时配置
原:connectTimeout=3 调整为:connectTimeout=10
但依然会报超时错,并且一来redis操作的数据量并不大,二来其他的逻辑也存在同样数据的操作,并没有发生异常,所以判断不是命令执行时间配置本身问题。
(2)通过观察日志发现超时都是发生在订阅逻辑之后,怀疑是订阅的缓冲设置问题
于是查看当前缓冲设置
xx.xx.xx.xx:8080> config get client-output-buffer-limit 1) "client-output-buffer-limit" 2) "normal 0 0 0 slave 34359738368 8589934592 0 pubsub 33554432 8388608 60"
看出在订阅消费模式下,当客户端输出缓冲达到32M或持续60s达到8M就会断开客户端连接。于是调大该参数
client-output-buffer-limit pubsub 64mb 16mb 120
依然还是报错。
(3)经过长时间的日志观察,发现只有在订阅后进行redis操作,才会抛异常,所以进入redis官网查看发布/订阅的文档,发现以下两处说法:
https://lettuce.io/core/release/reference/#pubsub.subscribing
https://lettuce.io/core/snapshot/reference/
https://zhuanlan.zhihu.com/p/44439782
https://lettuce.io/core/release/reference/#pubsub.subscribing
不要在发布订阅的回调中发起阻塞的操作。
https://lettuce.io/core/snapshot/reference/
超时可能是因为阻塞操作打破了时间循环。
然后查看了代码,发现确实在订阅的回调中,发起了redis的阻塞命令。于是尝试将订阅动作和消息的处理逻辑解耦异步,在订阅中只接受保存消息,然后用
另外的线程去处理消息。
最终异常没有再出现。
排查过程记录如上。