Python 下 Threads Leak 问题排查
TL;DR
py-spy & grep & log 立功. py-spy 确认 leak 点, grep & log 确认 leak 链路
背景
最近在做一个安全加固, 引入了 second party lib 之后, 某日告警说 CPU 使用率异常 + fd 泄露.
这个 second party lib 是用来代理 HTTP 请求的, 通过这个 proxy 我们可以确保请求是可信的.
排查过程
1. 使用 py-spy 确认 leak 点
py-spy 除了可以用来做 Python 的性能分析, 还可以用来做线程 dump. 我们使用 py-spy 来确认 leak 点.
py-spy dump <pid>
通过这个命令, 你可以看到当前进程的线程栈. 如果某个进程有大量的雷同的线程栈, 那么这个进程就有可能存在 leak. leak point 就是重复出现的线程。
2. 使用 grep 和 log 确认 leak 链路
Python 的 lsp 在分析一些 duck type 或者 protocol 的调用的时候, 并不会直接跳转到具体实现. 这个时候就只能靠字符串匹配来确认 leak 链路.
- 通过
grep递归查找类库内的 trigger point - 通过
log的内容, 验证 call chain 的猜想是否正确, 比如在猜想链路上是否有符合猜想的日志打出等等
这里有一些技巧:
- 一般来说我们的应用会有一个 baseline version, 这个 version 是正常运行的版本, 而做了某个变更之后才会出现 leak. 所以关注变更的代码, 二分查找 trigger point 会有助于我们明确调用链
grep挺有用的, 直接递归查找比想象中快而且准- 可以从泄露点 和 trigger point 两端分别向对方靠拢, 找到共同的调用链
其他
这篇只是一个引子, 后面我会更深入地分析 py-spy 的工作机制