Django应用部署到生产环境后响应变慢,排查起来容易一头雾水。先别急着调并发参数或上缓存,很多瓶颈来自常见的配置遗漏或逻辑问题。以下按优先级列出几个检查点,每个都附带操作动作、验证方式和风险边界。
先检查数据库查询是否成瓶颈
如果响应缓慢,首先检查数据库查询是否成为瓶颈。启用Django的DEBUG模式后,在浏览器或日志中查看django.db.backends的查询日志,关注是否有大量重复查询或未使用索引的慢查询。使用connection.queries可以实时查看当前请求的所有SQL语句。如果发现同一查询多次执行,考虑使用select_related或prefetch_related减少查询次数。对于慢查询,通过数据库的EXPLAIN命令分析索引使用情况,必要时添加联合索引或优化查询逻辑。
适用场景:页面加载慢但CPU和内存使用率不高,或者数据库服务器CPU飙升。操作时注意:DEBUG模式不应在生产环境长期开启,建议临时开启后抓取一次日志就关闭。connection.queries只能在请求过程中访问,可放在响应中间件中打印。验证方式:修复后重新请求,观察django.db.backends日志中查询次数和耗时是否下降。风险边界:如果查询数量很少但每一条都很慢,重点检查索引;如果查询次数很多,优先减少查询次数。
中间件耗时逐个排查
定位中间件对响应时间的影响,可通过在settings.py中临时注释部分中间件并测试响应速度来缩小范围。更精确的方法是在自定义中间件中记录进入和离开的时间戳,输出到日志。常见的耗时中间件包括SessionMiddleware(涉及数据库读写)、CsrfViewMiddleware(计算token)、以及压缩或缓存中间件。如果发现某个中间件耗时异常,检查其背后的存储后端(如session引擎)是否配置不当,或考虑改用异步中间件。
操作动作:先在本地或测试环境复制对应请求,逐层注释中间件。如果注释后响应明显变快,该中间件就是嫌疑对象。例如,SessionMiddleware如果使用数据库session后端,每次请求都会读写session表,可以考虑切换到缓存后端(如Redis)。验证方式:在自定义中间件中打印每个中间件的耗时;或使用django-debug-toolbar的中间件面板。风险边界:注释中间件可能导致功能异常(如CSRF保护丢失),测试时需确认业务不受影响。如果中间件耗时普遍,考虑升级Django版本或改用异步视图。
静态文件服务配置检查
若生产环境仍使用Django自带的runserver服务静态文件,会导致响应缓慢,尤其在高并发时。检查nginx或Apache中静态文件的反向代理配置,确保静态文件直接由Web服务器返回,不经过Django。使用collectstatic命令后,检查STATIC_ROOT路径是否正确,以及Web服务器是否指向该目录。如果静态请求响应时间超过50ms,很可能存在问题,可通过浏览器开发者工具查看静态资源加载时间,确认是否来自Django进程。
验证方式:在浏览器开发者工具的网络面板中,找一个静态资源(如CSS、JS),查看响应头中的Server字段。如果显示Django或WSGIServer/0.x,说明没有走静态文件服务器。正确的做法是Server显示nginx或Apache。操作动作:修改nginx配置,添加location /static/ alias /path/to/static/; 并重启nginx。如果STATIC_URL路径有变更,需要同步修改。风险边界:如果使用了CDN或云存储,需要确保collectstatic上传后路径一致。
缓存使用现状评估
检查项目中是否合理使用了缓存。首先确认缓存后端配置,如Memcached或Redis是否正常运行,使用ping命令或客户端测试连接。在视图或模板中,对于数据库查询结果、计算密集型操作使用cache.set和cache.get。注意缓存失效策略,避免缓存雪崩。一个常见坑是缓存键生成不合理导致未命中,建议统一使用函数或视图的摘要作为键。可以通过在日志中输出缓存命中率,如果大量请求未命中且数据库压力大,则需调整缓存粒度或增加缓存时间。
操作动作:在配置文件中设置CACHES后端,例如使用Redis。然后在需要缓存的地方调用cache.set('key', data, timeout=3600)。验证方式:编写一个简单的视图,先检测缓存命中情况,或者使用django-debug-toolbar的缓存面板。如果发现缓存命中率很低,检查键是否正确,或者考虑使用低级缓存API。风险边界:缓存时间不宜过长,否则数据过期不及时;也不宜过短,否则失去缓存意义。对于变化频繁的数据,考虑使用信号触发主动失效。
服务器资源监控与连接池调整
使用系统工具如top、htop、iostat监控CPU、内存、I/O使用率。如果CPU持续接近100%,考虑是否Gunicorn或uWSGI的worker数设置过高导致上下文切换;内存不足则检查是否有内存泄漏,可通过objgraph分析内存对象。磁盘I/O高可能是日志写入频繁或数据库文件读写,调整日志级别或使用异步日志。同时检查网络带宽是否饱和,用iftop监控端口流量。若资源一切正常但响应慢,需进一步检查应用逻辑。
另外,Django默认每个请求创建新的数据库连接,若并发量高且数据库连接数有限,会导致请求排队等待连接。检查数据库的max_connections配置,同时查看Django的CONN_MAX_AGE设置,适当增大该值可重用连接。如果使用PostgreSQL,可通过pg_stat_activity查看活跃连接数;MySQL则通过show variables like 'max_connections'。一个常见坑是连接池配置过大挤占数据库内存,建议根据服务器内存调整。若连接数经常打满,考虑使用连接池中间件如django-db-connection-pool。
验证方式:使用top观察CPU和内存变化,同时观察应用日志中的请求响应时间。如果worker数从4调整为8后,CPU反而接近100%,说明worker数过高,需要降低。对于数据库连接,使用监控工具查看活跃连接数是否超过max_connections的80%。风险边界:调整worker数需要重启进程,建议在低峰期操作。CONN_MAX_AGE设置过大会占用数据库连接,需结合连接数上限计算合理值。
以上几个方向覆盖了大多数Django响应缓慢的原因。建议从数据库查询和中间件耗时入手,因为这两项通常是最容易验证且影响最大的。如果所有检查都无异常,再考虑服务器资源配置和缓存策略。记住,每次修改后都要通过日志或监控确认效果,并且保留回滚方案。