go Redis SDK线程实现导致延迟问题分析说明
6. 与客户沟通,podA设置了liveness和readiness probe,探测http端口,问题发生期间,没有出现异常,说明node本地容器网络没有问题。1.客户做压力测试时问题发生,在podA内手工发送http本地请求,延迟明显,有时延迟2-10s,有时卡住curl不退出。PodB没有明显卡顿。在进行压力测试过程中,发现客户端访问业务pod访问有延迟,共两个pod,一个延迟大(2-10s
一、问题描述
在进行压力测试过程中,发现客户端访问业务pod访问有延迟,共两个pod,一个延迟大(2-10s),一个延迟小。
二、业务场景分析
client端请求podA的处理过程为
①podA接受请求
②podA请求Pod(geocrowd),成功后执行③
③podA请求Pod(place-search), 成功后执行④
④podA请求Redis实例,成功后返回结果给client端。
三、问题观测和分析过程
阶段一
1.客户做压力测试时问题发生,在podA内手工发送http本地请求,延迟明显,有时延迟2-10s,有时卡住curl不退出。PodB没有明显卡顿。
2. http本地请求卡顿时,podA内手工发送http请求访问Pod(geocrowd),没有明显延迟(没有秒级延迟)
3. http本地请求卡顿时,podA内手工发送http请求访问Pod(place-search),没有明显延迟(没有秒级延迟)
4. 在podA测试redis端口连通性,正常。telnet <redisip> 6379
5. 查看pod的cpu利用率,内存使用率,监控平台查看网卡出入流量,没有发现瓶颈。
6. 与客户沟通,podA设置了liveness和readiness probe,探测http端口,问题发生期间,没有出现异常,说明node本地容器网络没有问题。
pod到redis之间的网络环节不确定是否有问题。
根据6,网络环节①没有问题,根据2和3,网络环节②,③没有问题。
根据4,确定redis IP Port连通性没有问题。但是redis是否有延迟或卡顿不能确认。
基于以上信息,怀疑Redis请求可能会出问题,需要进一步观测。
7.客户对podA没有对各环节做详细的延迟监控,没有关键路径的日志,异常日志等。所以需要继续找其他信息来定位。
8.客户业务(podA, podB)进程开放了golang pprof端口,抓取golang运行时调试信息,方法参见:https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/
提取goroutine调用栈: curl -o debughttp://10.20.128.151:15033/debug/pprof/goroutine?debug=2
podA与podB的goroutine调用栈对比,发现podA有goroutine 4400+,有4300+跟redis访问相关,都在等待semphore。没有问题的Pod goroutine只有100-400个。
阶段二
1.客户继续压测,继续观测pod状态,
redis实例在可用区prod_sh01, 推测podA和podB的不同表现可能是AZ间网络延迟增加造成的。
2.wireshark抓包分析,发现有redis数据流有异常。
3.转给redis侧分析,结合 go-redis的代码 + tcpdump抓的包 + goroutine调用堆栈
发现有两个问题:
(1) go-redis的cluster pipeline模式依赖command命令,京东云Redis不支持command命令。
在不支持command命令的情况下,所有访问的redis命令都会变成串行执行,并且会多发出一个command命令(2) 发现有时候会发送参数个数为0的mget命令(这个对性能没有影响)
4. redis侧给出解决方案: 升级redis服务,支持command命令
5. 升级完成后,客户重新压测,redis阻塞协程数都为0,tcp连接数达到连接池最大值200.
6.客户反馈业务延迟降低,TP99最高1.5s左右,QPS接近正常。后续逐步切量。
四、结论
中间件Redis不支持command命令,导致客户侧redis client异常,goroutine堆积阻塞,造成卡顿。
五、后续优化项
TP99最高仍有1.5s左右,后续用户切业务中,业务峰值流量是否能支持有待观察,需要继续优化。
更多推荐
所有评论(0)