RabbitMQ / AMQP: hàng đợi đơn, nhiều người tiêu dùng cho cùng một tin nhắn?


144

Tôi mới bắt đầu sử dụng RabbitMQ và AMQP nói chung.

  • Tôi có một hàng tin nhắn
  • Tôi có nhiều người tiêu dùng, tôi muốn làm những việc khác nhau với cùng một thông điệp .

Hầu hết các tài liệu của RabbitMQ dường như tập trung vào vòng tròn, tức là trong đó một tin nhắn được sử dụng bởi một người tiêu dùng, với tải được lan truyền giữa mỗi người tiêu dùng. Đây thực sự là hành vi tôi chứng kiến.

Một ví dụ: nhà sản xuất có một hàng đợi và gửi tin nhắn cứ sau 2 giây:

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) 


})

Và đây là một người tiêu dùng:

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

Nếu tôi bắt đầu người tiêu dùng hai lần, tôi có thể thấy rằng mỗi người tiêu dùng đang tiêu thụ các thông điệp thay thế trong hành vi quay vòng. Ví dụ: tôi sẽ thấy các tin nhắn 1, 3, 5 trong một thiết bị đầu cuối, 2, 4, 6 trong thiết bị đầu cuối khác .

Câu hỏi của tôi là:

  • Tôi có thể để mỗi người tiêu dùng nhận được cùng một tin nhắn không? Tức là cả hai người tiêu dùng nhận được tin nhắn 1, 2, 3, 4, 5, 6? Cái này được gọi là gì trong AMQP / RabbitMQ nói? Làm thế nào nó được cấu hình bình thường?

  • Điều này thường được thực hiện? Tôi có nên chỉ có lộ trình trao đổi tin nhắn thành hai hàng đợi riêng biệt, với một người tiêu dùng, thay vào đó?


5
Tôi không phải là chuyên gia RabbitMQ. Tuy nhiên, những gì bạn có bây giờ được gọi là hàng đợi nhưng những gì bạn muốn là chủ đề, hãy xem hướng dẫn này: rabbitmq.com/tutorials/tutorial-five-python.html , nhiều hơn về hàng đợi so với chủ đề: msdn.microsoft.com/en-us /
l Library / windowsazure / hh367516.aspx

1
Tôi tin rằng anh ấy muốn fanout thực sự mặc dù các chủ đề sẽ hoạt động tốt và sẽ kiểm soát nhiều hơn sau này.
robthewolf

Cảm ơn @UrbanEsc. Các chủ đề dường như giải quyết vấn đề bằng cách có một tin nhắn đánh vào nhiều hàng đợi, và do đó được tiêu thụ bởi mỗi người tiêu dùng hàng đợi. Điều này cho tôi biết thêm về kịch bản nhiều hàng đợi / người tiêu dùng cho trường hợp cụ thể của tôi.
mikemaccana

1
Đối với năm 2018 (và thậm chí cho năm 2016 trở về trước), câu trả lời là sử dụng một cái gì đó như Kafka, IMO.
WattsInABox

Câu trả lời:


115

Tôi có thể để mỗi người tiêu dùng nhận được cùng một tin nhắn không? Tức là cả hai người tiêu dùng nhận được tin nhắn 1, 2, 3, 4, 5, 6? Cái này được gọi là gì trong AMQP / RabbitMQ nói? Làm thế nào nó được cấu hình bình thường?

Không, không phải nếu người tiêu dùng ở trên cùng một hàng đợi. Từ hướng dẫn về khái niệm AMQP của RabbitMQ :

điều quan trọng là phải hiểu rằng, trong AMQP 0-9-1, các thông điệp được tải cân bằng giữa người tiêu dùng.

Điều này dường như ngụ ý rằng hành vi quay vòng trong hàng đợi là nhất định và không thể định cấu hình. Tức là, hàng đợi riêng biệt được yêu cầu để có cùng một ID tin nhắn được xử lý bởi nhiều người tiêu dùng.

Điều này thường được thực hiện? Tôi có nên chỉ có lộ trình trao đổi tin nhắn thành hai hàng đợi riêng biệt, với một người tiêu dùng, thay vào đó?

Không, không, hàng đợi đơn / nhiều người tiêu dùng với mỗi người tiêu dùng xử lý cùng một ID tin nhắn là không thể. Có lộ trình trao đổi tin nhắn vào hai hàng đợi riêng biệt thực sự tốt hơn.

Vì tôi không yêu cầu định tuyến quá phức tạp, một trao đổi fanout sẽ xử lý việc này độc đáo. Tôi đã không tập trung quá nhiều vào Trao đổi trước đó vì nút-amqp có khái niệm 'trao đổi mặc định' cho phép bạn xuất bản tin nhắn đến một kết nối trực tiếp, tuy nhiên hầu hết các tin nhắn AMQP được xuất bản tới một trao đổi cụ thể.

Đây là trao đổi fanout của tôi, cả gửi và nhận:

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
quạt ra rõ ràng là những gì bạn muốn. Nó sẽ không giúp bạn ở đây, nhưng tôi nghĩ tôi đã đề cập đến hành vi quay vòng trong hàng đợi là có thể cấu hình được. int prefetchCount = 1; channel.basicQos(prefetchCount); Điều này sẽ cho phép mỗi người tiêu dùng nhận được một tin nhắn ngay sau khi kết thúc với tin nhắn trước đó. Thay vì nhận tin nhắn xen kẽ. Một lần nữa không giải quyết vấn đề của bạn, nhưng có thể hữu ích cho mọi người biết. ví dụ ở đây http://www.rabbitmq.com/tutorials/tutorial-two-java.html theo Công văn
Ommit

3
Để làm rõ: 'trao đổi mặc định' không phải là nút cụ thể-amqp. Đó là khái niệm AMQP chung với các quy tắc sau: khi bất kỳ thông báo nào được xuất bản để trao đổi mặc định, khóa định tuyến (với thông báo đó được xuất bản) được coi là tên hàng đợi của nhà môi giới AMQP. Vì vậy, có vẻ như bạn có thể xuất bản để xếp hàng trực tiếp. Nhưng bạn thì không. Người môi giới chỉ cần liên kết mỗi hàng đợi để trao đổi mặc định với khóa định tuyến bằng với tên hàng đợi.
Ruslan Stelmachenko

2
Có sự thay thế nào cho các chủ đề Apache activemq jms trong rabbitmq không có hàng đợi nào liên quan mà thay vào đó là đa hướng?
pantonis

Nếu cùng một người dùng đăng nhập từ nhiều thiết bị thì tin nhắn chỉ nhận được một thiết bị. Làm thế nào có thể giải quyết nó hoặc có ý tưởng nào không?
Rafiq

@Rafiq bạn nên đặt câu hỏi cho việc này.
mikemaccana

27

Chỉ cần đọc hướng dẫn rabbitmq . Bạn xuất bản tin nhắn để trao đổi, không phải xếp hàng; sau đó nó được chuyển đến hàng đợi thích hợp. Trong trường hợp của bạn, bạn nên liên kết hàng đợi riêng cho từng người tiêu dùng. Bằng cách đó, họ có thể tiêu thụ tin nhắn hoàn toàn độc lập.


25

Một vài câu trả lời cuối cùng gần như đúng - Tôi có hàng tấn ứng dụng tạo ra các tin nhắn cần kết thúc với những người tiêu dùng khác nhau nên quá trình này rất đơn giản.

Nếu bạn muốn nhiều người tiêu dùng đến cùng một tin nhắn, hãy làm thủ tục sau.

Tạo nhiều hàng đợi, một cho mỗi ứng dụng nhận tin nhắn, trong mỗi thuộc tính hàng đợi, "liên kết" một thẻ định tuyến với trao đổi amq.direct. Thay đổi ứng dụng xuất bản của bạn để gửi tới amq.direct và sử dụng thẻ định tuyến (không phải hàng đợi). AMQP sau đó sẽ sao chép tin nhắn vào mỗi hàng đợi với cùng một ràng buộc. Hoạt động như một bùa mê :)

Ví dụ: Hãy nói rằng tôi có một chuỗi JSON mà tôi tạo, tôi xuất bản nó lên trao đổi "amq.direct" bằng cách sử dụng thẻ định tuyến "new-sales-order", tôi có một hàng đợi cho ứng dụng order_printer của tôi in lệnh, tôi có một xếp hàng cho hệ thống thanh toán của tôi sẽ gửi một bản sao của đơn đặt hàng và gửi hóa đơn cho khách hàng và tôi có một hệ thống lưu trữ web nơi tôi lưu trữ các đơn đặt hàng vì lý do lịch sử / tuân thủ và tôi có giao diện web của khách hàng nơi các đơn hàng được theo dõi khi có thông tin khác một đơn đặt hàng.

Vì vậy, hàng đợi của tôi là: order_printer, order_billing, order_archive và order_tracking Tất cả đều có thẻ ràng buộc "new-sales-order" ràng buộc với chúng, cả 4 sẽ nhận được dữ liệu JSON.

Đây là một cách lý tưởng để gửi dữ liệu mà không cần ứng dụng xuất bản biết hoặc quan tâm đến các ứng dụng nhận.


7

Có, mỗi người tiêu dùng có thể nhận được cùng một thông điệp. hãy xem http://www.rabbitmq.com/tutorials/tutorial-three-python.html http://www.rabbitmq.com/tutorials/tutorial-four-python.html http: //www.rabbitmq. com / hướng dẫn / hướng dẫn-five-python.html

cho các cách khác nhau để định tuyến tin nhắn. Tôi biết chúng dành cho python và java nhưng thật tốt khi hiểu các nguyên tắc, quyết định những gì bạn đang làm và sau đó tìm cách làm điều đó trong JS. Có vẻ như bạn muốn thực hiện một fanout đơn giản ( hướng dẫn 3 ), sẽ gửi tin nhắn đến tất cả các hàng đợi được kết nối với trao đổi.

Sự khác biệt với những gì bạn đang làm và những gì bạn muốn làm về cơ bản là bạn sẽ thiết lập và trao đổi hoặc loại fanout. Fanout excahnges gửi tất cả tin nhắn đến tất cả các hàng đợi được kết nối. Mỗi hàng đợi sẽ có một người tiêu dùng sẽ có quyền truy cập vào tất cả các tin nhắn riêng biệt.

Có, điều này thường được thực hiện, nó là một trong những tính năng của AMPQ.


câu trả lời tuyệt vời, ngoại trừ bởi 'điều này thường được thực hiện?' Tôi đã đề cập đến việc "mỗi người tiêu dùng nhận được cùng một thông điệp" - điều này thường không được thực hiện (người tiêu dùng trên cùng một hàng đợi luôn luôn quay vòng). Có lẽ lỗi của tôi là không đủ rõ ràng.
mikemaccana

Trên thực tế tôi sẽ mạo hiểm để nói rằng nó phụ thuộc vào những gì bạn muốn sử dụng nó cho. Bạn có hai lựa chọn cơ bản pub / sub hoặc hàng đợi công việc. Thiết lập ban đầu của bạn là một hàng đợi công việc nhưng những gì bạn muốn là một quán rượu / phụ. Họ chỉ ra rằng việc sử dụng phổ biến ở đây hoàn toàn phụ thuộc vào những gì bạn muốn làm.
robthewolf

Chắc chắn nhưng trong hàng đợi công việc, cùng một thông điệp (ví dụ: cùng một ID tin nhắn) không được xử lý bởi những người tiêu dùng khác nhau - đó là mặc nhiên làm tròn. Một lần nữa, đây có lẽ là lỗi của tôi vì không đủ rõ ràng.
mikemaccana

chúng ta dường như đang nói chuyện với mục đích chéo ở đây.
robthewolf

Xin lỗi về sự nhầm lẫn. Nếu có một số cách để có một hàng đợi công việc trong đó người tiêu dùng trên cùng một hàng đợi xử lý cùng một ID tin nhắn, vui lòng chỉ cho tôi một tham chiếu. Nếu không, tôi sẽ tiếp tục tin những gì tôi đã đọc ở nơi khác.
mikemaccana


3

RabbitMQ / AMQP: hàng đợi đơn, nhiều người tiêu dùng cho cùng một tin nhắn và làm mới trang.

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

Để có được hành vi bạn muốn, chỉ cần mỗi người tiêu dùng tiêu thụ từ hàng đợi của chính họ. Bạn sẽ phải sử dụng loại trao đổi không trực tiếp (chủ đề, tiêu đề, fanout) để nhận được thông báo tới tất cả các hàng đợi cùng một lúc.


1

Theo tôi đánh giá trường hợp của bạn là:

  • Tôi có một hàng tin nhắn (nguồn của bạn để nhận tin nhắn, hãy đặt tên cho nó là q111)

  • Tôi có nhiều người tiêu dùng, tôi muốn làm những việc khác nhau với cùng một thông điệp.

Vấn đề của bạn ở đây là trong khi 3 tin nhắn được nhận bởi hàng đợi này, tin nhắn 1 được tiêu thụ bởi người tiêu dùng A, người tiêu dùng khác B và C tiêu thụ tin nhắn 2 và 3. Khi bạn đang cần một thiết lập trong đó rabbitmq chuyển trên cùng một bản sao của đồng thời cả ba tin nhắn (1,2,3) cho cả ba người tiêu dùng được kết nối (A, B, C).

Trong khi nhiều cấu hình có thể được thực hiện để đạt được điều này, một cách đơn giản là sử dụng khái niệm hai bước sau:

  • Sử dụng một cái xẻng thỏ động để lấy các tin nhắn từ hàng đợi mong muốn (q111) và xuất bản lên một trao đổi fanout (trao đổi được tạo riêng và dành riêng cho mục đích này).
  • Bây giờ hãy định cấu hình lại người tiêu dùng A, B & C của bạn (những người đang nghe hàng đợi (q111)) để nghe trực tiếp trao đổi Fanout này bằng cách sử dụng hàng đợi độc quyền & ẩn danh cho mỗi người tiêu dùng.

Lưu ý: Trong khi sử dụng khái niệm này, không tiêu thụ trực tiếp từ hàng đợi nguồn (q111), vì các tin nhắn đã được sử dụng sẽ không được chuyển sang trao đổi Fanout của bạn.

Nếu bạn nghĩ rằng điều này không đáp ứng yêu cầu chính xác của bạn ... vui lòng gửi đề xuất của bạn :-)



0

Tôi nghĩ bạn nên kiểm tra việc gửi tin nhắn của mình bằng bộ trao đổi quạt . Bằng cách đó, bạn sẽ nhận được cùng một thông điệp cho người tiêu dùng khác nhau, trong bảng RabbitMQ đang tạo ra hàng đợi khác nhau cho mỗi người tiêu dùng / người đăng ký mới này.

Đây là liên kết để xem ví dụ hướng dẫn trong javascript https://www.rabbitmq.com/tutorials/tutorial-one-javascript.html


-1

Có một lựa chọn thú vị trong kịch bản này tôi chưa tìm thấy trong câu trả lời ở đây.

Bạn có thể Nack tin nhắn với tính năng "yêu cầu" trong một người tiêu dùng để xử lý chúng ở người khác. Nói chung nó không phải là một cách đúng đắn, nhưng có lẽ nó sẽ đủ tốt cho một ai đó.

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

Và hãy cẩn thận với các vòng lặp (khi tất cả các thông báo nack + tin nhắn yêu cầu)!


1
Tôi rất khuyên bạn nên chống lại điều này, vì nó không mở rộng bằng bất kỳ phương tiện nào. Không có đơn đặt hàng cho người tiêu dùng, bạn không thể đảm bảo người tiêu dùng B sẽ không yêu cầu nó, nhận được tin nhắn trước người tiêu dùng A sẽ xử lý và yêu cầu nó, các vòng lặp được đề cập là một vấn đề. Như bạn nói "điều này nói chung là không đúng cách" và tôi không thể nghĩ ra một kịch bản mà điều này sẽ tốt hơn các câu trả lời khác.
Kevin Strerich
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.