《当Flask遇上FastAPI:双轨运行架构的优雅解决方案》
关于《与AI Agent同行:门户网站创建之旅经典技术分享》专栏
本专栏是一套系统性的Web开发技术实战教程,基于Madechango.com门户网站的真实开发经验,涵盖架构设计、AI能力集成、研究工具开发等9大模块共40篇文章。面向中高级Python开发者,通过18万行生产级代码实践,深入讲解Flask+FastAPI双轨架构、多模型AI矩阵、学术研究全链路工具等现代Web技术栈的完整应用。
摘要:本文是《与AI Agent同行:门户网站创建之旅经典技术分享》专栏系列第1篇(模块1第1篇),深入探讨了现代Web开发中Flask与FastAPI双轨运行架构的设计与实现。通过Madechango项目实战案例,详细解析了WSGI+ASGI混合部署的技术方案,包括Uvicorn多端口实例配置、Nginx反向代理负载均衡、ASGI会话中间件设计等核心技术要点。文章通过性能对比数据和踩坑经验分享,为开发者提供了可复制的双架构解决方案。

核心亮点: WSGI+ASGI混合部署
为什么需要双架构?同步与异步的选择困境
在现代Web开发中,开发者经常面临一个关键抉择:是选择成熟稳定的Flask还是拥抱现代化的FastAPI?实际上,这两种框架各有优势,单一架构往往无法满足复杂项目的多样化需求。Madechango项目采用了Flask+FastAPI双轨运行架构,充分发挥两种框架的优势:
Flask优势:
- 成熟稳定,拥有丰富的第三方扩展生态
- 同步处理能力强,适合传统Web页面渲染
- 适合复杂的业务逻辑处理
FastAPI优势:
- 高性能,原生支持异步编程
- 自动API文档生成,开发效率高
- 类型提示完善,代码可维护性强
通过双轨架构,我们实现了:
- Flask处理传统的同步Web请求和复杂业务逻辑
- FastAPI处理高性能API请求和实时通信
- 两者共享同一套数据模型和业务逻辑层
技术实现:Uvicorn多端口实例 + Nginx反向代理负载均衡
1. 项目架构设计
Madechango采用以下架构模式:
Nginx (80/443) -> Uvicorn多端口实例 -> Flask/FastAPI应用
Flask应用入口 (app/asgi.py):
python
from flask import Flask
from app.main import create_app
flask_app = create_app()
# 通过ASGI包装器使Flask应用支持异步
from app.middleware.asgi_middleware import ASGISessionMiddleware
def create_asgi_app():
asgi_app = NonBlockingWsgiToAsgi(flask_app)
asgi_app = debug_session_middleware(asgi_app)
asgi_app = ASGISessionMiddleware(asgi_app)
return asgi_app
asgi_app = create_asgi_app()
FastAPI应用入口 (madechango_thesis_ai/app/main.py):
python
from fastapi import FastAPI
from app.config.settings import settings
app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json"
)
@app.on_event("startup")
async def startup_event():
"""应用启动时的事件处理"""
logger.info("论文助手应用启动中...")
# 预初始化向量服务
import asyncio
asyncio.create_task(initialize_vector_service())
logger.info("论文助手应用启动完成")
2. Uvicorn多端口实例配置
通过批处理脚本启动多个Uvicorn实例:
batch
REM 启动实例1 - 主应用(Flask)
start "Application Port <PORT_1>" cmd /k "cd /d <PROJECT_PATH> && call Scripts\activate.bat && set UVICORN_WID=1 && python -m uvicorn app.asgi:asgi_app --host 0.0.0.0 --port <PORT_1> --workers 1 --log-level info --log-config uvicorn_log_config.json --ws none"
REM 启动实例2 - 辅助应用
start "Application Port <PORT_2>" cmd /k "cd /d <PROJECT_PATH> && call Scripts\activate.bat && set UVICORN_WID=2 && python -m uvicorn app.asgi:asgi_app --host 0.0.0.0 --port <PORT_2> --workers 1 --log-level info --log-config uvicorn_log_config.json --ws none"
Uvicorn配置优化:
python
class UvicornConfig:
@staticmethod
def get_config():
return {
"timeout_keep_alive": 180, # 保持连接超时时间(秒)
"timeout_graceful_shutdown": 60, # 优雅关闭超时(秒)
"limit_concurrency": 200, # 并发连接限制
"backlog": 2048, # 连接队列大小
"h11_max_incomplete_event_size": 33554432, # HTTP请求体大小限制 (32MB)
"access_log": True,
"log_level": "info"
}
3. Nginx反向代理配置
Nginx配置实现负载均衡和静态文件处理:
nginx
# Upstream定义
upstream application_backend {
server localhost:<PORT_1> max_fails=2 fail_timeout=10s;
server localhost:<PORT_2> max_fails=2 fail_timeout=10s;
server localhost:<PORT_3> max_fails=2 fail_timeout=10s;
server localhost:<PORT_4> max_fails=2 fail_timeout=10s;
keepalive 8;
}
# 主服务器配置
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# 静态文件处理
location /static/ {
alias /path/to/your/project/app/static/;
expires 30d;
add_header Cache-Control "public";
access_log off; # 关闭静态资源日志记录
}
# X-Accel-Redirect配置,用于安全的文件下载
location /protected/ {
internal;
alias /path/to/your/project/app/downloads/;
add_header Content-Disposition "attachment";
}
# 动态请求代理到后端
location / {
proxy_pass http://madechango_backend;
# IP头部配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 120s;
# 缓冲区设置
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
}
}
中间件设计:ASGISessionMiddleware统一会话管理
由于Flask是WSGI应用,而我们需要在ASGI环境中运行,因此开发了ASGISessionMiddleware来解决会话兼容性问题:
python
class ASGISessionMiddleware:
"""
处理 ASGI 环境中的会话一致性问题和文件上传
"""
def __init__(self, app):
self.app = app
async def __call__(self, scope, receive, send):
request_type = scope.get("type", "")
if request_type == "http":
await self._handle_http(scope, receive, send)
elif request_type == "websocket":
# WebSocket请求特殊处理
await self._handle_websocket(scope, receive, send)
else:
await self.app(scope, receive, send)
该中间件还包含了请求日志过滤功能,避免高频请求污染日志:
python
# 定义需要过滤的高频请求路径
EXCLUDED_PATHS = {
'/analytics/session/duration',
'/api/health',
'/favicon.ico',
'/static/uploads/class_photos/',
'/static/uploads/avatars/',
}
async def middleware(scope, receive, send):
if scope['type'] == 'http':
request_path = scope.get('path', 'unknown')
should_exclude = any(request_path.startswith(prefix) for prefix in EXCLUDED_PATHS)
if not should_exclude:
# 记录日志
asgi_logger.info(f"Processing request: {request_path}")
真实案例:Madechango如何用Flask服务传统路由,FastAPI处理论文助手系统
在Madechango项目中,我们采用了以下分工策略:
Flask负责:
- 传统Web页面渲染(用户中心、班级空间、moments动态等)
- 会话管理和用户认证
- 传统表单处理
- 静态文件服务
FastAPI负责:
- 论文助手系统(
/thesis_assistant_proxy/) - 高性能API接口
- 实时数据处理
- RAG向量检索
Nginx配置示例:
nginx
# 论文助手API专用代理
location ~ ^/thesis_assistant_proxy/api/ {
rewrite ^/thesis_assistant_proxy/(.*) /$1 break;
proxy_pass http://thesis_assistant_backend;
# 完整的IP头部配置
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 长连接支持
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
}
# 论文助手应用代理
location /thesis_assistant_proxy/ {
rewrite ^/thesis_assistant_proxy/(.*) /$1 break;
proxy_pass http://thesis_assistant_backend;
# 其他代理配置...
}
性能对比:压测数据揭示双架构的性能优势
通过压测对比,我们获得了以下数据:
| 场景 | Flask单架构 | Flask+FastAPI双架构 | 提升幅度 |
|---|---|---|---|
| 首页响应时间 | 1.2s | 0.8s | 33% |
| API请求吞吐量 | 150 QPS | 350 QPS | 133% |
| 并发用户支持 | 500 | 1200 | 140% |
| 内存使用率 | 85% | 70% | 18% |
双架构的优势在于:
- 负载分离:不同类型请求分发到最适合的框架
- 资源优化:异步请求充分利用CPU,同步请求保证数据一致性
- 扩展性:可根据业务需求独立扩展各部分
踩坑经验:WSGI wrapper错误处理与进程通信
在实现双轨架构过程中,我们遇到了几个关键技术难点:
1. WSGI/ASGI兼容性问题
Flask基于WSGI,而Uvicorn是ASGI服务器,直接运行会导致会话丢失。解决方案是使用NonBlockingWsgiToAsgi包装器:
python
class NonBlockingWsgiToAsgi:
def __init__(self, wsgi_application):
self.wsgi_application = wsgi_application
async def __call__(self, scope, receive, send):
# 使用非阻塞方式包装WSGI应用
await NonBlockingWsgiToAsgiInstance(self.wsgi_application)(scope, receive, send)
2. 多进程调度器冲突
由于使用了多端口实例,调度器会在每个进程中重复启动,导致任务重复执行。解决方案是使用文件锁机制:
python
def ensure_single_scheduler():
"""确保调度器只在一个进程中运行"""
lock_file = os.path.join(tempfile.gettempdir(), 'scheduler.lock')
if os.path.exists(lock_file):
try:
with open(lock_file, 'r') as f:
existing_pid = int(f.read().strip())
# 检查进程是否存在
if psutil.pid_exists(existing_pid):
return False # 调度器已在其他进程运行
else:
# 进程不存在,清理锁文件
os.remove(lock_file)
except:
pass
# 创建锁文件
with open(lock_file, 'w') as f:
f.write(str(os.getpid()))
return True
3. 日志多进程安全
多进程环境下,日志文件写入会产生冲突。我们使用了ConcurrentRotatingFileHandler:
python
from concurrent_log_handler import ConcurrentRotatingFileHandler
def setup_logging(app):
worker_id = os.environ.get('UVICORN_WID', '0')
if worker_id == '0':
log_file = os.path.join(log_dir, 'app_w0.log')
else:
log_file = os.path.join(log_dir, f'app_w{worker_id}.log')
file_handler = ConcurrentRotatingFileHandler(
log_file,
maxBytes=50*1024*1024, # 50MB
backupCount=5,
encoding='utf-8'
)
总结:Flask+FastAPI双轨运行架构为企业级Web应用提供了灵活的技术选型方案。通过合理的架构设计和中间件处理,我们成功解决了WSGI/ASGI兼容性、会话管理、进程调度等关键技术难题。该方案不仅提升了系统性能和可扩展性,还为后续功能迭代奠定了坚实基础。建议开发者根据实际业务需求选择合适的框架组合,避免盲目追求技术新颖性而忽视项目稳定性。