服务压测偶现卡住问题分析

服务框架介绍

服务是一个生产者,一个消费者,通过对象池分配对象,通过加锁队列进行数据交互。

现象

通过观察服务日志,发现服务经常报timeout错误

初步定位

内核打印执行步骤,发现服务是阻塞在最后一帧,由于内核没有发出最后一帧,因此服务一直在尝试获取最后一帧

详细日志分析

通过分析,发现最后一帧数据没有发出来是因为队列中数据被破坏了,生产者生产了数据,压入队列,消费者在提取数据时,队列中链表关系就被破坏了

分析过程

第一步:因为对象池和加锁队列都已经运行5年了,开始不能怀疑是这两个结构出了问题,对于这种异常,先怀疑是最近修改的代码导致内存越界,因此引发这种异常现象。
结论:通过内存检测工具,未发现内核有内存泄露

第二步:开始分别阅读对象池和加锁队列源码
结论:两份源码都没有发现异常,但是发现对象池和加锁队列共用一个队列,两者都会对元素的前项指针和后项指针进行操作,这是有问题的

第三步:放弃使用对象池,直接分配内存
结论:问题被解决,但是实现方案不好,频繁分配内存会造成内存碎片,继续研究对象池方案

第四步:拆分对象池和加锁队列,让他们使用不同的链表节点
结论:测试下来没有解决问题

第五步:继续加日志,分析日志
结论:在分析过程中发现服务运行中会出现队列中的数据和队列长度不一致的情况。

第六步:对于数据和队列长度不一致的情况,怀疑是队列没有加锁导致,对队列加锁部分增加日志
结论:队列加锁没有问题,但是偶然发现从对象池中获取数据,在没有归还之前居然还可以取出来继续被使用,这里不符合预期,
检查对象池代码,发现对象池和加锁队列还是共用的一个链表节点,修改代码继续测试

最终结论:问题解决。

小结

其实对象池本身是没有问题的,加锁队列本身也是没有问题。当时在第二步我就发现对象池和加锁队列共用链表可能有问题,
但是当时修改代码不细致,得出了第四步错误的结论,使得我定位问题多花了一天时间。
定位这种问题,修改代码一定要细节,修改的部分可以加日志确认,问题分析正确由于错误的编码得出错误的结论是不应该的。

posted on 2023-12-28 14:52  寒魔影  阅读(15)  评论(0编辑  收藏  举报

导航