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

python-socketio异步多客户端连接实现及高并发CPU占用优化

Python-SocketIO 高并发连接CPU占用过高优化方案

问题描述

我参考python-socketio官方文档编写了异步通信代码,目前已实现客户端与服务端单连接搭建,可完成少量消息emit收发。现需要批量创建大量客户端连接Socket服务端,并行观测消息收发性能表现。

现有测试代码

client.py

import random
import gevent
import time
import socketio
import asyncio

class ConnectionTest():
     def __init__(self):
        self.sio = socketio.AsyncClient(handle_sigint=True, logger=True, engineio_logger=True)


     async def listen_to_redis(self):
        await self.sio.connect('http://dfs.confec.co.in/?socket_qa2=True&session_id='+str(random.randint(1,100000))) 
        @self.sio.on('custom_event')
        async def on_custom_event(data):
            await self.sio.emit('message', '27 July 2015) was an Indian aerospace scientist')
        @self.sio.on('client')
        async def on_client(data):
            pass

     async def run(self):
        await self.listen_to_redis() 

async def main():
    async def iterations(i):
        print("connection :",i)
        obj1 = ConnectionTest()
        await obj1.run()
        await obj1.sio.wait()
    x = [iterations(i) for i in range(2000)]
    await asyncio.gather(*x)


if __name__ == '__main__':
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main())

注:原代码中main函数存在缩进错误,上述代码已做修正

Server.py

import uvicorn
import asyncio
import socketio
import aiohttp


url='redis://my_master:q2_gadse@10.1.7.4:6379/0'
channel='public_chat'
mgr = socketio.AsyncRedisManager(url=url, channel=channel, write_only=False)
sio = socketio.AsyncServer(async_mode='aiohttp',client_manager=mgr, async_handlers=True, logger=True, engineio_logger=True)

app = aiohttp.web.Application()
sio.attach(app)

@sio.on('connect')
async def test_connect(sid, environ):
      print('connected', sid)


@sio.event
async def message(sid, message):
      await sio.emit('client', message)



@sio.on('disconnect')
async def test_disconnect(sid):
    print('Client disconnected')


if __name__=='__main__':
    aiohttp.web.run_app(app, host='0.0.0.0', port=31451)

当前测试情况

目前已通过实例化多个AsyncClient对象完成多连接性能测试,上述代码已做对应更新,但无论采用何种部署策略,CPU占用始终持续达到100%。性能目标为单处理器至少承载5000个连接(最初目标为10000个)。

测试硬件配置为4GB内存、2核/4核CPU,客户端与服务端分别部署在不同Linux节点上。测试过程中客户端CPU占用快速攀升至100%-200%,服务端因使用Redis作为外部脚本emit消息的中间件,运行状态相对稳定。

查阅python-socketio官方文档后,未找到类似Node.js版Socket.IO提供的性能调优、负载测试、压力测试相关章节,压测统计截图已附,现求可实现单进程至少5000个连接、解决CPU占用过高问题的可行优化建议。


优化方案

按优先级顺序执行即可:

  • 第一优先级:关闭调试日志
    当前客户端和服务端初始化时都开启了logger=True, engineio_logger=True,两个参数会输出所有协议交互、心跳、事件收发的详细日志,高并发下日志IO和字符串拼接会消耗70%以上的CPU资源。压测和生产环境必须设置为False,仅在调试单连接问题时临时开启。
  • 修正客户端事件注册逻辑
    当前把@self.sio.on事件装饰器写在了listen_to_redis方法内部,每次新建连接都会重复注册事件handler,额外占用内存和事件分发的CPU开销。把事件注册移到__init__方法中,每个客户端实例只注册一次即可。
  • 调整系统文件句柄限制
    Linux默认单进程文件句柄上限通常为1024,连接数达到2000已经接近上限,会触发大量连接重试、超时逻辑占用CPU。压测前执行ulimit -n 65535临时修改,同时修改/etc/security/limits.conf永久生效,保证单进程可打开的句柄数大于目标连接数。
  • 替换异步事件循环实现
    Python默认asyncio事件循环在高并发网络IO下性能一般,客户端和服务端都可以使用uvloop替换默认事件循环,安装后仅需在代码入口加两行:
    import uvloop
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    
    网络IO性能可提升30%-50%。
  • 控制连接建立的并发速率
    当前用asyncio.gather一次性发起2000+连接,瞬间的TCP握手、HTTP升级、SocketIO握手请求会打满事件循环的调度队列,导致CPU尖峰。可以用信号量控制并发建连速率,比如每秒建立100-200个连接,避免瞬间流量冲击:
    sem = asyncio.Semaphore(200)
    async def iterations(i):
        async with sem:
            print("connection :",i)
            obj1 = ConnectionTest()
            await obj1.run()
            await asyncio.sleep(1)
            await obj1.sio.wait()
    
  • 关闭不必要的客户端配置
    客户端初始化时handle_sigint=True仅需在单连接调试时开启,多实例压测时可以设为False,避免信号处理的额外开销;如果不需要自动重连、心跳检测的精细配置,可以调整ping_interval、ping_timeout参数为更宽松的值,减少心跳包的收发频率。
  • 服务端配置优化
    服务端当前用aiohttp.web.run_app启动默认是单进程,可以配合gunicorn+uvicorn worker启动多进程实例,绑定不同端口分摊连接压力;如果不需要异步handler的隔离,可以把async_handlers=True设为False,减少事件调度的开销。

按以上步骤调整后,单2核CPU节点承载5000-10000个空闲长连接的CPU占用通常可以降到10%以下,可达到预期性能目标。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:48:14