部署 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
內容目錄
A. 前言
Channels(ASGI)應用程式的部署與WSGI應用程式類似——您需要將它們加載到像Daphne這樣的伺服器中,並且可以根據需要調整伺服器進程的數量。對於Channels專案來說額外的一個可選需求是配置一個通道層。下面將介紹這兩個步驟。
B. 設定ASGI應用程式
如同在安裝和路由一節中所討論的,您將有一個類似於 myproject/asgi.py 的文件,該文件將定義您的根應用程式。這幾乎可以確定是您的頂層(協議類型)路由器。
下面是一個可能的 asgi.py 文件範例:
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from django.urls import path
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
from chat.consumers import AdminChatConsumer, PublicChatConsumer
application = ProtocolTypeRouter({
# Django's ASGI application to handle traditional HTTP requests
"http": django_asgi_app,
# WebSocket chat handler
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter([
path("chat/admin/", AdminChatConsumer.as_asgi()),
path("chat/", PublicChatConsumer.as_asgi()),
])
)
),
})
C. 設定Channel後端服務
通常,頻道後端會連接到一個或多個作為通信層的中央伺服器。例如,Redis 後端會連接到一個 Redis 伺服器。所有這些設置都放在 CHANNEL_LAYERS 設定中;以下是一個遠端 Redis 伺服器的範例:
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("redis-server-name", 6379)],
},
},
}
記得線透過指令(pip install -U channels_redis
)安裝套件。
D. Run protocol servers
為了與外界溝通,您的 Channels/ASGI 應用程序需要加載至協議伺服器中。這些伺服器可以像 WSGI 伺服器一樣以 HTTP 模式運行您的應用程序,但它們也可以橋接至各種協議(例如聊天協議、物聯網(IoT)協議,甚至是無線電網路)。所有這些伺服器都有其自身的配置選項,但它們都有一個共同點 – 它們會要求您向其提供一個 ASGI 應用程序來運行。您只需將專案的 asgi.py 文件中的應用程序對象傳遞給協議伺服器作為其應運行的應用程序即可。
daphne -p 8001 myproject.asgi:application
E. HTTP and WebSocket
儘管 ASGI 是一個通用協定,我們無法涵蓋所有可能的伺服器,但很可能您會希望將 Channels 專案部署以便在 HTTP 和可能的 WebSocket 上運作,因此我們將更詳細地介紹這一點。
Channels 專案維護了一個官方的 ASGI HTTP/WebSocket 伺服器,名為 Daphne,我們將討論其配置。其他的 HTTP/WebSocket ASGI 伺服器也是可能的且只要遵循規範就能正常運作,但它們的配置可能會有所不同。
您可以選擇使用 Daphne 來處理所有的請求——無論是 HTTP 還是 WebSocket——或者如果您對穩定性較為保守,可以將標準的 HTTP 請求繼續通過 WSGI 伺服器運行,並僅使用 Daphne 來處理 WSGI 無法處理的事情,如 HTTP 長輪詢和 WebSockets。如果您選擇分開,則需要在 Daphne 和 WSGI 伺服器前放置某些東西來判斷哪些請求應發送到哪一個(可以使用 HTTP 路徑或網域),這裡沒有覆蓋這部分,但請知道您可以這麼做。
如果您將 Daphne 用於所有流量,它會自動協商處理 HTTP 和 WebSocket,因此不需要在不同的網域或路徑上配置 WebSocket(並且它們將能與常規檢視代碼共享 cookie,而如果您是按網域而不是路徑分開,這是做不到的)。
運行 Daphne 時,只需提供一個應用程序,就像需要為 WSGI 伺服器提供應用程序一樣。確保您有一個如上所述的 asgi.py 文件。
然後,您可以運行 Daphne 並將 ASGI 應用程序作為參數提供:
daphne myproject.asgi:application
你應該在一個進程管理器(如 systemd、supervisord)或容器編排系統(如 Kubernetes、Nomad)中運行 Daphne,以確保在需要時 Daphne 能夠重新啟動,並允許你調整進程的數量。如果你想要將多個 Daphne 實例綁定到機器上的同一個端口,使用能在端口上監聽並將文件描述符傳遞給啟動進程的進程管理器,然後通過 –fd NUM 傳遞文件描述符。你也可以指定 Daphne 綁定的端口和 IP:
daphne -b 0.0.0.0 -p 8001 myproject.asgi:application
你可以在 GitHub 上查看關於 Daphne 和其選項的更多資訊。
F. 其他的Web伺服器
您也可以選擇使用其他 ASGI 伺服器來服務 Django Channels。在某種程度上,ASGI 網頁伺服器應該是可以互換的,因為它們都具備基本的功能來處理 HTTP 和 WebSocket 請求。伺服器之間可能存在差異的方面包括其配置和預設值、效能特徵、資源限制的支援、不同的協議與套接字支援,以及程序管理的方法。您可以在 ASGI 實現的文檔中看到更多替代伺服器,例如 Uvicorn。
1. Uvicorn設定
Uvicorn使用方式與Daphne類似,步驟如下:
首先,確保您已經安裝了 Uvicorn。您可以使用 pip 來安裝,接著執行,就完成了。
pip3 install uvicorn
uvicorn myproject.asgi:application
其他用法如下
# 指定 Host 和 Port
uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000
# 重新載入
uvicorn myproject.asgi:application --reload
# 設置Worker數量
uvicorn myproject.asgi:application --workers 4
G. 設定指引
這些是可能的設定範例——它們不保證能立即運行,應被視為指引而非直接的教學。
1. Nginx/Supervisor (Ubuntu)
此範例將在 Ubuntu 伺服器上設置一個 Django 站點,使用 Nginx 作為主要的網頁伺服器,並使用 supervisord 來運行和管理 Daphne。首先,安裝 Nginx 和 Supervisor:
sudo apt install nginx supervisor
現在,您需要創建一個 Supervisor 配置文件(通常位於 /etc/supervisor/conf.d/ 目錄中——這裡我們讓 Supervisor 監聽 TCP 埠,然後將該套接字傳遞給子進程,以便它們能夠共享同一綁定埠:
[fcgi-program:asgi]
# TCP socket used by Nginx backend upstream
socket=tcp://localhost:8000
# Directory where your site's project files are located
directory=/my/app/path
# Each process needs to have a separate socket file, so we use process_num
# Make sure to update "mysite.asgi" to match your project name
command=daphne -u /run/daphne/daphne%(process_num)d.sock --fd 0 --access-log - --proxy-headers mysite.asgi:application
# Number of processes to startup, roughly the number of CPUs you have
numprocs=4
# Give each process a unique name so they can be told apart
process_name=asgi%(process_num)d
# Automatically start and recover processes
autostart=true
autorestart=true
# Choose where you want your log to go
stdout_logfile=/your/log/asgi.log
redirect_stderr=true
為在 Supervisor 配置文件中引用的套接字創建運行目錄:
sudo mkdir /run/daphne/
當以不同的使用者運行 supervisor fcgi-program 時,請更改運行目錄的擁有者設定:
sudo chown <user>.<group> /run/daphne/
/run/ 資料夾在伺服器重啟時會被清空。要使 /run/daphne 資料夾保持持久,請建立一個檔案 /usr/lib/tmpfiles.d/daphne.conf,並將以下內容寫入該檔案:
d /run/daphne 0755 <user> <group>
讓 supervisor 重新閱讀並更新其作業:
sudo supervisorctl reread
sudo supervisorctl update
在命令行中運行帶有 –fd 0 的 daphne 命令會失敗,並導致錯誤 [Errno 88]:在非套接字上的套接字操作。
Supervisor 將自動創建套接字、綁定並在分叉群組中的第一個子進程之前進行監聽。該套接字將通過文件描述符編號 0(零)傳遞給每個子進程。請參閱 https://supervisord.org/configuration.html#fcgi-program-x-section-settings。
接下來,必須告訴 Nginx 將流量代理到正在運行的 Daphne 實例:
upstream channels-backend {
server localhost:8000;
}
...
server {
...
location / {
try_files $uri @proxy_to_app;
}
...
location @proxy_to_app {
proxy_pass http://channels-backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
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-Host $server_name;
}
...
}
在配置 Nginx 以處理 WebSocket 升級請求時,有幾個重要的設定需要注意。首先,必須確保使用 HTTP/1.1 協議,因為 WebSocket 握手需要通過此協議進行。HTTP/1.0 版本不支持持久連接和 `Upgrade` 機制,因此需要在 proxy 配置中指定 `proxy_http_version 1.1;` 確保正確的協議版本。
接著,WebSocket 協議是透過 HTTP 請求的升級機制而實現的,這使得一個普通的 HTTP 連接可以轉變成 WebSocket 連接。為此,需要利用 `proxy_set_header Upgrade $http_upgrade;` 指令來告知 Nginx 傳遞 `Upgrade` 頭部,從而支持這種協議升級。
最後,還需要設置 `proxy_set_header Connection “upgrade”;`,這是為了告訴目標服務器(例如 Daphne),該連接應該始終保持在升級狀態。這與 `Upgrade` 頭部一起構成標準的 WebSocket 升級過程所必需的配置。這樣的設置確保了即使經過代理,WebSocket 連接仍然能夠正常工作。
重新載入 nginx 以套用更改:
sudo service nginx reload
H. 總結
Channels(ASGI)應用程式的部署類似於WSGI應用程式,主要需要將應用程式載入合適的伺服器,例如Daphne,同時可以透過調整伺服器進程數量來進行擴展。此外,Channels專案需要配置一個通道層,常見的是連接到Redis伺服器。要運行Channels/ASGI應用程式,必須使用像Daphne這樣的協議伺服器,並可以使用Nginx和Supervisor在Ubuntu環境中進行管理和配置。在擁有協議伺服器後,您還可以根據需要處理HTTP及WebSocket請求。確保正確設置Nginx來代理至Daphne實例,並使用supervisor控制進程重啟及任務管理。 提供了完整的Nginx和Supervisor設置範例以供參考。
I. 系列文章
-
簡介 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
Django Channels 是擴展 Django 的一個框架,它增加了非同步支持和長連接協議支持,包括 WebSockets 和 MQTT,適合需要持久連接的應用場景。相對於WSGI,ASGI 支… [閱讀全文]
-
實時更新的多人聊天室 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
文章介紹了如何使用 Django Channels 在 Django 架構中建立即時更新的多人聊天室。文章首先講解了安裝 Channels 這個套件的基本步驟,包括 Django 專案初始化、安裝相關… [閱讀全文]
-
Consumers深入說明 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
文章中根據官方文件對Consumer的說明,簡單的翻譯成了繁體中文,同時也增加了些許補充。文章探討了 Django Channels 中 Consumers 的使用,強調其在支持異步通信和長連接協議上… [閱讀全文]
-
資料庫存取 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
ASGI_THREADS, AsyncConsumer, close_old_connections, database_sync_to_async, django channels, Django ORM, SyncConsumer在 Django Channels 中,當處理資料庫存取時,需要區分同步和異步操作。同步消費者不需要額外處理,但異步消費者需使用 `database_sync_to_async` 或異步模型方法來安全… [閱讀全文]
-
Routing – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
Django Channels 提供了處理異步通信和長連接的能力,通過使用 ASGI 路由器來靈活地管理連接。核心元件包括 `ProtocolTypeRouter`,用於協議類型分派,如 HTTP 和… [閱讀全文]
-
Channel Layers – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
async_to_sync, channel, channel layer, channel layer specification, django channels, group, redis channel layer本文探討了 Django Channels 的通道層(Channel Layers),其允許應用實例之間進行非同步通信,適合用於分散式實時應用。通道層透過 `CHANNEL_LAYERS` 配置,支持… [閱讀全文]
-
Sessions、身份驗證、安全性 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
authentication, channels-auth-token-middlewares, csrf, django channels, security, SessionMiddlewareStack, sessionsDjango Channels 支援異步通訊,並在會話、身份驗證和安全性上提供解決方案。它使用 SessionMiddlewareStack 來簡化會話管理,並透過 AuthMiddleware 支援… [閱讀全文]
-
Workers與背景任務 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
Django Channels 和 Celery 是兩種用於處理背景任務和非同步操作的工具,各有其特定優勢。Django Channels 適用於即時通訊、WebSocket 連接和需要即時響應的應用… [閱讀全文]
-
部署 – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
部署 Django Channels(ASGI)應用程式類似於 WSGI,主要需要載入至伺服器如 Daphne,並可以設定通道層,通常會使用 Redis 伺服器。應用程式運行在協議伺服器中,兼容 HT… [閱讀全文]
-
ASGI – Django Channels:實現 WebSocket 異步通信,打造高效的長連接系統
ASGI(非同步伺服器網關介面)是一個規範,用於解綁Django Channels應用程式與特定伺服器,提供撰寫應用程式和中介軟體的共同方式。它採用一個異步可調用函數,包括範圍(Scope)字典、接收… [閱讀全文]