RabbitMQ / AMQP: одна черга, кілька споживачів за одне повідомлення?


146

Я тільки починаю використовувати 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? Як це нормально налаштовано?

  • Це зазвичай робиться? Чи потрібно мені просто обміняти маршрут обміну повідомленням у дві окремі черги, замість цього один споживач?


5
Я не експерт RabbitMQ. Однак те, що у вас зараз називається чергою, але те, що ви хочете, - це теми, дивіться у цьому підручнику: rabbitmq.com/tutorials/tutorial-five-python.html , докладніше про черги та теми: msdn.microsoft.com/en-us /library/windowsazure/hh367516.aspx
UrbanEsc

1
Я вважаю, що він хоче насправді роздуватися, хоча теми також працюватимуть і нададуть більше контролю.
розбійний вовк

Дякуємо @UrbanEsc. Здається, що теми вирішують проблему тим, що одне повідомлення потрапляє до кількох черг, і тому їх споживають усі черги споживачів. Що нахиляє мене далі до сценарію з кількома чергами / одного споживача для мого конкретного випадку.
mikemaccana

1
На 2018 рік (і навіть на 2016 рік і раніше) відповідь - використовувати щось на кшталт Kafka, IMO.
WattsInABox

Відповіді:


115

Чи можу я кожен споживач отримувати однакові повідомлення? Тобто, обидва споживачі отримують повідомлення 1, 2, 3, 4, 5, 6? Як це називається в розмові AMQP / RabbitMQ? Як це нормально налаштовано?

Ні, ні, якщо споживачі стоять на одній черзі. З посібника з концепцій AMQP RabbitMQ :

Важливо розуміти, що в AMQP 0-9-1 повідомлення споживачі збалансовані між собою.

Це, мабуть, означає, що поведінка навколо круга в межах черги є заданою , а не конфігуруваною. Тобто, окремі черги потрібні для того, щоб однаковий ідентифікатор повідомлення оброблявся кількома споживачами.

Це зазвичай робиться? Чи потрібно мені просто обміняти маршрут обміну повідомленням у дві окремі черги, замість цього один споживач?

Ні, це не так, одна черга / кілька споживачів, коли кожен споживач обробляє один ідентифікатор повідомлення, неможливий. Маючи маршрут обміну, повідомлення в дві окремі черги дійсно краще.

Оскільки мені не потрібна занадто складна маршрутизація, обмін вентиляторами впорається з цим чудово. Раніше я не зосереджувався на обмінах, тому що node-amqp має концепцію "обміну за замовчуванням", що дозволяє публікувати повідомлення безпосередньо на з'єднання, проте більшість повідомлень AMQP публікуються на певному обміні.

Ось мій fanout обмін, як надсилання, так і отримання:

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) 
 })
})

1
вентилятор був явно те, що ти хотів. Тут вам би це не допомогло, але я подумав, що я згадаю поведінку круглоліття в черзі, яку можна налаштувати. int prefetchCount = 1; channel.basicQos(prefetchCount); Це дозволить кожному споживачеві отримати повідомлення, як тільки воно закінчиться з попереднім. Замість отримання чергових повідомлень. Знову не вирішує вашу проблему, але може бути корисним людям, щоб знати. Наприклад тут: http://www.rabbitmq.com/tutorials/tutorial-two-java.html у розділі Fair Dispatch
Ommit

3
Для уточнення: "обмін за замовчуванням" не є специфічним для node-amqp. Це загальна концепція AMQP з такими правилами: коли будь-яке повідомлення, опубліковане на обміні за замовчуванням, брокер AMQP трактує ключ маршрутизації (з яким це повідомлення публікується). Тож здається, що ви можете опублікувати в черзі безпосередньо. Але ти це не так. Брокер просто прив’язує кожну чергу до обміну за замовчуванням за допомогою клавіші маршрутизації, рівного імені черги.
Руслан Стельмаченко

2
Чи є альтернатива темам Apache activemq jms у rabbitmq, де не задіяні черги, а швидше багатоадресна передача?
пантоніс

Якщо один і той же користувач входить з декількох пристроїв, то повідомлення отримує лише один пристрій. Яким чином його можна вирішити чи будь-яку ідею, будь ласка?
Рафік

@Rafiq для цього вам слід задати питання.
mikemaccana

28

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


27

Остання пара відповідей майже коректна - у мене є безліч додатків, які генерують повідомлення, які потребують різних споживачів, тому процес дуже простий.

Якщо ви хочете, щоб декілька споживачів отримували одне і те ж повідомлення, виконайте наступну процедуру.

Створіть декілька черг, по одній для кожного додатка, який повинен отримати повідомлення, у властивостях кожної черги "прив'язуйте" тег маршрутизації з обміном amq.direct. Змініть додаток, який ви публікуєте, щоб надіслати amq.direct і використовувати тег маршрутизації (не чергу). Потім AMQP скопіює повідомлення у кожну чергу з однаковим прив'язкою. Працює як шарм :)

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

Тому мої черги: order_printer, order_billing, order_archive та order_tracking У всіх є прив’язаний до них тег "new-sales-order", усі 4 отримають дані JSON.

Це ідеальний спосіб надсилання даних без публікації додатка, не знаючи або піклуючись про додатки, що отримують.


8

Так, кожен споживач може отримувати однакові повідомлення. подивіться на http://www.rabbitmq.com/tutorials/tutorial-three-python.html http://www.rabbitmq.com/tutorials/tutorial-four-python.html http: //www.rabbitmq. com / підручники / підручник-п'ять-python.html

для різних способів маршрутизації повідомлень. Я знаю, що вони призначені для python та java, але добре зрозуміти принципи, вирішити, що ви робите, а потім знайти, як це зробити в JS. Це звучить так, як ви хочете зробити просту фан-аут ( підручник 3 ), який надсилає повідомлення на всі черги, підключені до обміну.

Різниця в тому, що ви робите і що ви хочете зробити, полягає в основному в тому, що ви збираєтеся налаштувати та обмінятись або вводити вентиляцію. Фантастичні екскаватори надсилають усі повідомлення на всі підключені черги. Кожна черга матиме споживача, який матиме доступ до всіх повідомлень окремо.

Так, це зазвичай робиться, це одна з особливостей AMPQ.


чудова відповідь, хіба що "це зазвичай робиться?" Я мав на увазі «кожен споживач отримує однакові повідомлення», що не часто робиться (споживачі в одній черзі завжди круглі). Можливо, я винен у тому, що я недостатньо зрозумів.
mikemaccana

Насправді я б ризикну сказати, що це залежить від того, для чого ви хочете його використовувати. У вас є два основні варіанти pub / sub або черги на роботу. Ваша оригінальна настройка була робочою чергою, але те, що ви хотіли, - це паб / фен. Вони зазначають, що загальне використання тут повністю залежить від того, що ви хочете зробити.
розбійний вовк

Звичайно, але в черзі роботи одне і те ж повідомлення (наприклад, той самий ідентифікатор повідомлення) різними споживачами не обробляється - це неявно кругла робота. Знову ж, це, мабуть, моя вина, що я недостатньо зрозуміла.
mikemaccana

Ми, здається, тут розмовляємо з перехресними цілями.
розбійний вовк

Вибачте за плутанину. Якщо є якийсь спосіб встановити робочу чергу, коли споживачі в одній черзі обробляють один і той же ідентифікатор повідомлення, будь ласка, вкажіть мене на посилання. Інакше я продовжуватиму вірити тому, що я читав деінде.
mikemaccana


3

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);
            }
        });
    });

1

Щоб отримати бажану поведінку, просто попросіть кожного споживача споживати свою власну чергу. Вам доведеться скористатися непрямим типом обміну (тема, заголовок, вентиляція), щоб отримати повідомлення відразу до всіх черг.


1

Як я оцінюю ваш випадок:

  • У мене є черга повідомлень (ваше джерело для отримання повідомлень, дає ім'я q111)

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

Ваша проблема полягає в тому, що 3 черги отримують цю чергу, повідомлення 1 споживає споживач A, інші споживачі B і C споживають повідомлення 2 і 3. Там, де вам потрібна установка, де rabbitmq передає ті самі копії всі ці три повідомлення (1,2,3) для всіх трьох підключених споживачів (A, B, C) одночасно.

Хоча для цього можна зробити багато конфігурацій, простим способом є використання наступних двох етапів:

  • Використовуйте динамічну лопатку rabbitmq, щоб підбирати повідомлення з потрібної черги (q111) та публікувати в обмінниках (обмін виключно створений і призначений для цієї мети).
  • Тепер переконфігуруйте своїх споживачів A, B & C (які слухали чергу (q111)) для прослуховування з цього обміну Fanout безпосередньо, використовуючи ексклюзивну та анонімну чергу для кожного споживача.

Примітка. Під час використання цієї концепції не споживайте безпосередньо з черги-джерела (q111), оскільки повідомлення, які вже були використані, не передаються на ваш обмін Fanout.

Якщо ви думаєте, що це не відповідає вашій точній вимозі ... сміливо розміщуйте свої пропозиції :-)



0

Я думаю, ви повинні перевірити надсилання своїх повідомлень за допомогою обмінника вентиляторів . Таким чином, ви отримаєте те саме повідомлення для різних споживачів, під таблицею RabbitMQ створюються черги для кожного з цих нових споживачів / абонентів.

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


-1

Є один цікавий варіант у цьому сценарії, якого я не знайшов у відповідях тут.

Можна обробляти повідомлення з функцією "requeue" в одного споживача, щоб обробити їх у іншого. Взагалі кажучи, це не правильний шлях, але, можливо, для когось це буде досить добре.

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

І остерігайтеся циклів (коли всі concumers nack + message requeue)!


1
Я б дуже радив проти цього, оскільки це не має масштабів. Не існує замовлення для споживачів, ви не можете гарантувати споживачеві B, який не вимагатиме його, отримує повідомлення перед споживачем A, який буде обробляти його та вимагати його, зазначені петлі є проблемою. Як ви говорите, "це, як правило, не правильний шлях", і я не можу придумати сценарій, коли це було б краще, ніж інші відповіді.
Кевін Стрейчер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.