RabbitMQ/AMQP: одиночная очередь, несколько потребителей для одного сообщения?

Я только начинаю использовать RabbitMQ и AMQP в целом.

  • У меня очередь сообщений
  • У меня несколько пользователей, и я хотел бы делать разные вещи с тем же сообщением.

Большая часть документации RabbitMQ, по-видимому, ориентирована на круговое движение, то есть когда одно сообщение потребляется одним потребителем, причем нагрузка распределяется между каждым потребителем. Это действительно поведение, которое я свидетельствую.

Пример: производитель имеет одну очередь и отправляет сообщения каждые 2 секунды:

var amqp = require('amqp');
var connection = amqp.createConnection({ host: "localhost", port: 5672 });
var count = 1;

connection.on('ready', function () {
  var sendMessage = function(connection, queue_name, payload) {
    var encoded_payload = JSON.stringify(payload);  
    connection.publish(queue_name, encoded_payload);
  }

  setInterval( function() {    
    var test_message = 'TEST '+count
    sendMessage(connection, "my_queue_name", test_message)  
    count += 1;
  }, 2000) 


})

А вот потребитель:

var amqp = require('amqp');
var connection = amqp.createConnection({ host: "localhost", port: 5672 });
connection.on('ready', function () {
  connection.queue("my_queue_name", function(queue){
    queue.bind('#'); 
    queue.subscribe(function (message) {
      var encoded_payload = unescape(message.data)
      var payload = JSON.parse(encoded_payload)
      console.log('Recieved a message:')
      console.log(payload)
    })
  })
})

Если я дважды запускаю пользователя, , я вижу, что каждый потребитель потребляет альтернативные сообщения в циклическом режиме. Например, я увижу сообщения 1, 3, 5 в одном терминале, 2, 4, 6 в другом.

Мой вопрос:

  • Могу ли я, чтобы каждый потребитель получал одни и те же сообщения? То есть, оба потребителя получают сообщение 1, 2, 3, 4, 5, 6? Что это называется в AMQP/RabbitMQ? Как обычно он настроен?

  • Это обычно делается? Должен ли я просто иметь обменный маршрут сообщение в две отдельные очереди с одним потребителем?

Ответ 1

Могу ли я, чтобы каждый потребитель получал одни и те же сообщения? То есть, оба потребителя получают сообщение 1, 2, 3, 4, 5, 6? Что это называется в AMQP/RabbitMQ? Как он обычно настроен?

Нет, если потребители находятся в одной очереди. Из RabbitMQ Руководство по AMQP:

важно понять, что в AMQP 0-9-1 сообщения сбалансированы по нагрузке между потребителями.

Это, по-видимому, означает, что циклическое поведение в очереди - это заданный, а не настраиваемый. Т.е. отдельные очереди нужны для того, чтобы один и тот же идентификатор сообщения обрабатывался несколькими потребителями.

Это обычно делается? Должен ли я просто иметь обменный маршрут сообщение в две отдельные очереди с одним потребителем вместо?

Нет, нет, одна очередь/несколько потребителей с каждым каждым клиентом, обрабатывающим один и тот же идентификатор сообщения, не представляется возможным. Имея обменный маршрут, сообщение на две отдельные очереди действительно лучше.

Поскольку мне не требуется слишком сложная маршрутизация, разветкитель обмена справится с этим. Я раньше не фокусировался на обмене, поскольку node -amqp имеет концепцию обмена по умолчанию, позволяющую публиковать сообщения в соединении напрямую, однако большинство сообщений AMQP публикуются для определенного обмена.

Здесь мой обмен фанатов, как отправка, так и получение:

var amqp = require('amqp');
var connection = amqp.createConnection({ host: "localhost", port: 5672 });
var count = 1;

connection.on('ready', function () {
  connection.exchange("my_exchange", options={type:'fanout'}, function(exchange) {   

    var sendMessage = function(exchange, payload) {
      console.log('about to publish')
      var encoded_payload = JSON.stringify(payload);
      exchange.publish('', encoded_payload, {})
    }

    // Recieve messages
    connection.queue("my_queue_name", function(queue){
      console.log('Created queue')
      queue.bind(exchange, ''); 
      queue.subscribe(function (message) {
        console.log('subscribed to queue')
        var encoded_payload = unescape(message.data)
        var payload = JSON.parse(encoded_payload)
        console.log('Recieved a message:')
        console.log(payload)
      })
    })

    setInterval( function() {    
      var test_message = 'TEST '+count
      sendMessage(exchange, test_message)  
      count += 1;
    }, 2000) 
 })
})

Ответ 2

Просто прочитайте учебник по кроличнику. Вы публикуете сообщение для обмена, а не для очереди; он затем направляется в соответствующие очереди. В вашем случае вы должны привязать отдельную очередь для каждого пользователя. Таким образом, они могут потреблять сообщения полностью независимо.

Ответ 3

Последние несколько ответов почти правильны - у меня есть множество приложений, которые генерируют сообщения, которые должны быть в конечном итоге с разными потребителями, поэтому процесс очень прост.

Если вы хотите, чтобы несколько пользователей имели одно и то же сообщение, выполните следующую процедуру.

Создайте несколько очередей, по одному для каждого приложения, которое должно получать сообщение, в каждом из свойств очереди, "привяжите" тег маршрутизации обменом amq.direct. Измените публикацию приложения для отправки на amq.direct и используйте тег маршрутизации (а не очередь). AMQP затем скопирует сообщение в каждую очередь с тем же связыванием. Работает в обаянии:)

Пример: Предположим, что у меня есть строка JSON, которую я генерирую, я публикую ее на бирже "amq.direct", используя тег маршрутизации "new-sales-order", у меня есть очередь для моего приложения order_printer, которое печатает заказ, У меня есть очередь для моей биллинговой системы, которая отправит копию заказа и выставит счет клиенту, и у меня есть система веб-архива, в которой я архивирую заказы по причинам истории/соблюдения, и у меня есть клиентский веб-интерфейс, где заказы отслеживаются как другая информация идет о порядке.

Итак, мои очереди: order_printer, order_billing, order_archive и order_tracking У всех есть привязанный к ним привязанный тег "новый-порядок продаж", все 4 получат данные JSON.

Это идеальный способ отправить данные без приложения публикации, зная или заботясь о принимающих приложениях.

Ответ 4

Шаблон отправки - это взаимно однозначное отношение. Если вы хотите "отправить" нескольким получателям, вы должны использовать шаблон pub/sub. Подробнее см. http://www.rabbitmq.com/tutorials/tutorial-three-python.html.

Ответ 5

Да, каждый потребитель может получать одни и те же сообщения. посмотри на http://www.rabbitmq.com/tutorials/tutorial-three-python.html http://www.rabbitmq.com/tutorials/tutorial-four-python.html http://www.rabbitmq.com/tutorials/tutorial-five-python.html

для разных способов маршрутизации сообщений. Я знаю, что они предназначены для python и java, но хорошо понять принципы, решить, что вы делаете, а затем найти, как это сделать в JS. Похоже, вы хотите сделать простой фанат (учебник 3), который отправляет сообщения во все очереди, подключенные к обмену.

Разница с тем, что вы делаете, и что вы хотите сделать, это в основном то, что вы собираетесь настраивать и обменивать или набирать разветвление. Экзаменаторы Fanout отправляют все сообщения во все связанные очереди. Каждая очередь будет иметь потребитель, который будет иметь доступ ко всем сообщениям отдельно.

Да, это обычно делается, это одна из особенностей AMPQ.

Ответ 6

RabbitMQ/AMQP: одиночная очередь, несколько потребителей для того же сообщения и обновления страницы.

rabbit.on('ready', function () {    });
    sockjs_chat.on('connection', function (conn) {

        conn.on('data', function (message) {
            try {
                var obj = JSON.parse(message.replace(/\r/g, '').replace(/\n/g, ''));

                if (obj.header == "register") {

                    // Connect to RabbitMQ
                    try {
                        conn.exchange = rabbit.exchange(exchange, { type: 'topic',
                            autoDelete: false,
                            durable: false,
                            exclusive: false,
                            confirm: true
                        });

                        conn.q = rabbit.queue('my-queue-'+obj.agentID, {
                            durable: false,
                            autoDelete: false,
                            exclusive: false
                        }, function () {
                            conn.channel = 'my-queue-'+obj.agentID;
                            conn.q.bind(conn.exchange, conn.channel);

                            conn.q.subscribe(function (message) {
                                console.log("[MSG] ---> " + JSON.stringify(message));
                                conn.write(JSON.stringify(message) + "\n");
                            }).addCallback(function(ok) {
                                ctag[conn.channel] = ok.consumerTag; });
                        });
                    } catch (err) {
                        console.log("Could not create connection to RabbitMQ. \nStack trace -->" + err.stack);
                    }

                } else if (obj.header == "typing") {

                    var reply = {
                        type: 'chatMsg',
                        msg: utils.escp(obj.msga),
                        visitorNick: obj.channel,
                        customField1: '',
                        time: utils.getDateTime(),
                        channel: obj.channel
                    };

                    conn.exchange.publish('my-queue-'+obj.agentID, reply);
                }

            } catch (err) {
                console.log("ERROR ----> " + err.stack);
            }
        });

        // When the visitor closes or reloads a page we need to unbind from RabbitMQ?
        conn.on('close', function () {
            try {

                // Close the socket
                conn.close();

                // Close RabbitMQ           
               conn.q.unsubscribe(ctag[conn.channel]);

            } catch (er) {
                console.log(":::::::: EXCEPTION SOCKJS (ON-CLOSE) ::::::::>>>>>>> " + er.stack);
            }
        });
    });

Ответ 7

Чтобы получить нужное поведение, просто каждый потребитель потребляет из своей очереди. Вам нужно будет использовать тип непрямого обмена (тема, заголовок, разветвление), чтобы сразу получить сообщение ко всем очередям.

Ответ 8

Как я оцениваю ваше дело:

  • У меня есть очередь сообщений (ваш источник для приема сообщений, давайте назовите его q111)

  • У меня есть несколько потребителей, и я хотел бы делать разные вещи с тем же сообщением.

Ваша проблема здесь в том, что в этой очереди получено 3 сообщения, сообщение 1 потребляется потребителем A, другие потребители B и C потребляют сообщения 2 и 3. Если вам нужна установка, в которой кролик переходит на одинаковые копии всех этих трех сообщений (1,2,3) для всех трех подключенных потребителей (A, B, C) одновременно.

В то время как для достижения этого можно сделать много конфигураций, простой способ состоит в использовании следующей концепции двух шагов:

  • Используйте динамический кролик-ковш для получения сообщений из нужной очереди (q111) и публикуйте в обмен на разветвление (обмен исключительно для создания и выделение для этой цели).
  • Теперь переконфигурируйте своих потребителей A, B и C (которые слушали очередь (q111)), чтобы прослушивать этот обмен Fanout напрямую, используя эксклюзивную и анонимную очередь для каждого пользователя.

Примечание. Хотя использование этой концепции не потребляется непосредственно из исходной очереди (q111), поскольку уже принятые сообщения не будут перекошены на ваш обмен Fanout.

Если вы считаете, что это не удовлетворяет вашим точным требованиям... не стесняйтесь публиковать свои предложения:-)

Ответ 10

Я думаю, вы должны проверить отправку сообщений с помощью обменника fan-out. Таким образом, вы получите одно и то же сообщение для разных потребителей, в таблице RabbitMQ создает разные очереди для каждого из этих новых потребителей/подписчиков.

Это ссылка для примера учебника в javascript https://www.rabbitmq.com/tutorials/tutorial-one-javascript.html

Ответ 11

В этом сценарии есть один интересный вариант, которого я не нашел в ответах.

Вы можете Nack сообщения с функцией "требовать" в одном потребителе для обработки их в другом. Вообще говоря, это не правильный путь, но, может быть, это будет достаточно хорошо для кого-то.

https://www.rabbitmq.com/nack.html

И остерегайтесь петель (когда все врачи накручивают + требуют сообщения)!