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, 和发送结构化数据。 更多的信息,可以参考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;
}

最后启动:

  1. redis: nohup redis-server &
  2. django:python manage.py runserver
  3. python server.py (服务端可以用supervisord控制tornado服务)

补充

因为项目原先采用RabbitMQ来做信息分发、Celery任务执行,不过因为时间不够,只能临时先用redis顶着。 如果是RabbitMQ,就需要用Pika来实现具体参考

以上也只利用SSE获取通知,并有深入的处理信息和按频道分发——后面会增加按团队来分发通知的功能。Tornado-sse的源码很短,各位可以细细读读,机制和Websocket的实现是类似的,基于事件嘛。


你可能感兴趣的:(DJANGO 实时系统的另类实现)