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, 和发送结构化数据。 更多的信息,可以参考Stream Updates with Server-Sent Events ,Killing a library(用ruby实现了SSE,略简单)
迫于工程项目的紧急性,只能找现成的轮子——今天的主角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中加入
如果是本地的话,需要修改为127.0.0.1:8888/
服务器环境如果是Apache
ProxyPass http://localhost:8888
如果是nginx:
location /sse/ {
rewrite ^(.*)$ / break; # to root of our tornado
proxy_buffering off; # to push immediately
proxy_pass http://127.0.0.1:8888;
}
最后启动:
因为项目原先采用RabbitMQ来做信息分发、Celery任务执行,不过因为时间不够,只能临时先用redis顶着。 如果是RabbitMQ,就需要用Pika来实现具体参考
以上也只利用SSE获取通知,并有深入的处理信息和按频道分发——后面会增加按团队来分发通知的功能。Tornado-sse的源码很短,各位可以细细读读,机制和Websocket的实现是类似的,基于事件嘛。