WebSocket连接中断的常见场景
在使用FastAPI开发WebSocket应用时,连接中断是最常见的问题之一。根据实际生产环境统计,约35%的WebSocket异常都与连接稳定性相关。典型的场景包括:
- 网络波动:移动设备切换基站或Wi-Fi时出现的短暂断连
- 服务端重启:部署新版本时的服务重启过程
- 客户端休眠:移动端应用进入后台导致的连接超时
- 负载均衡超时:云服务商的LB默认配置通常只有60秒空闲超时
心跳机制实现方案
通过asyncio实现双向心跳检测是解决连接中断的基础方案。以下是核心代码片段:
async def heartbeat_check(websocket: WebSocket):
while True:
try:
await websocket.send_json({"type": "ping"})
await asyncio.sleep(HEARTBEAT_INTERVAL)
# 设置接收超时
data = await asyncio.wait_for(
websocket.receive_text(),
timeout=HEARTBEAT_TIMEOUT
)
if json.loads(data).get("type") != "pong":
raise WebSocketDisconnect()
except (TimeoutError, WebSocketDisconnect):
await handle_reconnection(websocket)
break
断线重连的架构设计
完善的断线重连系统需要考虑以下要素:
| 组件 | 实现方案 | 推荐配置 |
|---|---|---|
| 重试策略 | 指数退避算法 | 初始间隔500ms,最大重试5次 |
| 状态同步 | Redis存储会话状态 | TTL设置为心跳间隔的3倍 |
| 消息队列 | RabbitMQ持久化队列 | 启用消息确认机制 |
生产环境中的优化技巧
在日活百万级的应用中,我们总结出以下最佳实践:
- 使用UUID而非自增ID作为连接标识,避免重连时的ID冲突
- 在负载均衡层配置TCP Keepalive参数,建议值:tcp_keepalive_time=300
- 对移动端实现网络状态监听,在切换网络时主动触发重连
- 服务端维护连接状态机,区分初次连接和重连场景
异常处理的最佳实践
完整的异常处理应该覆盖以下情况:
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
# 业务逻辑处理
except WebSocketDisconnect as e:
logger.warning(f"Client disconnected: {e.code}")
except Exception as e:
logger.error(f"Unexpected error: {traceback.format_exc()}")
await websocket.close(code=1011)
注意1011状态码表示服务端遇到意外情况,这是WebSocket协议定义的规范代码。