用asyncio搭建轻量级异步微服务时,应基于aiohttp或FastAPI实现WebSocket服务,统一事件循环,手动管理连接生命周期,用asyncio.Queue分组广播,配合aiohttp.ClientSession和asyncpg等异步IO库协同外部服务,并通过debug模式、Uvicorn部署与日志追踪保障可观测性。

用 asyncio 搭建轻量级异步微服务时,WebSocket 是实现实时通信(如聊天、状态推送、设备联动)最直接的方式。关键不是堆砌框架,而是理清事件循环、连接生命周期和并发模型三者的协作关系。
WebSocket 服务端:基于 aiohttp 或 fastapi 的极简实现
aiohttp 自带原生 WebSocket 支持,适合专注异步逻辑的微服务;FastAPI 则在类型提示和开发体验上更友好,底层同样依赖 Starlette 的 asyncio WebSocket 处理。两者都不需要额外线程或进程管理,所有连接都运行在同一个 event loop 中。
- 用 aiohttp.web.WebSocketResponse 手动管理连接:接收消息用
ws.receive()(返回 awaitable),发送用ws.send_str()或ws.send_json() - FastAPI 中直接声明 WebSocket 类型参数,用
await websocket.accept()后即可收发,错误自动断开 - 每个 WebSocket 连接对应一个协程任务,避免在 handler 中做阻塞操作(如同步数据库查询、time.sleep),否则会拖慢整个服务
连接管理:广播、分组与生命周期控制
真实场景中很少只做点对点回显。你需要维护活跃连接集合,并支持按用户 ID、房间号、设备类型等维度分发消息。核心原则是:不共享可变状态,用 asyncio.Queue 或 weakref 避免内存泄漏。
- 用 set() 存储 WebSocket 实例,但必须在连接关闭时及时移除(推荐在 try/finally 或 async with 块中清理)
- 广播消息前先检查
ws.closed == False,避免向已断开连接写入触发异常 - 为不同业务场景建独立的 asyncio.Queue(如“告警队列”“配置更新队列”),由后台任务持续消费并推送给对应连接组
与外部服务协同:HTTP 客户端 + 数据库异步驱动
微服务通常要调用其他 API 或查数据库。同步库(如 requests、psycopg2)会阻塞 event loop,必须换用异步替代方案。
立即学习“Python免费学习笔记(深入)”;
- HTTP 调用统一走 aiohttp.ClientSession,复用 session 实例,避免重复创建 TCP 连接
- 数据库选 asyncpg(PostgreSQL)或 aiomysql(MySQL),配合 SQLAlchemy 1.4+ 的 asyncio 支持,不要用 ORM 的同步 session
- 第三方 SDK 不支持 async?用 asyncio.to_thread()(Python 3.9+)包装,或 loop.run_in_executor() 把阻塞调用扔进线程池,但需评估吞吐瓶颈
部署与可观测性:别让协程“静默消失”
asyncio 应用出问题常表现为连接卡住、消息不达、CPU 占用低但响应延迟高——大概率是某个协程没被 await、异常未捕获,或信号未正确传递给 event loop。
- 启动时加 asyncio.run(main(), debug=True),开启调试模式可捕获未 await 的协程和慢回调
- 用 Uvicorn(支持 ASGI)而非 Gunicorn(默认 fork 进程)部署 FastAPI/aiohttp,确保 event loop 正确初始化
- 记录 WebSocket 生命周期(open/close/receive error),用 logging.getLogger(__name__) 记录连接 ID 和用户标识,方便追踪单个会话行为
不复杂但容易忽略。asyncio 不是魔法,它把并发责任交还给你:谁启动协程、谁处理异常、谁清理资源,都得自己想清楚。










