介绍(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 框架已经快要垫底了。

速度飞快的python框架Sanic,老牌flask、django逐步垫底_Web

官方地址:Sanic

从Python3+后,各种异步很火,所以说相对于传统的同步框架在某些特定的场景下更加适应,因为同步与异步在并发、实时性上还是有很大差异的

特征(Features)

  • 内置极速 web server
  • 生产准备就绪
  • 极高的拓展性
  • 支持 ASGI
  • 简单直观的 API 设计
  • 社区保障

快速开始(Getting Started)

在我们开始之前,请确保您使用的是 Python3.7 或更高版本。目前已知可以使用的 Python 版本包括:3.7,3.8 和 3.9。

#安装(Install)

pip install sanic

速度飞快的python框架Sanic,老牌flask、django逐步垫底_服务器_02

运行(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)


在终端中运行上面应用程序:

速度飞快的python框架Sanic,老牌flask、django逐步垫底_服务器_03

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

"127.0.0.1"

服务器监听的地址。

port

8000

服务器监听的端口。

unix

None

Unix 套接字文件(不是 TCP)。

debug

False

开启 DEBUG 输出 (降低服务器性能)。

ssl

None

SSLContext,子进程用于 SSL 加密。

sock

None

服务器接受连接的套接字。

workers

1

要生成的子进程数量。

loop

None

一个兼容 asyncio 的事件循环。如果没有指定,Sanic 会创建自己的事件循环。

protocol

HttpProtocol

asyncio.protocol 子类。

access_log

True

启用请求访问日志(显著降低服务器速度)。

在该样例中,我们关闭输出访问日志来提升性能。

# 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)