Django Websocket随连接用户增多变慢,生产环境异常排查求助
问题分析:Django Channels生产环境Websocket连接慢、推送延迟问题
问题描述
我用Django Channels向前端每秒推送1条消息,本地运行正常,但用Nginx+Gunicorn+Daphne部署到生产环境后,Websocket要尝试2-3次才能连上,而且连接后消息推送速度特别慢。想问这是服务器配置问题还是代码问题?
相关代码
consumer.py
class MyConsumer(AsyncJsonWebsocketConsumer): async def connect(self): self.room_group_name = 'Live Message' self.error_code = 4011 await self.channel_layer.group_add(self.room_group_name, self.channel_name) await self.accept() async def disconnect(self, code): await self.channel_layer.group_discard(self.room_group_name, self.channel_name) await self.close(self.error_code) async def send_live_data(self, event): data = event.get('value') additional_msg = get_additional_msg() data['additional_msg'] = json.dumps(additional_msg, default=default) try: await self.send_json(data) except Exception as e: await self.disconnect({'code': self.error_code}) await self.close(self.error_code)
message.py
channel_layer = get_channel_layer() async def send_data(): try: await (channel_layer.group_send)('Live Message', { 'type': 'send_live_data', 'value': {'live_message':json.dumps(message)}}) except: print("Error while sending message ...\n", traceback.format_exc()) class MyWorker(Thread): def __init__(self): Thread.__init__(self) def run(self): print('Worker is running .....') while True: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(send_data()) loop.close() time.sleep(1) MyWorker().start()
问题根源:代码+配置双重问题
一、代码层面的核心问题
异步循环滥用
在MyWorker的run方法中,每次循环都新建并关闭asyncio事件循环,这会产生巨大的性能开销——每次创建循环都要初始化异步资源,关闭时还要清理,直接导致每秒一次的消息发送延迟飙升,这是推送慢的主要原因之一。异常处理与参数错误
send_data的except未指定具体异常类型,会捕获所有错误,掩盖配置类问题,不利于排查。disconnect方法中调用close时传入字典,而close仅接受整数错误码,这会导致连接关闭逻辑异常,间接引发重连问题。
- 序列化冗余
send_data中已将message用json.dumps序列化,到send_live_data又对additional_msg再次序列化,最后用send_json发送,导致JSON嵌套序列化,既浪费性能,还可能引发前端解析问题。
二、服务器配置层面的可能问题
- Nginx Websocket代理配置缺失
Nginx默认不会维持Websocket长连接,必须添加专属配置:
- 未转发
Upgrade和Connection头,会导致Nginx主动断开连接,引发多次重连。 proxy_read_timeout默认60秒过短,容易导致连接超时。
正确的Nginx配置片段:
location /ws/ { proxy_pass http://127.0.0.1:8001; # Daphne监听地址 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 3600s; }
Daphne与Gunicorn职责混淆
Gunicorn仅处理HTTP请求,Websocket请求必须全部转发给Daphne,若让Gunicorn处理Websocket请求,会直接导致连接失败或延迟。Daphne启动参数不合理
未设置足够的worker进程或未启用异步优化参数,会导致连接和消息处理能力不足。
修复方案
代码修复
- 复用asyncio事件循环
class MyWorker(Thread): def __init__(self): Thread.__init__(self) def run(self): print('Worker is running .....') loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: while True: loop.run_until_complete(send_data()) time.sleep(1) finally: loop.close()
- 修正异常处理与序列化
# send_data优化 async def send_data(): try: # 去掉冗余序列化,直接传对象 await channel_layer.group_send('Live Message', { 'type': 'send_live_data', 'value': {'live_message': message} }) except Exception as e: print("Error while sending message ...\n", traceback.format_exc()) # send_live_data优化 async def send_live_data(self, event): data = event.get('value') # 直接传对象,send_json自动序列化 data['additional_msg'] = get_additional_msg() try: await self.send_json(data) except Exception as e: # close仅传整数错误码 await self.close(self.error_code)
配置检查
- 确保Nginx的Websocket代理配置正确,重点检查
Upgrade/Connection头和超时设置。 - 确认Daphne独立启动(例如
daphne -b 0.0.0.0 -p 8001 myproject.asgi:application),Nginx仅将/ws/路径请求转发给Daphne,其余HTTP请求转发给Gunicorn。 - 检查服务器防火墙,确保Daphne监听的端口未被拦截。
内容的提问来源于stack exchange,提问作者Django Developer
相关产品推荐
相关产品推荐

