如何配置FastAPI+Uvicorn微服务避免互相调用时冻结崩溃?
微服务循环调用冻结问题的解决方法
一、修复当前同步调用的阻塞问题
1. 给requests强制添加超时参数
同步的requests如果不设置超时,遇到网络异常或对方服务无响应时会一直阻塞线程/进程,导致Uvicorn worker被占满、服务冻结。必须显式设置超时,并捕获异常:
import requests from fastapi import JSONResponse import logging logger = logging.getLogger(__name__) def call_service2(data): try: # 分别设置连接超时(3秒)和读取超时(10秒),可根据业务调整 response = requests.post("http://service2/api", json=data, timeout=(3, 10)) response.raise_for_status() # 主动抛出HTTP错误状态码异常 return response.json() except requests.exceptions.RequestException as e: logger.error(f"调用service2失败: {str(e)}") return JSONResponse(status_code=503, content={"detail": "服务暂时不可用"})
2. 优化Uvicorn运行配置
Uvicorn默认配置无法有效应对阻塞场景,调整以下参数:
- 启用多worker模式:避免单个worker被阻塞后整个服务无响应,启动命令添加
--workers 4(建议值为CPU核数*2+1) - 设置连接超时:
--timeout-keep-alive 60,避免无效长连接占用资源 - 优雅关闭超时:
--timeout-graceful-shutdown 30,给worker留足时间处理完现有请求再关闭 - 若使用单worker异步模式,替换
requests为异步HTTP客户端(如httpx.AsyncClient),避免阻塞事件循环:
from httpx import AsyncClient from fastapi import JSONResponse import logging logger = logging.getLogger(__name__) @app.get("/async-call") async def async_call_service2(data): async with AsyncClient() as client: try: response = await client.post("http://service2/api", json=data, timeout=10.0) response.raise_for_status() return response.json() except Exception as e: logger.error(f"异步调用service2失败: {str(e)}") return JSONResponse(status_code=503, content={"detail": "服务暂时不可用"})
3. 配置Kubernetes健康探针
添加livenessProbe和readinessProbe,让K8s及时发现异常Pod并重启,同时避免将流量导向不健康的服务:
livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 10 periodSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 3 failureThreshold: 2
FastAPI需提供对应的健康检查接口:
from fastapi import FastAPI app = FastAPI() @app.get("/health") async def health_check(): return {"status": "healthy"}
二、架构层面优化:避免同步循环调用
当前的同步双向调用天然存在死锁风险(双方互相等待响应),更可靠的方案是改用异步消息队列(如RabbitMQ、Redis队列):
- service1不再直接调用service2接口,而是将请求数据发送到消息队列
- service2监听队列,收到消息后异步处理,完成后将结果发送到另一个结果队列
- service1监听结果队列,获取处理结果后返回给前端
这种模式的优势:
- 彻底规避同步阻塞和循环调用死锁
- 自带重试、消息持久化机制,网络异常时不会丢失请求
- 支持削峰填谷,流量突增时队列可缓冲请求,避免服务被压垮
三、额外建议
- 完善日志:在请求发起、响应接收、异常捕获节点添加详细日志,包含请求ID、参数、耗时等信息,便于排查问题
- 限流降级:用
slowapi等工具给接口添加限流规则,调用失败时返回降级响应,避免请求长期阻塞 - 链路追踪:引入链路追踪工具(如Jaeger),清晰查看请求在服务间的流转路径,快速定位阻塞点
内容的提问来源于stack exchange,提问作者westman379
相关产品推荐
相关产品推荐

