服务端 - Sanic 异步效率和架构
2025-08-06 16:36:34 0 举报
AI智能生成
Sanic是一个高性能的Python框架,专门设计用于异步HTTP请求,为基于Web的应用程序提供了杰出的处理速度和效率。 使用非阻塞驱动作为后端,利用Python协程,Sanic能够突破传统同步框架的性能限制,特别适合构建需要高并发和快速响应的应用。 分析了完善的中间件功能,事件信号系统。
作者其他创作
大纲/内容
特点
内置支持 ASGI:<br>
遵循 ASGI 规范,可以运行在任何兼容 ASGI 的服务器上(如 uvicorn, hypercorn, daphne)。<br><br>内置了高性能的生产级服务器(基于 sanic.worker 和 uvloop),开箱即用,无需额外配置 WSGI 服务器(如 uWSGI, Gunicorn)。
极致的性能:<br>
这是 Sanic 最突出的特点。它使用 uvloop(一个基于 libuv 的快速事件循环替代品)作为默认事件循环,显著提升了 asyncio 的性能。<br><br>其简洁高效的设计(无全局请求对象、直接传递请求/响应对象)减少了开销。
异步的支持:<br>
从底层到 API 设计都围绕 async/await 构建。允许你编写非阻塞的视图函数、中间件、信号处理器等。<br><br>能够轻松集成其他异步库(如 asyncpg 访问 PostgreSQL, aiohttp 发起 HTTP 请求, aioredis 访问 Redis 等),避免阻塞事件循环。
简洁直观的 API:<br>
设计理念类似于 Flask,学习曲线相对平缓。<br><br>路由定义清晰(@app.route 或 @app.get, @app.post 等装饰器)。<br><br>支持基于类的视图,提供更好的代码组织方式,特别是对于 RESTful API 资源。<br><br>请求 (request) 和响应 (response) 对象作为参数直接传递给处理函数,易于操作。<br>
强大的中间件:<br>
支持请求前 (request) 和响应后 (response) 中间件。<br>
中间件也可以是异步函数,方便实现认证、日志、CORS、请求/响应修改等全局逻辑。
信号系统:<br>
提供内置的信号机制,如: before_server_start, after_server_stop, http.routing.before, http.lifecycle.response 等<br>
允许在应用生命周期的特定时刻注入自定义逻辑。
ASGI vs WSGI<br>
客户端请求 → ASGI服务器(uvicorn/hypercorn) → ASGI协议解码 → Sanic应用 → 异步视图处理
WSGI<br>
之前Python Web框架主要遵循**WSGI (Web Server Gateway Interface)** 标准。<br>
WSGI是一个同步的接口规范,定义了一个简单的同步调用约定:Web服务器接收请求,然后调用应用(一个可调用对象),应用处理请求并返回响应。<br>
虽然WSGI为Python Web开发带来了统一性,但它本质上是同步阻塞的。如果一个视图函数在处理时需要等待I/O(如数据库查询、外部API调用),整个工作线程会被阻塞,无法处理其他请求,会导致性能瓶颈。<br>
ASGI<br>
**ASGI (Asynchronous Server Gateway Interface)** 应运而生。<br>
ASGI是WSGI的精神继承者,但设计为**异步友好**。它允许应用处理异步事件,支持WebSocket、HTTP/2等协议,并且更适合长时间连接(如SSE、WebSocket)。<br>
ASGI定义了一个异步调用约定。一个ASGI应用是一个异步函数(`async def`),它接收三个参数: scope, receive, send<br>
请求对象
在视图函数中通过 request 对象访问请求信息 (URL 参数、Params、Headers、Body 等)<br>
响应对象
使用response 模块中的函数创建并返回响应对象 (text, json, html, file, stream, redirect 等) <br>
聊聊中间件
<b>提供灵活的请求/响应处理管道</b>,尤其擅长处理请求前(request)和响应后(response)两个关键阶段的中间件操作。
特点
擅长处理请求前(request)和响应后(response)两个关键阶段
请求前中间件(Request Middleware)<br>
仅使用Request 对象一个参数<br>
在请求到达路由处理函数之前执行,常用于:<br>
认证授权,访问控制<br><br>请求数据预处理<br><br>请求日志记录
核心特性:<br>
<b>执行顺序:按注册顺序执行<br></b><br>中断能力:可直接返回响应,跳过后续处理<br><br>请求修改:可修改请求对象
案例
# 日志中间件<br>@app.middleware("request")<br>async def log_middleware(request: Request):<br> request.ctx.start_time = time.time()<br> print(f"{request.method} {request.path} from {request.ip}")
# 限流控制<br>from sanic.exceptions import TooManyRequests<br><br>@app.middleware("request")<br>async def rate_limit_middleware(request: Request):<br> ip = request.ip<br> current = await redis.incr(f"rate:{ip}")<br> if current == 1:<br> await redis.expire(f"rate:{ip}", 60)<br> <br> if current > 100: # 每分钟100次<br> raise TooManyRequests("Rate limit exceeded")<br>
其他
响应后中间件(Response Middleware)<br>
使用Request, Response 两个参数<br>
在路由处理函数生成响应后执行,常用于:<br>
添加统一响应头<br><br>性能监控<br><br>错误格式标准化<br>
核心特性:<br>
<b>执行顺序:按注册顺序反向执行(洋葱模型)<br></b><br>响应修改:可修改响应对象<br><br>异常处理:即使路由抛出异常也会执行
案例
# 中间件记录响应日志<br>@app.middleware("response")<br>async def response_log_middleware(request: Request, response):<br> duration = (time.time() - request.ctx.start_time) * 1000<br> print(f"{request.method} {request.path} → {response.status} ({duration:.2f}ms)")<br>
# 使用中间件计数<br>@app.middleware("response")<br>async def count_requests(request, response):<br> METRICS.inc_request()<br> METRICS.inc_status(response.status)<br>
其他
中间件顺序管理建议<br>
安全相关中间件最先注册<br>
核心业务逻辑最后注册
聊聊信号系统
定义
<b>Sanic的信号系统提供了一种发布/订阅模型</b>,允许开发者注册处理函数(订阅者)来响应框架内部发出的特定事件(信号)。
作用
Sanic的信号系统基于异步事件,允许开发者在<b>应用,请求生命周期的特定时刻注入自定义逻辑</b>
信号系统是Sanic框架中用于<b>解耦和扩展</b>功能的重要机制。
信号在应用的不同阶段被触发,例如服务器启动前、路由处理前等实现逻辑。<br>
案例
服务器启动停止前后处理
before_server_start:服务器启动前<br>@app.signal("server.init.before")<br>async def setup_db(app):<br> app.ctx.db = await create_db_pool()<br> app.ctx.redis = await create_redis_pool()<br>
after_server_start:服务器启动后<br>@app.signal("server.init.after")<br>async def notify_ready(app):<br> await send_slack("Server is ready!")<br> await init_background_tasks(app)<br>
before_server_stop:服务器停止前@app.signal("server.shutdown.before")<br>async def cleanup(app):<br> await app.ctx.db.close()<br> await app.ctx.redis.close()<br><br>
after_server_stop:服务器停止后<br>@app.signal("server.shutdown.after")<br>async def final_log(app):<br> logger.info("Server shutdown complete")<br><br>
请求前后的信号处理
请求前,动态功能开关<br>@app.signal("http.handler.before")<br>async def feature_toggle(request):<br> # 根据请求头启用实验性功能<br> if request.headers.get("X-New-Feature") == "enabled":<br> request.ctx.use_new_algorithm = True<br><br>
请求后,响应缓存<br>@app.signal("http.handler.after")<br>async def cache_response(request, response):<br> if request.method == "GET" and response.status == 200:<br> await redis.set(<br> f"response:{request.path}",<br> response.body,<br> ex=300 # 缓存5分钟<br> )<br>
跨整个请求上下文
@app.signal("http.lifecycle.complete")<br>async def global_metrics(request, response):<br> # 聚合所有请求的指标<br> METRICS["requests"].inc()<br> METRICS["status_codes"][response.status].inc()<br>
指标统计详细案例
架构组件
核心组件
信号(Signal):预定义或自定义的事件标识符(如 http.lifecycle.response)<br><br>发布者(Publisher):框架内部在关键节点触发信号的组件<br><br>订阅者(Subscriber):开发者注册的信号处理函数<br><br>事件总线(Event Bus):负责将信号路由到所有注册的监听器<br>
核心方法实现
简化版信号分发实现<br>
插件生态系统<br>
拥有一个不断增长的社区插件生态系统(通过 sanic-ext 扩展包或第三方库):<br>
CORS (跨域资源共享)<br><br>模板渲染 (Jinja2)<br><br>依赖注入<br><br>请求验证 (Pydantic)<br><br>OpenAPI/Swagger 文档自动生成<br><br>健康检查端点<br><br>配置管理<br><br>数据库集成(ORM/ODM 适配)
它深受 Flask 的简洁性启发,但底层采用了异步编程asyncio
0 条评论
下一页
为你推荐
查看更多