如何用保证FIFO控制最大并行度?

时间:2017-01-23 14:49:49

标签: python rabbitmq

我正在研究使用rabbitmq来管理我的应用程序的事件。更具体地说,我想:

  1. 确保我获得每队列事件的FIFO处理:在完全处理完所有先前事件之前,不会处理新事件。
  2. 确保我可以控制并行执行的事件数。
  3. 一个典型的例子是我有200到800个队列,我想不允许并行超过8个工作人员。

    我决定使用n + 1个队列和n + m个工作人员(n = 200到800和m = 8):

    • 第一类工人(n)负责确保FIFO 队列中的所有事件
    • 第二种类型的工人(m)只是以并行的方式执行事件

    这是伪代码:

    def queues_declare(channel):
        channel.queue_declare(queue='type1', durable=True)
        channel.queue_declare(queue='type1_callback', durable=True)
        channel.queue_declare(queue='type2', durable=True)
    
    def type1(channel):
        def callback_type1(ch, method, properties, body):
            channel.basic_publish(exchange='',
                                  routing_key='type2',
                                  body=body,
                                  properties=pika.BasicProperties(
                                      reply_to = "type1_callback",
                                      correlation_id = method.delivery_tag,
                                      delivery_mode = 2,
                                  ))
        def callback_type1_callback(ch, method, properties, body):
            ch.basic_ack(delivery_tag = properties.correlation_id)
            ch.basic_ack(delivery_tag = method.delivery_tag)
    
        queues_declare(channel)
        channel.basic_qos(prefetch_count=1)
        channel.basic_consume(callback_type1,
                              queue='type1')
        channel.basic_consume(callback_type1_callback,
                              queue='type1_callback')
    
    def type2(channel):
        queues_declare(channel)
    
        def callback_type2(ch, method, properties, body):
            # XXX: do work !
            channel.basic_publish(exchange='',
                                  routing_key=properties.reply_to,
                                  body='',
                                  properties=pika.BasicProperties(
                                      correlation_id = properties.correlation_id,
                                  ))
            ch.basic_ack(delivery_tag = method.delivery_tag)
    
        channel.basic_consume(callback_type2,
                              queue='type2')
    

    所以,我的问题是:这是用rabbitmq实现我想要的正确方法吗?有没有更好的方法来控制并行性并确保FIFO处理?

1 个答案:

答案 0 :(得分:0)

这里有几个问题。

  1. 保证FIFO顺序的唯一方法是使用单个队列来序列化访问。并且使用大量只是将消息重新发布到这个单一队列的工作人员实际上放松了一点保证 - 所以最好以消息将直接到达该队列的方式设置消息传递结构。 无论如何,最大的缺点是你的性能受到单核CPU性能的限制。

  2. 有一种方法可以仅使用RabbitMQ本身来限制并发性。您需要为此目的创建一个单独的队列,并使用等于所需并发级别的消息量预先填充它。然后你工作人员应该做的第一件事就是尝试得到那个信息,但不要承认它 - 所以这个消息将在这个非工作状态下悬挂一个工人的整个一生。当工作者死亡(或只是关闭AMQP连接)时,任何其他工作人员都可以访问该消息以获取它。但同样,那里有一个缺点 - 这只能在非集群环境中可靠地运行。例如。请参阅https://aphyr.com/posts/315-jepsen-rabbitmq,其中几乎正在测试这个用例。