RabbitMQ是一個很受歡迎的訊息中介軟體,通過它可以很方便地實現異構子系統之間的通訊,還可以將不同子系統之間進行解耦。它用erlang開發,基本上是實現了AMQP 1.0標準的訊息協議。
瞭解RabbitMQ首先要瞭解以下一些概念:Message,Producer、Exchange、Queue、Consumer
Message是一些簡單的字串, Producer(Publisher)是實際發布訊息的角色
Queue,是實際存放訊息的地方。顧名思義,訊息從Queue一端放入,另一段由Consumer(Subscriber)取出,如果有多Consumer,每個consumer各自取出不同的訊息進行處理。
當Producer發布訊息的時候,首先是發布到Exchange,然後RabbitMQ根據Exchange的類型和邏輯來判斷應該發送到哪個Queue中。所以Queue必須bind到特定的Exchange上才能擷取到訊息,綁定的時候可以提供一個routing_key來判斷選擇什麼訊息,Publisher在發出資訊的時候就可以指定不同的routing_key來選擇如何分發訊息。
當使用最基本的隊列模式的時候,可以不指定exchange,這時候會使用預設exchange來進行訊息的發送。
Exchange和Queue都有自己的名字,多個Publisher發行就緒到同一個Exchange,多個Consumer也可以訂閱到同一個Queue。
RabbitMQ支援的Exchange方式有:
direct 直接投遞
fanout 廣播投遞
topic 可以按照一個topic名字的模式進行匹配routing_key,例如topic.*可以匹配topic.paragraph和topic.paragraph.word,而topic.#
rpc Producer可以等待Consumer處理訊息結束並把結果返回給Producer
Ruby下可以使用基於EventMachine的非同步用戶端amqp,或者是同步模式的bunny和carrot。
用bunny,以topic訂閱為例:
publisher部分:
代碼如下 |
複製代碼 |
#!/usr/bin/env ruby # encoding: utf-8 require "bunny" conn = Bunny.new conn.start ch = conn.create_channel x = ch.topic("topic_logs") severity = ARGV.shift || "anonymous.info" msg = ARGV.empty? ? "Hello World!" : ARGV.join(" ") x.publish(msg, :routing_key => severity) puts " [x] Sent #{severity}:#{msg}" conn.close
|
consumer部分
代碼如下 |
複製代碼 |
#!/usr/bin/env ruby # encoding: utf-8 require "bunny" if ARGV.empty? abort "Usage: #{$0} [binding key]" end conn = Bunny.new conn.start ch = conn.create_channel x = ch.topic("topic_logs") q = ch.queue("", :exclusive => true) ARGV.each do |severity| q.bind(x, :routing_key => severity) end puts " [*] Waiting for logs. To exit press CTRL+C" begin q.subscribe(:block => true) do |delivery_info, properties, body| puts " [x] #{delivery_info.routing_key}:#{body}" end rescue Interrupt => _ ch.close conn.close end
|
RabbitMQ叢集和High Scalability
由於RabbitMQ實現的是AMQP,它非常強調一致性,而AMQP本身就是一種適用於金融行業的訊息協議。根據CAP原理,一致性、高可用性和分區容忍性只能選兩項,RabbitMQ提供了三種配置選項:
ignore:預設配置,發生網路磁碟分割時不作處理,當認為網路是可靠時選用該配置
autoheal:各分區協商後重啟用戶端串連最少的分區節點,恢複叢集(CAP 中保證 AP,有狀態丟失)
pause_minority:分區發生後判斷自己所在分區內節點是否超過叢集總節點數一半,如果沒有超過則暫停這些節點(保證 CP,總節點數為奇數個)
由於使用Erlang開發,RabbitMQ可以非常方便的搭建叢集,可以隨時加入節點,這些節點之間是互相等同的,可以在用戶端隨機播放節點,或者使用諸如haproxy等進行負載平衡反向 Proxy,以達到水平擴充的目的。