一 现象
业务侧报 jedis 客户端无法和redis集群建立连接 ,SocketTimeoutException报错日志如下:
二 问题分析排查
2.1 排查监控
检查redis 实例,该实例是八个节点的 redis 集群。其中数据节点 6 整体性能异常, 14:59-15:09 分 cpu 负载100%,内存使用量达到5G。
outflow 带宽增加13倍。
qps 从14:59 到15:00 分增加500个qps请求,根据qps 增量明显小于带宽增量,判断有bigkey 。
2.2 内存暴涨的原因
从监控指标来看14:58-15:09峰值2000/s,咨询开发发现hvals请求会将某个key xxx:resource 所有的 5300 组field value 对加载到内存中的输出缓冲区 。
Redis 的工作机制会给每个连接分配 输出区。Redis 为每个客户端设置的输出缓冲区也包括两部分:
一部分,是一个大小为 16KB 的固定缓冲空间,用来暂存 OK 响应和出错信息;
一部分,是一个可以动态增加的缓冲空间,用来暂存大小可变的响应结果。
程序大量调用hvals导致输出缓冲区暴增,等业务停止和限流之后,请求量下降,内存使用量迅速下降,2个监控项时间点也是吻合。
2.3 业务系统hang的原因
业务访问redis的链路是通过jedis访问 proxy 然后再访问 redis jedis ----> proxy ----> redis node proxy系统配置的连接最大值8w个连接 , 每个应用程序的客户端 jedis配置的是8 或者32个连接,总共有400台机器左右。proxy 侧的连接数远大于机器连接满的连接数量。
所以影响业务系统不可访问的其实是一个雪崩效应,redis 单个请求 hvals 耗费 10-12ms ,redis每秒最大处理100个请求,而监控显示每秒最高2000个 hvals ,造成redis侧有大量命令排队等待。客户端的 jedis 连接会持续等待请求返回结果,新的请求不断进来,将客户端的jedis 连接池耗尽,进而出现应用获取不到连接的报错。
三 解决方法
- 根据业务逻辑拆分 bigkey
- 使用 hget key field 的方式直接获取 field对应的value值。
hvals key 返回 (f1 v1, f2 v2, f3 f3),
hget key f1 返回 v1