调试mysql延迟与libevent回调实际发送回复时机问题

1 问题描述

某历史项目,被反馈 HTTP 请求失败率高,一直超时。遂,排查之。# 2 排查过程

2 排查过程

2.1 信息收集

根据调用 API,找到对应的服务、服务自身的日志文件、项目源码,以及调用方的日志。##

2.2 根据日志文件的初步分析:

shell 复制代码
I0928 16:26:43.937340 30062 MyHttpServer-- body:...
I0928 16:26:43.937624 30062 http response finised . result:...

根据日志信息显示,服务在不到 1ms 的时间就已经完成处理并返回响应了。反馈给调用方,让其排查自身。约半个时辰后,调用方反馈自身没有问题。好吧,something wrong...

重新进行自身日志和对方日志,按照时间线,核对,发现了两个问题:

  • 1.调用方,短时间内很多请求,但是自身服务,根据日志来看来只接收到一条. 类似于有某种过滤,或者限制频率的处理层存在.
  • 2.对方接收到的响应回复时间,是在整个自身服务的所有操作日志完成后的.

分析问题:

  • 1.这个暂时没有头绪,先放下.
  • 2.一种猜想,那就是我自身的日志打印的回复时间,并不是真正的回复时间.发送的回复应该是确实处理好了,但是因为某种原因,一直被阻塞住,没发出来.

ok,那需要进一步的信息收集和真伪信息的验证.

采用tcpdump对服务接口进行抓包.

shell 复制代码
# tcpdump -U  -i eth0 port 服务端口 -w ~/http.pcap &

分析抓包结果,回复确实是,30秒之后才真正发出的.这已经超时了.

2.3 结合服务源码深入分析

发现该服务使用的libevent创建的.所有的业务是在一个注册的http的处理函数中进行的.

cpp 复制代码
	// 设置回调函数
	//指定generic callback - 这是也给通用回调
	evhttp_set_gencb(_httpd, httpd_handler, NULL);

httpd_handler 内部做了两件事

  • 1.处理计算请求,得出结果.进行http响应回复.
  • 2.将处理结果,更新到数据库中.需要更新几个表中的记录.

没有学习过libevent,但是根据事实证据推断:

  • 1.对于第一步的响应,应当是在整个回调走完,回到libevent自身的运行层面时,才做的真正发送.
  • 2.第一步生成响应的整体处理时间,也就最多1ms以内就完成了.那么,延迟应该是出现在了后续的数据库操作中.此时看数据库的操作日志,能够看出一些延迟端倪,但是,具体延迟的原因,尚不清楚.

2.4 结合抓包,查看,验证mysql操作的延迟

重新针对mysql的操作进行抓包. 这一步收集的网络包,可以确认延迟发生在哪一段,是数据库本身延迟,还是自身服务处理的延迟问题.

shell 复制代码
tcpdump -U -i eth0 -w /root/mysql.pcap 'host mysql服务ip and port  mysql服务端口'

分析网络包发现:

在本服务对mysql进行建立连接时,延迟巨大. 服务端响应 Server Greeting 稳定耗时10秒延迟.

进一步,查看服务项目代码,发现

  • 1.每次对mysql的操作,都是重新建立连接,操作完成后断开.
  • 2.而每个请求,需要进行三次数据库操作.

至此,请求超时的30秒原因,已经查明:

  • 1.libevent的真正回复处理时机是在,回调函数完成后.
  • 2.回调函数中对mysql的数据库操作延迟问题,造成了整体的回复延迟问题.

3 总结处理

3.1 针对问题2

本次排查的核心经验是:服务日志显示处理完成,并不代表响应已经真正发出 。日志打印时间与实际网络发送时间之间存在时间差,排查超时问题时,必须结合抓包工具(如 tcpdump)从网络层验证真实行为,而不能只依赖应用日志。

最终定位到根因:libevent 的回调函数完成后才真正发送响应,而回调中对 MySQL 的每次操作都重新建立连接(每个请求三次),单次建连耗时约 10 秒,叠加后导致整体响应延迟 30 秒。

解决方案:修改本服务,以维护一个连接池,或者一个长连接 MySQL 的方式,避免每次请求都重新连接数据库的延迟问题。修复后回归验证,响应时间恢复正常。

3.2 针对问题1

截止目前还没有确定,因为在调用方和本服务中间,应该是没有所谓的过滤服务的.现在想,大概率是:* 1.延迟状态的项目源码,在libevent的单个回调没有执行完成时,阻塞的时间过长.

  • 2.导致在调用方短时间发送的后续请求,被丢弃,甚至直接在网络层面,就没有被从网卡取回.

这个需要在修复问题2的延迟问题后,后续再做验证.

相关推荐
旺仔学长 哈哈1 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
今晚打老虎2 小时前
c++之提高A(前缀和)(第三课)
数据结构·c++·算法
JosieBook2 小时前
【数据库】MySQL 实战精通系列 · 第6篇:InnoDB 存储引擎、日志与崩溃恢复
数据库·mysql
by209993 小时前
从结构体到对象:正式学习C++类的骨架、封装与this指针
c++·经验分享·学习
2601_962218614 小时前
C语言中三种库的编译和使用方法
开发语言·c++
jimy14 小时前
派生类重写基类虚函数(二):override的作用
开发语言·c++
ebiobiz5 小时前
基于 GD32 Embedded Builder (GEB) 与 Nimmake 的 MCU 工程搭建指南
c++·python·单片机·嵌入式硬件·mcu
hetao17338375 小时前
2026-09-29 hetao1733837 的刷题记录
c++·算法
:mnong5 小时前
几何内核“四大金刚“:ACIS、Parasolid、CGM、Open CASCADE 核心特征深度解析
c++·cad·cax