Django中集成RabbitMQ消息中间件,实现消息异步处理

目的: web访问中的事件直接传递到其他系统中,异步处理。
传统做法:将消息写入数据库 或文件中,另一个程序后台轮询读取处理。或者通过IPC, socket,发给对方处理程序。
缺点:耦合。两个系统需要共享一个存储空间,数据库或文件,或者直接发送到对方程序中。不论怎样,都需要知道处理程序的存在的具体位置。

利用MQ解决: 直接在django中发送给MQ一个消息,由订阅此消息的外围程序异步处理。

实际例子:每访问一个页面发送一个消息
通过 django middleware 来hook每一个 request

Django Middleware

创建一个类 LogRequestMiddleware ,定义一个方法:process_request

class LogRequestMiddleware(object):
    def process_request(self, request):
        n = time.ctime()
        MQ().send_msg('Get a request at:' + n)

在settings.py 的 MIDDLEWARE_CLASSES 中增加此类,这样我们便创建了自己的一个中间件,用户每刷新一个页面,便会发送一条消息到MQ。

MQ 的设计

MQ类实现为一个单例模式,这样服务器中保留一个连接,不会每次请求都去连接rabbitmq服务器。

import amqplib.client_0_8 as amqp
from settings import mq_host, mq_user, mq_password, mq_ssl

class MQ(object):
    "A RabbitMQ Connection Factory use Singleton pattern"
    __instance = None
    def __init__(self):
        if MQ.__instance is None:
            print 'Create MQ Connection'
            MQ.__instance = amqp.Connection(mq_host, userid=mq_user, password=mq_password, ssl=mq_ssl)
        self.__dict__['conn'] = MQ.__instance

    def __getattr__(self, attr):
        return getattr(self.__instance, attr)

    def __setattr__(self, attr, value):
        return setattr(self.__instance, attr, value)

    def send_msg(self, msg):
        ch = self.conn.channel()
        ch.access_request('/data', active=True, write=True)

        ch.exchange_declare('myfan', 'fanout', auto_delete=True)

        msg = amqp.Message(msg, content_type='text/plain', application_headers={'foo': 7, 'bar': 'baz'})

        ch.basic_publish(msg, 'myfan')

        ch.close()

测试

使用之前post中提到的那个 demo_receiver.py 来监听消息。

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

但是也并没有解决你

但是也并没有解决你所说的缺点把。
既然是async来处理,必然需要有个地方来做缓冲,往往借用db
这个midware后面实现应该也是类似你说的传统方法把

当然了, MQ

当然了, MQ 后面有基于文件或数据库的缓冲。但这些是应用开发者不需要去关心的,包括网络传输问题,存储等问题都帮开发者解决掉了。

Albert,

Albert, RabbitMQ好用吗?性能如何?

RabbitMQ的性能粗测比较

RabbitMQ的性能粗测比较强劲,还没有深入使用。

而另外一个erlang开发的文档数据库 CouchDB 的性能,粗测后比较悲观,可能是我用的不对。