Twisted框架中的HTTP接口性能问题分析与解决方案

文章目录

在某个客户的环境中,基于 Twisted 框架封装的 HTTP 接口在处理 Web 请求时表现出忽快忽慢的情况。客户反馈的一个具体问题是,一个页面上大约显示九个图表时,部分图表在加载时延迟明显,有时需要等待很长时间才能返回结果。虽然并发量和数据量不大,但在几天的运行后,性能却异常低下。

问题现象

项目在本地使用了三个 Twisted 进程,分别绑定到 127.0.0.1:8001127.0.0.1:8002127.0.0.1:8003。使用 Nginx 进行反向代理时,查看 Nginx 的日志发现,许多接口的响应时间超过 60 秒,有的甚至超过 100 秒。观察到这种性能问题具有规律性:所有响应缓慢的请求均指向 127.0.0.1:8003

疑点初步排查

最初,考虑到系统中存在许多定时任务,这些任务可能导致性能下降。然而,进一步分析后发现,慢请求与定时任务并无直接关联。由于客户环境限制,无法逐一暂停定时任务进行排查,原有的排查思路难以继续推进。

经过仔细检查 Nginx 的日志,发现所有慢请求均由 8003 处理。进而怀疑该进程是否开启了其他两个进程没有的定时任务配置,但配置文件内容检查显示三者配置相同。去掉 8003 的 upstream 后,服务恢复正常。

性能瓶颈调查

使用 strace 工具监控该进程,发现其不断重复发送类似日志的内容,并在遇到某个文件不存在的报错后,持续进入 sendto 状态,最终导致进程几乎瘫痪。该问题显然与 Twisted 框架中的 loggingobserver 机制有关。

在 Twisted 框架中,服务启动时会启动一个 loggingobserver,用于同时记录 Python 和 Twisted 的日志到同一个文件。此时,发现使用的 handler 是带有轮转功能的(rotating),而 strace 输出的错误信息显示,进程在处理日志时发生了递归死循环,导致 CPU 负载剧增。

根本原因定位

进一步查看 Twisted 框架代码,发现 logging 模块在处理日志轮转时,未进行文件存在性的检查,导致在删除文件时出现错误,最终引发了死循环。虽然在 GitHub 上查找了 CPython 的日志代码,发现逻辑上没有问题,但正式环境中使用的 Python 版本为 2.7.5,与最新版本 2.7.14 存在差异,后者在处理文件重命名时添加了存在性检查,修复了这一问题(见 Python Bug Tracker)。

解决方案

将 Python 环境升级至最新版本,即可解决此 bug,恢复系统的正常性能。尽管未找到引发递归死循环的具体原因,但可推测是由于框架特定实现和 Twisted 机制的结合所致。

小结

这次故障的解决过程提醒我们,在使用第三方框架时,保持代码的更新与维护至关重要,及时跟进已知问题和修复措施,有助于避免潜在的性能瓶颈和系统崩溃。对于系统中的定时任务和其他进程,也应定期进行性能监测,以确保服务的稳定性。


也可以看看