介绍(Introduction)
Sanic 是 Python3.7+ Web 服务器和 Web 框架,旨在提高性能。它允许使用 Python3.5 中添加的 async
/await
语法,这使得您的代码有效的避免阻塞从而达到提升响应速度的目的。
首先,在入坑之前, 您应该知道 Sanic 框架和其他的框架相比是与众不同的。
Sanic 不仅仅是一个 框架,它还是一个 Web 服务器, 在后面的 部署 环节中,我们将仔细地探讨这个问题。
Sanic 具备开箱即用的功能,它可以用于编写,部署和扩展生产级 Web 应用程序。
背景
Sanic最早由ChannelCat团队开发,旨在提供一个高性能的异步Web框架。其灵感来自于Flask,并在异步编程的基础上进行了优化。Sanic利用Python3.5引入的async/await语法,使得开发者可以编写快速且高效的异步Web应用程序
速度为先
当下,python都已经更新到了 Python3.12.X 了,如果你还没有使用过 asyncio、和 Python3.5 新增的 async/await 语法,那说明你可能真的是桃花源人,问今是何世,不知有汉,无论魏晋了。
在当下,基于 async/await 语法的异步 Web 框架也有很多,在 github 上找一找比比皆是是,那究竟应该选哪一款呢?在 github 上有一个专门测试各种语言各种 Web 框架速度的项目,我们来看一看简单的数据:
这是所有的 Python Web 框架速度测试,有人可能会问为什么不是从 1 开始排序的,因为这个项目的测试还包含 golang、java、php 等众多语言的 Web 框架,共有 226 款。这里我们只用 Python 来做对比。
可以明显的看到,flask、django、tornado 等老牌的 Python Web 框架已经快要垫底了。
官方地址:Sanic
从Python3+后,各种异步很火,所以说相对于传统的同步框架在某些特定的场景下更加适应,因为同步与异步在并发、实时性上还是有很大差异的
特征(Features)
- 内置极速 web server
- 生产准备就绪
- 极高的拓展性
- 支持 ASGI
- 简单直观的 API 设计
- 社区保障
快速开始(Getting Started)
在我们开始之前,请确保您使用的是 Python3.7 或更高版本。目前已知可以使用的 Python 版本包括:3.7,3.8 和 3.9。
#安装(Install)
pip install sanic
运行(Running)
让我们将上面写好的文件保存为 server.py
, 然后运行它。
sanic server.app
HELLO word的编写
# -*- coding: utf-8 -*-
from sanic import Sanic
from sanic import response
app = Sanic("sanic_demo")
@app.route("/")
def run(request):
return response.text("Hello World !")
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8001, debug=True)
在终端中运行上面应用程序:
http://127.0.0.1:8001就可以看到返回的信息了
基础配置(Basics)
Sanic 会将配置保存在应用程序对象的 Config 属性中,它是一个可以通过字典的形式或者属性的形式进行操作的对象。
app = Sanic("myapp")
app.config.DB_NAME = "appdb"
app.config["DB_USER"] = "appuser"
因此,您也可以使用 update() 方法来更新配置。
db_settings = {
'DB_HOST': 'localhost',
'DB_NAME': 'appdb',
'DB_USER': 'appuser'
}
app.config.update(db_settings)
小提示
在 Sanic 中, 标准做法是使用 大写字母 来命名您的配置名称,如果您将大写名称和小写名称混合使用,可能会导致某些配置无法正常读取,遇到无法解释的状况。
环境变量(Environment variables)
任何使用 SANIC_
作为前缀的环境变量都会被加载并应用于 Sanic 配置。例如:在环境变量中设置 SANIC_REQUEST_TIMEOUT
环境变量后,将会被应用程序自动加载,并传递到 REQUEST_TIMEOUT
配置变量中。
$ export SANIC_REQUEST_TIMEOUT=10
>>> print(app.config.REQUEST_TIMEOUT)
10
您可以自动选择启动时应用程序要读取的变量前缀。
$ export MYAPP_REQUEST_TIMEOUT=10
>>> app = Sanic(__name__, load_env='MYAPP_')
>>> print(app.config.REQUEST_TIMEOUT)
10
同样,您可以完全禁用环境变量的加载。
app = Sanic(__name__, load_env=False)
内置配置(Builtin values)
变量名称 | 默认值 | 说明 |
ACCESS_LOG | True | 访问日志开关 |
AUTO_EXTEND^ | True | Sanic 拓展启用开关 |
AUTO_RELOAD | True | 自动重载开关 |
EVENT_AUTOREGISTER | True | 自动注册信号开关(开启后不存在的事件将会自动注册) |
FALLBACK_ERROR_FORMAT | html | 异常返回格式 |
FORWARDED_FOR_HEADER | X-Forwarded-For | 客户端 IP 和代理 IP:X-Forwarded-For |
FORWARDED_SECRET | None | 用于安全地识别特定的代理服务器(见下文) |
GRACEFUL_SHUTDOWN_TIMEOUT | 15.0 | 强制关闭非空闲连接的等待时间(秒) |
KEEP_ALIVE | True | 是否启用长连接 |
KEEP_ALIVE_TIMEOUT | 5 | 长连接超时时间 |
MOTD^ | True | 是否在启动时展示 MOTD 信息 |
MOTD_DISPLAY | {} | 键/值对显示 MOTD 中的附加任意数据 |
NOISY_EXCEPTIONS ^ | False | 强制禁止异常输出 |
PROXIES_COUNT | None | 应用程序钱代理服务器的数量(见下文) |
REAL_IP_HEADER | None | 客户端真实 IP: X-Real-IP |
REGISTER | True | 是否启用应用程序注册表 |
REQUEST_BUFFER_QUEUE_SIZE | 100 | 请求流缓冲区队列大小 |
REQUEST_ID_HEADER | X-Request-ID | 请求头中的请求 ID 名称:X-Request-ID |
REQUEST_MAX_SIZE | 100000000 | Request 的最大字节数 |
REQUEST_MAX_HEADER_SIZE | 8192 | Request 请求头最大字节数 (最大16384) |
REQUEST_TIMEOUT | 60 | 请求超时时间 |
RESPONSE_TIMEOUT | 60 | 响应超时时间 |
WEBSOCKET_MAX_SIZE | 2^20 | websocket 传入消息最大字节数 |
WEBSOCKET_PING_INTERVAL | 20 | websocket ping 帧 发送间隔 |
WEBSOCKET_PING_TIMEOUT | 20 | websocket pong 帧 响应超时时间 |
提示
如果您使用 Gunicorn 运行,那么
USE_UVLOOP
将会被忽略。在不支持的平台(Windows)上该值默认为 False。如果您处于 ASGI 模式, 那么
WEBSOCKET_
的值将会被忽略
超时(Timeouts)
#请求超时(REQUEST_TIMEOUT)
请求时间用于衡量从建立 TCP 连接到整个 HTTP 请求接收完成所花费的时间。如果请求时间超过了设定的 REQUEST_TIMEOUT
,Sanic 会将其视为客户端错误并将 HTTP 408 作为响应发送给客户端。如果您的客户端需要频繁传递大量的数据, 请您将此参数调至更高或减少传输数据。
#响应超时(RESPONSE_TIMEOUT)
响应时间用于衡量从整个 HTTP 请求接收完成到 Sanic 将响应完整发送至客户端所花费的时间。如果响应时间超过了设定的 RESPONSE_TIMEOUT
,Sanic 会将其视为服务端错误并将 HTTP 503 作为响应发送给客户端。如果您的应用程序需要消耗大量的时间来进行响应,请尝试将此参数调至更高或优化响应效率。
#长连接超时(KEEP_ALIVE_TIMEOUT)
#什么是长连接?长连接超时有什么作用?
Keep-Alive
中文叫做长连接,它是 HTTP1.1 中引入的 HTTP 功能。当发送 HTTP 请求时,客户端(通常是浏览器)可以通过设置 Keep-Alive
标头来指示 http 服务器(Sanic)在发送响应之后不关闭 TCP 连接。这将允许客户端重用现有的 TCP 连接来发送后续的 HTTP 请求,以提高客户端和服务端之间的通讯效率。
在默认情况下,Sanic 中的 Keep-Alive
的值为 True
。如果您的应用程序不需要此功能,可以将其设置为 False。不过此举将导致 Sanic 无视 Keep_Alive
标头,且所有的客户端连接在响应发送完成之后被立即关闭。
TCP 连接打开的时长本质上由服务器自身决定,在 Sanic 中,使用 KEEP_ALIVE_TIMEOUT
作为该值。默认情况下它设置为 5 秒。这与 Apache 的默认值相同。该值足够客户端发送一个新的请求。如非必要请勿更改此项。如需更改,请勿超过 75 秒,除非您确认客户端支持 TCP 连接保持足够久。
小提示:
- Apache httpd 服务器默认 KEEP_ALIVE_TIMEOUT = 5 秒
- Nginx 服务器默认 KEEP_ALIVE_TIMEOUT = 75 秒
- Nginx 性能调整准则使用 KEEP_ALIVE_TIMEOUT = 15 秒
- IE(5-9)客户端 KEEP_ALIVE_LIMIT = 60 秒
- Firefox 客户端 KEEP_ALIVE_LIMIT = 115 秒
- Opera 11 客户端 KEEP_ALIVE_LIMIT = 120 秒
- Chrome 13+ 客户端 KEEP_ALIVE_LIMIT > 300+秒
运行 Sanic(Running Sanic)
Sanic 自带了一个 Web 服务器。在大多数情况下,推荐使用该服务器来部署您的 Sanic 应用。除此之外,您还可以使用支持 ASGI 应用的服务器来部署 Sanic,或者使用 Gunicorn。
#Sanic 服务器(Sanic Server)
当定义了 sanic.Sanic
实例后,我们可以调用其 run
方法,该方法支持以下几个关键字参数:
参数名称 | 默认值 | 参数说明 |
host |
| 服务器监听的地址。 |
port |
| 服务器监听的端口。 |
unix |
| Unix 套接字文件(不是 TCP)。 |
debug |
| 开启 DEBUG 输出 (降低服务器性能)。 |
ssl |
| SSLContext,子进程用于 SSL 加密。 |
sock |
| 服务器接受连接的套接字。 |
workers |
| 要生成的子进程数量。 |
loop |
| 一个兼容 asyncio 的事件循环。如果没有指定,Sanic 会创建自己的事件循环。 |
protocol |
| asyncio.protocol 子类。 |
access_log |
| 启用请求访问日志(显著降低服务器速度)。 |
在该样例中,我们关闭输出访问日志来提升性能。
# server.py
app = Sanic("My App")
app.run(host='0.0.0.0', port=1337, access_log=False)
现在,执行包含 app.run(...)
代码的 Python 脚本。
python server.py
通过命令行运行(Running via command)
#Sanic 命令行界面(Sanic CLI)
Sanic 也提供一个简单的命令行界面,来帮助您通过命令行启动。
比如,如果您在 server.py
文件中初始化了一个 Sanic 应用,您可以使用右侧命令运行程序:
sanic server.app --host=0.0.0.0 --port=1337 --workers=4
您还可以使用 sanic --help
来查看所有选项。
$ sanic --help
usage: sanic [-h] [--version] [--factory] [-s] [-H HOST] [-p PORT] [-u UNIX] [--cert CERT] [--key KEY] [--tls DIR] [--tls-strict-host]
[-w WORKERS | --fast] [--access-logs | --no-access-logs] [--debug] [-d] [-r] [-R PATH] [--motd | --no-motd] [-v]
[--noisy-exceptions | --no-noisy-exceptions]
module
▄███ █████ ██ ▄█▄ ██ █ █ ▄██████████
██ █ █ █ ██ █ █ ██
▀███████ ███▄ ▀ █ █ ██ ▄ █ ██
██ █████████ █ ██ █ █ ▄▄
████ ████████▀ █ █ █ ██ █ ▀██ ███████
To start running a Sanic application, provide a path to the module, where
app is a Sanic() instance:
$ sanic path.to.server:app
Or, a path to a callable that returns a Sanic() instance:
$ sanic path.to.factory:create_app --factory
Or, a path to a directory to run as a simple HTTP server:
$ sanic ./path/to/static --simple
Required
========
Positional:
module Path to your Sanic app. Example: path.to.server:app
If running a Simple Server, path to directory to serve. Example: ./
Optional
========
General:
-h, --help show this help message and exit
--version show program's version number and exit
Application:
--factory Treat app as an application factory, i.e. a () -> <Sanic app> callable
-s, --simple Run Sanic as a Simple Server, and serve the contents of a directory
(module arg should be a path)
Socket binding:
-H HOST, --host HOST Host address [default 127.0.0.1]
-p PORT, --port PORT Port to serve on [default 8000]
-u UNIX, --unix UNIX location of unix socket
TLS certificate:
--cert CERT Location of fullchain.pem, bundle.crt or equivalent
--key KEY Location of privkey.pem or equivalent .key file
--tls DIR TLS certificate folder with fullchain.pem and privkey.pem
May be specified multiple times to choose multiple certificates
--tls-strict-host Only allow clients that send an SNI matching server certs
Worker:
-w WORKERS, --workers WORKERS Number of worker processes [default 1]
--fast Set the number of workers to max allowed
--access-logs Display access logs
--no-access-logs No display access logs
Development:
--debug Run the server in debug mode
-d, --dev Currently is an alias for --debug. But starting in v22.3,
--debug will no longer automatically trigger auto_restart.
However, --dev will continue, effectively making it the
same as debug + auto_reload.
-r, --reload, --auto-reload Watch source directory for file changes and reload on changes
-R PATH, --reload-dir PATH Extra directories to watch and reload on changes
Output:
--motd Show the startup display
--no-motd No show the startup display
-v, --verbosity Control logging noise, eg. -vv or --verbosity=2 [default 0]
--noisy-exceptions Output stack traces for all exceptions
--no-noisy-exceptions No output stack traces for all exceptions
作为模块运行 (As a module)
Sanic 也可以被当做模板直接调用。
python -m sanic server.app --host=0.0.0.0 --port=1337 --workers=4
Sanic 简易服务器
有时,您为了快速搭建一个本地环境,只需要代理一些静态文件。现在,只要指定一个特定的目录,Sanic 就能为您搭建一个简易的静态文件服务器。
sanic ./path/to/dir --simple
这也可以和自动重启功能一起使用。
sanic ./path/to/dir --simple --reload --reload-dir=./path/to/dir
性能方面的考虑 (Performance considerations)
当部署在生产环境时,请确保 debug
模式处于关闭状态。
app.run(..., debug=False)
如果您选择关闭了 access_log
,Sanic 将会全速运行。
如果您的确需要请求访问日志,又想获得更好的性能,可以考虑使用 Nginx 作为代理,让 Nginx 来处理您的访问日志。这种方式要比用 Python 处理快得多得多。
app.run(..., access_log=False)