You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调试陷入BUSY状态且占用内存的uWSGI Worker?

调试uWSGI/Django Worker僵死问题的实用方法

这种worker突然进入BUSY状态、耗尽内存导致实例崩溃的情况,在生产环境里确实让人头疼。结合我自己的实战经验,分享几个快速且规范的调试思路,帮你定位到具体的请求和函数:

1. 实时抓取BUSY Worker的当前请求

当你通过uwsgitop发现异常worker时,立刻用uWSGI自带的工具查看它正在处理的请求,这是最直接的方法:

  • 如果你的uWSGI用的是unix socket,执行:
uwsgi --connect-and-read /path/to/your/uwsgi/socket
  • 如果是TCP端口监听,执行:
uwsgi --connect-and-read 127.0.0.1:3031

这个命令会直接输出该worker当前处理的请求详情,包括HTTP方法、请求路径,甚至部分参数。结合Django的路由配置,你能快速对应到具体的视图函数。

2. 开启uWSGI请求追踪日志

修改你的uWSGI配置文件,添加日志增强参数,让它记录每个请求的完整生命周期,包括worker ID、处理时长、内存占用:

# 自定义日志格式,包含关键信息
log-format = %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) %(micros)s %(memuse)B worker:%(worker_id)
# 开启请求级别的详细日志
log-req = true

重启uWSGI后,日志会清晰记录每个worker处理的所有请求。当异常发生时,你可以根据worker ID和时间范围,筛选出它崩溃前处理的最后几个请求,缩小排查范围。

3. 实时追踪函数调用栈(用pyrasite/gdb)

如果worker已经僵死但还没崩溃,你可以附加到进程上查看当前的函数调用栈:

  1. 先找到异常worker的PID:
ps aux | grep uwsgi
  1. 安装pyrasite后,执行命令进入该进程的交互式Python shell:
pyrasite <worker_pid>
  1. 在shell里打印当前的调用栈:
import traceback
import sys

# 获取所有线程的调用栈
frames = sys._current_frames()
for thread_id, frame in frames.items():
    print(f"Thread {thread_id}:")
    traceback.print_stack(frame)

这样你就能看到worker卡在哪个函数里,是数据库查询、外部API调用还是某个业务逻辑导致的问题。

4. 事后分析:生成core dump排查内存问题

如果worker已经崩溃,你可以提前配置uWSGI生成core dump文件,事后用gdb分析:

  • 在uWSGI配置里添加:
enable-corefile = true
corefile-path = /var/uwsgi/core-dumps/
  • 当worker崩溃后,用gdb加载core文件:
gdb /path/to/uwsgi /var/uwsgi/core-dumps/core.<pid>
  • 在gdb中执行py-bt命令,就能看到Python层面的调用栈,定位到引发内存泄漏或死循环的函数。

5. Django层面添加请求监控中间件

在Django里自定义一个中间件,记录每个请求的视图函数、处理时长和内存变化:

import time
import os
import psutil
from django.utils.deprecation import MiddlewareMixin

class RequestMonitorMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        request.start_time = time.time()
        request.start_mem = psutil.Process(os.getpid()).memory_info().rss
        request.view_func = view_func.__name__

    def process_response(self, request, response):
        if hasattr(request, 'start_time'):
            duration = round(time.time() - request.start_time, 2)
            end_mem = psutil.Process(os.getpid()).memory_info().rss
            mem_diff = round((end_mem - request.start_mem) / 1024 / 1024, 2)
            # 可以将日志写入专门的文件或监控系统
            print(f"Worker {os.getpid()} | View: {request.view_func} | Duration: {duration}s | Mem Change: {mem_diff}MB")
        return response

把这个中间件添加到Django的MIDDLEWARE配置中,这样你就能在日志里看到每个视图的内存消耗情况,快速定位到内存暴涨的业务函数。

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:16:31