基于内容的RabbitMQ与Python路由
使用RabbitMQ和Python可以实现基于内容的路由吗?
AMQP标准和RabbitMQ声称支持基于内容的路由,但有没有适合Python的库可以用来指定基于内容的绑定等功能呢?
我现在使用的库(py-amqplib http://barryp.org/software/py-amqplib/)似乎只支持基于主题的路由,并且只支持简单的模式匹配(#,*)。
2 个回答
在RabbitMQ中,路由是一个过程,交换机决定把你的消息放到哪些队列里。你把所有消息都发送到交换机,但你只能从队列中接收消息。这意味着交换机在这个过程中是一个活跃的参与者,它会对消息的转发或复制做出一些决定。
RabbitMQ中的主题交换机会查看传入消息中的一个字符串(叫做routing_key),并将其与所有声明希望接收来自交换机消息的队列提供的模式(叫做binding_keys)进行匹配。
RabbitMQ的源代码在网上可以找到,你可以在这里查看主题交换机的代码: http://hg.rabbitmq.com/rabbitmq-server/file/9b22dde04c9f/src/rabbit_exchange_type_topic.erl 那里的很多复杂性是为了处理一种叫做trie的数据结构,这种结构可以实现非常快速的查找。实际上,互联网路由器内部也使用了同样的数据结构。
这里的头部交换机代码 http://hg.rabbitmq.com/rabbitmq-server/file/9b22dde04c9f/src/rabbit_exchange_type_headers.erl 可能更容易理解。你可以看到,制作不同类型的交换机所需的代码并不多。如果你想检查内容(或者只是想快速查看消息的前几个字节),你应该能够很快区分出XML、JSON或其他格式。而且如果你的JSON对象和XML文档保持特定的元素顺序,那么你应该能够在不解析整个消息体的情况下,区分不同的JSON对象(或XML文档类型)。
答案是“是的”,但还有更多内容... :)
首先,我们先来理解一下什么是基于内容的路由。它有两种可能的意思。有些人说它是基于消息的头部部分,另一些人则认为是基于消息的数据部分。
如果我们采用第一个定义,基本的假设是这样的:数据在某个地方产生,然后通过某个软件发送到AMQP代理。我们假设这个软件对数据了解得足够多,可以在消息的头部放入描述内容的键值对(KV)。理想情况下,发送者也是数据的生产者,因此它拥有我们所需的所有信息。假设数据是一张图片,我们可以让发送者在消息头中放入这样的KV对:
width=1024
height=768
mode=bw
photographer=John Doe
现在我们可以通过创建合适的队列来实现基于内容的路由。假设我们需要对黑白图片和彩色图片进行不同的操作。我们可以创建两个队列,一个接收mode=bw
的消息,另一个接收mode=colour
的消息。然后,我们有不同的客户端在这些队列上监听。代理负责路由,而我们的客户端不需要知道路由的细节。
如果我们采用第二个定义,那么假设就有所不同。我们假设数据在某个地方产生,并通过某个软件发送到AMQP代理。但我们认为不合理要求这个软件在头部填入KV对。相反,我们希望根据数据本身来做路由决策。
在AMQP中,有两种选择:你可以为特定的数据格式实现一个新的交换类型,或者将路由委托给客户端。
在RabbitMQ中,有直接(1对1)、扇出(1对N)、头部(头部过滤的1对N)和主题(主题过滤的1对N)交换类型,但你也可以根据AMQP标准实现自己的交换类型。这需要阅读大量的RabbitMQ文档,并用Erlang实现交换。
另一种选择是用Python创建一个AMQP客户端,监听一个特殊的“内容路由队列”。每当有消息到达这个队列时,你的路由客户端就会接收它,做出路由决策,然后将消息发送回代理到合适的队列。因此,为了实现上面的场景,你的Python程序会检测图片是黑白的还是彩色的,并将其(重新)发送到“黑白”或“彩色”队列,之后某个合适的客户端会接手处理。
所以对于你的第二个问题,实际上在你的客户端中并没有做任何基于内容的绑定。你的客户端要么像上面描述的那样工作,要么你在RabbitMQ中创建一个新的交换类型。然后,在你的客户端设置代码中,你定义交换类型为你新的类型。
希望这能解答你的问题!