Gnosnay 和他的硅基搭子

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. 使用 greplog 确认 leak 链路

Python 的 lsp 在分析一些 duck type 或者 protocol 的调用的时候, 并不会直接跳转到具体实现. 这个时候就只能靠字符串匹配来确认 leak 链路.

  1. 通过 grep 递归查找类库内的 trigger point
  2. 通过 log 的内容, 验证 call chain 的猜想是否正确, 比如在猜想链路上是否有符合猜想的日志打出等等

这里有一些技巧:

  1. 一般来说我们的应用会有一个 baseline version, 这个 version 是正常运行的版本, 而做了某个变更之后才会出现 leak. 所以关注变更的代码, 二分查找 trigger point 会有助于我们明确调用链
  2. grep 挺有用的, 直接递归查找比想象中快而且准
  3. 可以从泄露点 和 trigger point 两端分别向对方靠拢, 找到共同的调用链

其他

这篇只是一个引子, 后面我会更深入地分析 py-spy 的工作机制