不同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 跑。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1159324.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机多机通讯仓库测温报警系统设计

**单片机设计介绍,基于单片机多机通讯仓库测温报警系统设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机多机通讯仓库测温报警系统设计概要 一、引言 随着物流行业的快速发展,仓库温度管理变得尤为重要。为确…

SRC 漏洞挖掘零基础入门教程(超全详解):从入门到精通,一篇就能搞定!

>> 什么是挖src漏洞 经常有人问我SRC是什么,它可不是“源代码”的简称哦!在安全圈,SRC特指安全应急响应中心。 可以把它理解为:企业官方建立的、用于与全球安全研究员(白帽黑客)进行合作的一个平台。…

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

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

高德地图实现实时轨迹展示

Vue3 高德地图(AMap) 实现平滑的实时轨迹回放与追踪 前言 在物联网、物流监控或安防调度系统中,实时展示设备(如无人机、车辆、手环)的移动轨迹是一个常见需求。如果仅仅是简单的更新标记点位置,视觉上会出现“跳变”现象&#x…

基于单片机的多点温度测量系统设计

**单片机设计介绍,基于单片机的多点温度测量系统设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机的多点温度测量系统设计是一个结合了硬件与软件的综合性项目,旨在实时监测和记录多个不同位置的温度数据。以下…

基于单片机的电冰箱温度控制设计

**单片机设计介绍,基于单片机的电冰箱温度控制设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机的电冰箱温度控制设计是一个结合了硬件与软件技术的综合性项目,旨在实现对电冰箱内部温度的精确控制,…

亲测好用9个一键生成论文工具,MBA论文写作必备!

亲测好用9个一键生成论文工具,MBA论文写作必备! AI 工具让论文写作更高效 在当今快节奏的学术环境中,MBA 学生和研究者面临着越来越多的写作挑战。从选题到撰写,再到最终的降重,每一个环节都需要大量的时间和精力。而 …

SpringBoot核心配置文件深度解析:bootstrap.yml与application.yml的差异与应用场景

文章目录引言:配置文件的战略地位一、基础认知:两大配置文件概述1.1 设计定位差异1.2 历史演变二、核心差异深度对比2.1 加载时机与上下文层次2.2 属性优先级与覆盖规则2.3 配置文件查找路径三、bootstrap.yml:Spring Cloud的配置基石3.1 为什…

四套无线充电模型:详解LCC谐振器与磁耦合谐振的恒压、恒流输出设计,MATLAB仿真搭建及原理分析

无线充电仿真 simulink 磁耦合谐振 无线电能传输 MCR WPT lcc ss llc拓扑补偿 基于matlab 一共四套模型: 1.llc谐振器实现12/24V恒压输出 带调频闭环控制 附参考和讲解视频 2.lcc-s拓扑磁耦合谐振实现恒压输出 附设计过程和介绍 3.lcc-p拓扑磁耦合谐振实现恒流输…

2026 最新 SRC 挖洞完全指南:一文掌握常见攻击与高危漏洞挖掘技巧

SRC漏洞(Security Response Center Vulnerability),指在安全应急响应中心框架下公开披露的系统安全缺陷。想象一位数字空间的猎人,持续追踪系统防线中的薄弱环节。 01、SRC漏洞是什么? SRC漏洞指企业安全应急响应中心…

耐达讯自动化 Profibus 总线光纤中继器:解决半导体设备通信难题,提升产线效率

半导体工厂中,不同设备常因通信协议不同陷入“沟通障碍”。控制系统使用Profibus总线,而高精度传感器可能采用以太网或RS485,导致数据无法互通。传统解决方案需定制开发,成本高、调试复杂,系统扩展困难。耐达讯自动化P…

48990001-FK DSSR116电动机器人模块

48990001-FK DSSR116 电动机器人模块产品概述 DSSR116 是一款工业级电动机器人控制模块,用于机器人运动控制、位置反馈和驱动信号处理。它可与工业控制系统、PLC 或机器人控制器配合,实现精确、可靠的机械臂或自动化设备动作控制。主要功能运动控制&…

耐达讯自动化Profibus总线光纤中继器:破解石油化工分析仪器通讯难题

在石油化工行业,在线氢气分析仪、气相色谱仪等分析仪器是把控产品质量和生产安全的关键。但在实际应用中,这些仪器和Profibus总线主控系统的通讯却常遇麻烦:设备没法直接互通,要定制接口不仅成本高,调试周期还得1-2个月…

网络安全到底是什么?涵盖哪些核心方面?学会这些能成为黑客吗?

提及网络安全,很多人都是既熟悉又陌生,所谓的熟悉就是知道网络安全可以保障网络服务不中断。那么到底什么是网络安全?网络安全包括哪几个方面?通过下文为大家介绍一下。 一、什么是网络安全? 网络安全是指保护网络系统、硬件、软件以及其中的数据免…

一文教你学会数据库压力测试

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快很多人提到 jmeter 时,只会说到 jmeter进行接口自动化或接口性能测试,其实jmeter还能对数据库进行自动化操作。个人常用的场景有以下&#x…

57360001-KG DSMB175内存模块

57360001-KG DSMB175 内存模块产品概述 DSMB175 是一种工业控制系统专用内存模块,主要用于分布式控制系统(DCS)或可编程逻辑控制器(PLC)中,提供高速、稳定的数据存储和缓存功能。它确保控制系统在运行过程中…

冠军教练的“羽球密码“:韩宁波如何让吴忠学员技术飙升300%

冠军教练的"羽球密码":韩宁波如何让吴忠学员技术飙升300%在宁夏吴忠的羽毛球场上,国家二级运动员韩宁波正用一套融合科技、趣味与个性化的训练体系,让学员技术提升率突破300%。从肌肉激活到数字建模,从沙漠抗干扰到战术…

基于单片机智能充电器系统设计

**单片机设计介绍,基于单片机智能充电器系统设计 文章目录一 概要二、功能设计设计思路三、 软件设计原理图五、 程序一 概要 基于单片机智能充电器系统设计概要可以归纳如下: 一、引言 随着电子设备的普及和人们对充电效率及安全性的日益关注&#xf…

从赛场王者到羽球筑梦师:韩宁波用专业教学点亮吴忠全民健身新星火

从赛场王者到羽球筑梦师:韩宁波用专业教学点亮吴忠全民健身新星火在宁夏吴忠的羽毛球场上,国家二级运动员韩宁波正以双重身份书写传奇——他既是曾斩获市级锦标赛冠军的赛场王者,更是用专业教学点燃全民健身星火的筑梦师。从肌肉激活的毫米级…

开题报告驳回?不存在的!虎贲等考 AI:一键搭建学术框架,导师直呼专业

毕业论文写作的第一道坎,从来不是正文创作,而是开题报告。选题太老被批 “缺乏创新”,框架残缺被要求 “重新梳理”,文献综述堆砌被吐槽 “没有逻辑”…… 反复修改、来回折腾,不仅消磨心力,还耽误整体写作…