非同步服務_快如閃電的非同步伺服器Uvicorn
技術標籤:非同步服務
什麼是 Uvicorn ?
答:Uvicorn 是基於 uvloop 和 httptools 構建的非常快速的 ASGI 伺服器。
什麼是 uvloop 和 httptools ?
答: uvloop 用於替換標準庫 asyncio 中的事件迴圈,使用 Cython 實現,它非常快,可以使 asyncio 的速度提高 2-4 倍。asyncio 不用我介紹吧,寫非同步程式碼離不開它。
httptools 是 nodejs HTTP 解析器的 Python 實現。
什麼是 ASGI 伺服器?
答: 非同步閘道器協議介面,一個介於網路協議服務和 Python 應用之間的標準介面,能夠處理多種通用的協議型別,包括 HTTP,HTTP2 和 WebSocket。
請簡單介紹下 Uvicorn
答:目前,Python 仍缺乏非同步的閘道器協議介面,ASGI 的出現填補了這一空白,現在開始,我們能夠使用共同的標準為所有的非同步框架來實現一些工具,ASGI 幫助 Python 在 Web 框架上和 Node.JS 及 Golang 相竟爭,目標是獲得高效能的 IO 密集型任務,ASGI 支援 HTTP2 和 WebSockets,WSGI 是不支援的。
Uvicorn 目前支援 HTTP1.1 和 WebSocket,計劃支援 HTTP2。
使用方法:
$ pip install uvicorn
建立一個檔案 example.py
async def app(scope, receive, send): assert scope['type'] == 'http' await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ [b'content-type', b'text/plain'], ] }) await send({ 'type': 'http.response.body', 'body': b'Hello, world!', })
啟動 Uvicorn
$ uvicorn example:app
你也可以不使用命令列,直接執行你的指令碼也是可以的,如下:
import uvicorn
async def app(scope, receive, send):
...
if __name__ == "__main__":
uvicorn.run("example:app", host="127.0.0.1", port=5000, log_level="info")
使用命令列時,你可以使用 uvicorn --help
來獲取幫助。
Usage: uvicorn [OPTIONS] APP
Options:
--host TEXT Bind socket to this host. [default:
127.0.0.1]
--port INTEGER Bind socket to this port. [default: 8000]
--uds TEXT Bind to a UNIX domain socket.
--fd INTEGER Bind to socket from this file descriptor.
--reload Enable auto-reload.
--reload-dir TEXT Set reload directories explicitly, instead
of using the current working directory.
--workers INTEGER Number of worker processes. Defaults to the
$WEB_CONCURRENCY environment variable if
available. Not valid with --reload.
--loop [auto|asyncio|uvloop|iocp]
Event loop implementation. [default: auto]
--http [auto|h11|httptools] HTTP protocol implementation. [default:
auto]
--ws [auto|none|websockets|wsproto]
WebSocket protocol implementation.
[default: auto]
--lifespan [auto|on|off] Lifespan implementation. [default: auto]
--interface [auto|asgi3|asgi2|wsgi]
Select ASGI3, ASGI2, or WSGI as the
application interface. [default: auto]
--env-file PATH Environment configuration file.
--log-config PATH Logging configuration file.
--log-level [critical|error|warning|info|debug|trace]
Log level. [default: info]
--access-log / --no-access-log Enable/Disable access log.
--use-colors / --no-use-colors Enable/Disable colorized logging.
--proxy-headers / --no-proxy-headers
Enable/Disable X-Forwarded-Proto,
X-Forwarded-For, X-Forwarded-Port to
populate remote address info.
--forwarded-allow-ips TEXT Comma separated list of IPs to trust with
proxy headers. Defaults to the
$FORWARDED_ALLOW_IPS environment variable if
available, or '127.0.0.1'.
--root-path TEXT Set the ASGI 'root_path' for applications
submounted below a given URL path.
--limit-concurrency INTEGER Maximum number of concurrent connections or
tasks to allow, before issuing HTTP 503
responses.
--backlog INTEGER Maximum number of connections to hold in
backlog
--limit-max-requests INTEGER Maximum number of requests to service before
terminating the process.
--timeout-keep-alive INTEGER Close Keep-Alive connections if no new data
is received within this timeout. [default:
5]
--ssl-keyfile TEXT SSL key file
--ssl-certfile TEXT SSL certificate file
--ssl-version INTEGER SSL version to use (see stdlib ssl module's)
[default: 2]
--ssl-cert-reqs INTEGER Whether client certificate is required (see
stdlib ssl module's) [default: 0]
--ssl-ca-certs TEXT CA certificates file
--ssl-ciphers TEXT Ciphers to use (see stdlib ssl module's)
[default: TLSv1]
--header TEXT Specify custom default HTTP response headers
as a Name:Value pair
--help Show this message and exit.
```
## 使用程序管理器
使用程序管理器確保你以彈性方式執行執行多個程序,你可以執行伺服器升級而不會丟棄客戶端的請求。
一個程序管理器將會處理套接字設定,啟動多個伺服器程序,監控程序活動,監聽程序重啟、關閉等訊號。
Uvicorn 提供一個輕量級的方法來執行多個工作程序,比如 `--workers 4`,但並沒有提供進行的監控。
### 使用 Gunicorn
Gunicorn 是成熟的,功能齊全的伺服器,Uvicorn 內部包含有 Guicorn 的 workers 類,允許你執行 ASGI 應用程式,這些 workers 繼承了所有 Uvicorn 高效能的特點,並且給你使用 Guicorn 來進行程序管理。
這樣的話,你可能動態增加或減少程序數量,平滑地重啟工作程序,或者升級伺服器而無需停機。
在生產環境中,Guicorn 大概是最簡單的方式來管理 Uvicorn 了,生產環境部署我們推薦使用 Guicorn 和 Uvicorn 的 worker 類:
```python
gunicorn example:app -w 4 -k uvicorn.workers.UvicornWorker
執行上述命令將開戶 4 個工作程序,其中 UvicornWorker 的實現使用 uvloop 和httptools 實現。在 PyPy 下執行,你可以使用純 Python 實現,可以通過使用UvicornH11Worker 類來做到這一點。
gunicorn -w 4 -k uvicorn.workers.UvicornH11Worker
Gunicorn 為 Uvicorn 提供了不同的配置選項集,但是一些配置暫不支援,如--limit-concurrency
。
使用 Supervisor
Supervisor 作為程序管理器,以下兩點二選一:
- 使用其檔案描述符將套接字移交給 uvicorn,supervisor 始終將檔案描述符置 0,並且必須在本 fcgi-program 中進行設定。
- 為每個 uvicorn 程序使用 UNIX 套接字。
一個簡單的主管配置可能看起來像這樣: administratord.conf:
[supervisord]
[fcgi-program:uvicorn]
socket = tcp:// localhost:8000
命令= venv / bin / uvicorn --fd 0示例:App
numprocs = 4
process_name = uvicorn-%(process_num)d
stdout_logfile = / dev /標準輸出
stdout_logfile_maxbytes = 0
然後執行supervisord -n。
使用 Circus
使用 Circus 與 Supervisor 很類似。配置檔案 circus.ini 如下:
[watcher:web]
cmd = venv/bin/uvicorn --fd $(circus.sockets.web) example:App
use_sockets = True
numprocesses = 4
[socket:web]
host = 0.0.0.0
port = 8000
與 Nginx 部署
Nginx 作為 Uvicorn 程序的代理並不是必須的,你可以使用 Nginx 做為負載均衡。推薦使用 Nginx 時配置請求頭,如 X-Forwarded-For
,X-Forwarded-Proto
,以便 Uvicorn 識別出真正的客戶端資訊,如 IP 地址,scheme 等。這裡有一個配置檔案的樣例:
http {
server {
listen 80;
client_max_body_size 4G;
server_name example.com;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://uvicorn;
}
location /static {
# path for static files
root /path/to/app/static;
}
}
upstream uvicorn {
server unix:/tmp/uvicorn.sock;
}
}
使用 HTTPS
使用 HTTPS 證書是必須的,推薦使用免費的 Let's Encrypt。
$ uvicorn example:app --port 5000 --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem
使用 Gunicorn 也可以直接使用證書。
$ gunicorn --keyfile=./key.pem --certfile=./cert.pem -k uvicorn.workers.UvicornWorker example:app
參考文件
- 官方文件-介紹。
- 官方文件-部署。
關注微信公眾號:Python七號,和我一起學習 Python。