news 2026/6/15 16:04:37

不同Django服务器和部署方式的性能调研

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不同Django服务器和部署方式的性能调研

测试环境#

本次测试的项目部署在腾讯云2C2G的小水管服务器上,感觉服务器性能严重拖累了应用性能哈哈🤣

而且我还发现一个事情,腾讯云似乎偷偷摸摸在高峰期(如下午)把服务器性能降低,下午和凌晨测试的结果有很大差异。

本次参与测试的wsgi/asgi服务器有 daphne, granian, gunicorn, uwsgi, uvicorn, hypercorn 基本涵盖了 python 生态的大部分服务器了~

本次使用 wrk 作为性能测试功能,所有接口都使用-t4 -c200 -d30s的测试参数。

性能测试结论#

RPS 排名#

排名serverreq/sec接口
🥇 1uWSGI + WSGI1206WSGI
🥈 2Gunicorn + WSGI740WSGI
🥉 3Granian + ASGI220ASGI
4Daphne + ASGI190ASGI
5Uvicorn + ASGI181ASGI
6Hypercorn + ASGI168ASGI

结论:

  • WSGI 整体远快于 ASGI

    这是预期结果,Django 的内部原生就是 WSGI,同步路由不需要额外的 async 转换。

  • uWSGI 再次证明自己是 WSGI 性能之王

    uWSGI 的 C 实现、成熟的 worker 管理、内存利用优化都让它在纯 WSGI 场景无敌。

内存占用对比#

排名server内存
🥇 1uWSGI58M(极低)
2Granian170M
3Daphne175M
4Hypercorn300M
5Gunicorn+WSGI430M
6Uvicorn500M(最高)

结论

  • uWSGI 不仅最快,还最省内存
  • Uvicorn 内存最高(Python 单 worker overhead 明显)
  • ASGI 服务器普遍内存偏高是正常现象

性能测试数据#

以下是详细的性能测试数据。

daphne + asgi#

测试时内存峰值占用175M左右

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.03s 134.59ms 1.99s 89.71% Req/Sec 69.17 64.53 313.00 80.49% 5737 requests in 30.04s, 2.14MB read Socket errors: connect 0, read 0, write 0, timeout 4 Requests/sec: 190.99 Transfer/sec: 72.93KB

granian + asgi#

测试时内存峰值占用170M左右

$ curl http://127.0.0wrk -t4 -c200 -d30s875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 886.48ms 79.27ms 1.26s 85.40% Req/Sec 86.07 112.58 490.00 84.05% 6637 requests in 30.04s, 2.72MB read Requests/sec: 220.93 Transfer/sec: 92.56KB

gunicorn + wsgi#

测试时内存峰值占用430M左右

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 268.67ms 31.82ms 425.23ms 86.13% Req/Sec 187.47 119.54 494.00 56.66% 22244 requests in 30.03s, 9.52MB read Requests/sec: 740.60 Transfer/sec: 324.74KB

uwsgi + wsgi#

测试时内存峰值占用58M左右

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 199.52ms 277.85ms 1.97s 87.56% Req/Sec 302.89 88.84 575.00 67.33% 36210 requests in 30.02s, 12.95MB read Socket errors: connect 0, read 36216, write 0, timeout 96 Requests/sec: 1206.08 Transfer/sec: 441.68KB

uvicorn + asgi#

测试时内存峰值占用500M左右

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.00s 537.23ms 2.00s 59.81% Req/Sec 62.04 66.05 460.00 83.03% 5440 requests in 30.04s, 2.23MB read Socket errors: connect 0, read 0, write 0, timeout 369 Requests/sec: 181.07 Transfer/sec: 76.05KB

hypercorn + asgi#

测试时内存峰值占用300M左右

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/django-starter/monitoring/health Running 30s test @ http://127.0.0.1:9875/api/django-starter/monitoring/health 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 734.64ms 423.05ms 2.00s 51.70% Req/Sec 55.53 52.50 360.00 83.49% 5064 requests in 30.06s, 2.09MB read Socket errors: connect 0, read 0, write 0, timeout 1124 Requests/sec: 168.45 Transfer/sec: 71.24KB

更细化的性能测试#

访问一个有数据库查询的接口 http://127.0.0.1:9878/api/demo/movie/movie

直接 uwsgi

$ wrk -t4 -c200 -d30s http://127.0.0.1:9875/api/demo/movie/movie Running 30s test @ http://127.0.0.1:9875/api/demo/movie/movie 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 501.93ms 260.82ms 1.99s 94.20% Req/Sec 61.02 39.11 191.00 62.02% 6726 requests in 30.04s, 15.84MB read Socket errors: connect 0, read 6758, write 0, timeout 45 Requests/sec: 223.89 Transfer/sec: 539.82KB

经过 caddy 反代

$ wrk -t4 -c200 -d30s http://127.0.0.1:9878/api/demo/movie/movie Running 30s test @ http://127.0.0.1:9878/api/demo/movie/movie 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 562.46ms 166.56ms 1.65s 88.77% Req/Sec 52.66 21.07 150.00 65.63% 6299 requests in 30.04s, 15.06MB read Socket errors: connect 0, read 0, write 0, timeout 208 Non-2xx or 3xx responses: 40 Requests/sec: 209.69 Transfer/sec: 513.30KB

代码#

来介绍下代码的部分。

这次拿来进行性能测试的主要是健康检查和一个简单的数据库访问接口。所有接口都是用 django-ninja 开发的。

数据库访问接口#

涉及到数据库的就是这个接口

查询数据返回+分页功能,非常简单

@router.get('/movie', response=List[MovieOut], url_name='demo/movie/list') @paginate def list_items(request): qs = Movie.objects.all() return qs

健康检查接口#

引入这些package

import asyncio from ninja import Router from django.db import connections from django.db.utils import OperationalError from redis import Redis from redis.exceptions import RedisError from redis import asyncio as aioredis import os import time import platform import subprocess import anyio

原版的接口是纯同步的,还要调用一个系统进程去获取 uptime,这个操作严重拖慢了整个接口的速度,我这次重构成同步和异步两种接口。

首先是最简单的版本,这里面就啥也没有,单纯返回 JSON。

@router.get('health') def simple_health_check(request): """健康检查端点,用于容器健康检查和监控""" response_data = { 'status': 'healthy', 'status_code': 200, } return response_data

异步接口#

先来异步接口。

其实我很少用到 python 的异步功能,可能这也和 python 对异步的支持比较差有关系。

先写两个异步方法,用来检查数据库和Redis连接。

async def check_db_async(): """数据库检查(同步 ORM → 放线程池)""" try: def _check(): for conn in connections.all(): conn.cursor() return True return await anyio.to_thread.run_sync(_check) except OperationalError: return False async def check_redis_async(): """Redis 异步检查(注意:确保关闭客户端以释放连接池)""" try: redis_client = aioredis.Redis( host="redis", port=6379, socket_connect_timeout=1, decode_responses=True, ) try: ok = await redis_client.ping() return bool(ok) finally: # 关闭客户端和连接池,避免连接泄露(在短生命周期的容器/请求里很重要) try: await redis_client.close() except Exception: pass try: await redis_client.connection_pool.disconnect() except Exception: pass except Exception: return False

Django ORM 不支持异步,所以这里用 anyio 这个包来简化一下操作,把同步操作包装一下假装成异步运行。实际上用 asyncio 这个库也能做,不过 anyio 方便一点。

在用 aioredis 时,这里有个坑,我一开始安装了 aioredis 这个包,结果发现和原有的 redis 包冲突了。

查看文档才发现from redis import asyncio as aioredis就完事儿了,redis 包里已经自带了异步支持。

接着实现异步接口

@router.get('health/async') async def health_check_async(request): """Async 模式健康检查(ASGI 优化版)""" # 使用 asyncio.gather 并发运行 DB 和 Redis 检查 db_ok, redis_ok = await asyncio.gather( check_db_async(), check_redis_async(), ) status = "healthy" if db_ok and redis_ok else "unhealthy" status_code = 200 if status == "healthy" else 503 return { "status": status, "status_code": status_code, "checks": { "database": "ok" if db_ok else "error", "redis": "ok" if redis_ok else "error", }, "system": get_system_info(), }

同步接口#

同步的就简单了

@router.get('health/sync') def health_check_sync(request): """同步版本的健康检查接口""" # --- 检查数据库 & Redis --- db_ok = check_db_sync() redis_ok = check_redis_sync() # --- 系统信息 --- system_info = { "timestamp": time.time(), "uptime": get_uptime(), "hostname": os.environ.get("HOSTNAME", ""), "environment": os.environ.get("ENVIRONMENT", "development"), "os": platform.system(), } # --- 状态码 --- status = "healthy" if db_ok and redis_ok else "unhealthy" status_code = 200 if status == "healthy" else 503 # --- 返回数据 --- return { "status": status, "status_code": status_code, "checks": { "database": "ok" if db_ok else "error", "redis": "ok" if redis_ok else "error", }, "system": system_info, }

小结#

传统应用无脑选 uwsgi 就对了。

需要异步的可以把异步那部分切割出来用 granian 或者 daphne 跑。

当然这也增加了复杂度,但这是对性能优化的最佳权衡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 13:33:26

基于单片机智能热水器系统仿真设计

**单片机设计介绍,基于单片机智能热水器系统仿真设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机的智能热水器系统仿真设计概要如下: 一、设计背景与目标 随着科技的快速发展和智能化需求的提升,…

作者头像 李华
网站建设 2026/6/15 14:23:55

基于单片机的电加热炉温度控制系统设计

**单片机设计介绍,基于单片机的电加热炉温度控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序 一 概要 基于单片机的电加热炉温度控制系统设计是一个综合性的项目,旨在通过单片机实现对电加热炉温度的精确控制。以下是…

作者头像 李华
网站建设 2026/6/15 13:31:06

土壤墒情监测系统的设计与实现

2 系统整体方案设计 2.1 方案的设计 该系统主要使用了stm32单片机进行分析,链接土壤传感器,然后进行土壤湿度,土壤水分,土壤PH值酸碱度的监测,然后进行蜂鸣器报警,使用蓝牙进行手机端链接,并且显…

作者头像 李华
网站建设 2026/6/15 10:43:58

5 款 AI 写论文哪个好?实测大比拼!虎贲等考 AI 凭硬核实力 C 位出圈

毕业季来临,“AI 写论文哪个好用” 的提问直接刷屏学术圈。作为深耕论文写作工具测评的博主,我耗时半个月,对 5 款主流真实 AI 论文工具(虎贲等考 AI、掌桥科研 AI、68 爱写 AI、WPS AI、豆包学术助手)展开全维度实测&…

作者头像 李华
网站建设 2026/6/5 23:51:26

数学建模Matlab算法,第二十二章模糊数学模型

模糊数学模型的理论体系与实践应用探析 在经典数学的发展历程中,确定性与精确性始终是核心追求,然而现实世界中大量存在的“亦此亦彼”的模糊现象,如“高温与低温”“优秀与合格”“拥堵与畅通”等,却难以用经典数学工具进行精准刻画。1965年,美国著名计算机与控制专家查…

作者头像 李华
网站建设 2026/6/15 10:40:05

slmgr 查看Win10剩余激活天数

方法一:快速查看(slmgr.vbs -xpr) 按 WinR 打开“运行”,输入 slmgr.vbs -xpr 并回车。弹出的提示框会直接显示:若为永久激活,提示“此Windows副本已永久激活”;若为临时激活(如KMS&…

作者头像 李华