DJANGO 實時系統的另類實現
http://scriptogr.am/pison/post/django-
概述
基於Tornado, Redis, Django, SSE協議 實現Django的實時通訊系統
緣起
業務上要求能夠實現一旦伺服器收到警報,立刻將資訊反饋到頁面——簡單地說,就是彈框加BIBI聲。
角色
由於Django不支援非同步,所以本質上是無法滿足實時的要求——他一個請求進來是block住的,直到任務完成才返回。 即使是用uwsgi技術,也只能將可處理的執行緒支撐到兩位數以下。
Tornado天生支援非同步,當然也可以用Flask。
聽Alex Maccaw說SSE( Server-Sent Events)比Websocket更好。舉個簡單的例子,SSE不需要特殊的協議支援,因為它是基於傳統的HTTP,而Websocket則是需要full-duplex connections。其次Websocket缺少一些工程設計,而SSE能夠設定自動重新連線, 事件ID, 和傳送結構化資料。 更多的資訊,可以參考
迫於工程專案的緊急性,只能找現成的輪子——今天的主角Tornado-sse
需要的安裝Django-sse(Django內傳送資訊到redis), sse(將資訊處理成符合sse標準的包), redis(Django和Tornado通訊)。
步驟
在Django的setting檔案中新增
### SSE ### INSTALLED_APPS += ( 'redis', 'django_sse', 'tornado_sse', ) REDIS_SSEQUEUE_CONNECTION_SETTINGS = { 'location': 'localhost:6379', 'db': 0, } ### SSE ###
在tasks.py檔案(就是你用來執行任務的檔案)
from django_sse.redisqueue import send_event
def notify(message):
info = json.dumps({
'type': 'foo',
'html': message,
})
send_event('message', info, 'sse') # 預設頻道
return True
當然我建議將這個函式設定為signal觸發
在base.html中加入
<head> <script type="text/javascript" src="{{ STATIC_URL }}tornado_sse/jquery.eventsource.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}tornado_sse/sse.js"></script> </head> <body sse-data="/sse/"> </body> 如果是本地的話,需要修改為127.0.0.1:8888/
伺服器環境如果是Apache
<Location /sse>
ProxyPass http://localhost:8888
</Location>
如果是nginx:
location /sse/ {
rewrite ^(.*)$ / break; # to root of our tornado
proxy_buffering off; # to push immediately
proxy_pass http://127.0.0.1:8888;
}
最後啟動:
- redis: nohup redis-server &
- django:python manage.py runserver
- python server.py (服務端可以用supervisord控制tornado服務)
補充
因為專案原先採用RabbitMQ來做資訊分發、Celery任務執行,不過因為時間不夠,只能臨時先用redis頂著。 如果是RabbitMQ,就需要用Pika來實現具體參考
以上也只利用SSE獲取通知,並有深入的處理資訊和按頻道分發——後面會增加按團隊來分發通知的功能。Tornado-sse的原始碼很短,各位可以細細讀讀,機制和Websocket的實現是類似的,基於事件嘛。