查詢了好多大神的部落格,對rabbitmq的介紹,還是這位大神總結的比較好,作為收藏,轉自:http://blog.csdn.net/anzhsoft/article/details/19563091
1. 曆史
- RabbitMQ是一個由erlang開發的AMQP(Advanced Message Queue )的開源實作。
- 注意:rabbitMQ是運作在erlang上的,在使用rabbitmq是請先安裝erlang: http://blog.csdn.net/liangwanmian/article/details/78516824點選打開連結
- AMQP 的出現其實也是應了廣大人民群衆的需求,雖然在同步消息通訊的世界裡有很多公開标準(如 COBAR的 IIOP ,或者是 SOAP 等),但是在異步消息進行中卻不是這樣,隻有大企業有一些商業實作(如微軟的 MSMQ ,IBM 的 Websphere MQ 等),是以,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等聯合制定了 AMQP 的公開标準。
- RabbitMQ是由RabbitMQ Technologies Ltd開發并且提供商業支援的。該公司在2010年4月被SpringSource(VMWare的一個部門)收購。在2013年5月被并入Pivotal。其實VMWare,Pivotal和EMC本質上是一家的。不同的是VMWare是獨立上市子公司,而Pivotal是整合了EMC的某些資源,現在并沒有上市。
- RabbitMQ的官網是http://www.rabbitmq.com
2. 應用場景
言歸正傳。RabbitMQ,或者說AMQP解決了什麼問題,或者說它的應用場景是什麼?
對于一個大型的軟體系統來說,它會有很多的元件或者說子產品或者說子系統或者(subsystem or Component or submodule)。那麼這些子產品的如何通信?這和傳統的IPC有很大的差別。傳統的IPC很多都是在單一系統上的,子產品耦合性很大,不适合擴充(Scalability);如果使用socket那麼不同的子產品的确可以部署到不同的機器上,但是還是有很多問題需要解決。比如:
1)資訊的發送者和接收者如何維持這個連接配接,如果一方的連接配接中斷,這期間的資料如何方式丢失?
2)如何降低發送者和接收者的耦合度?
3)如何讓Priority高的接收者先接到資料?
4)如何做到load balance?有效均衡接收者的負載?
5)如何有效的将資料發送到相關的接收者?也就是說将接收者subscribe 不同的資料,如何做有效的filter。
6)如何做到可擴充,甚至将這個通信子產品發到cluster上?
7)如何保證接收者接收到了完整,正确的資料?
AMDQ協定解決了以上的問題,而RabbitMQ實作了AMQP。
3. rabbitmq的架構圖
- RabbitMQ Server: 也叫broker server,它不是運送食物的卡車,而是一種傳輸服務。原話是RabbitMQisn’t a food truck, it’s a delivery service. 他的角色就是維護一條從Producer到Consumer的路線,保證資料能夠按照指定的方式進行傳輸。但是這個保證也不是100%的保證,但是對于普通的應用來說這已經足夠了。當然對于商業系統來說,可以再做一層資料一緻性的guard,就可以徹底保證系統的一緻性了。
- Client A & B: 也叫Producer,資料的發送方。createmessages and publish (send) them to a broker server (RabbitMQ).一個Message有兩個部分:payload(有效載荷)和label(标簽)。payload顧名思義就是傳輸的資料。label是exchange的名字或者說是一個tag,它描述了payload,而且RabbitMQ也是通過這個label來決定把這個Message發給哪個Consumer。AMQP僅僅描述了label,而RabbitMQ決定了如何使用這個label的規則。
- Client 1,2,3:也叫Consumer,資料的接收方。Consumersattach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一個有名字的郵箱。當有Message到達某個郵箱後,RabbitMQ把它發送給它的某個訂閱者即Consumer。當然可能會把同一個Message發送給很多的Consumer。在這個Message中,隻有payload,label已經被删掉了。對于Consumer來說,它是不知道誰發送的這個資訊的。就是協定本身不支援。但是當然了如果Producer發送的payload包含了Producer的資訊就另當别論了。
- 對于一個資料從Producer到Consumer的正确傳遞,還有三個概念需要明确:exchanges, queues and bindings。
- Exchanges are where producers publish their messages.
- Queuesare where the messages end up and are received by consumers
- Bindings are how the messages get routed from the exchange to particular queues.
- 還有幾個概念是上述圖中沒有标明的,那就是Connection(連接配接),Channel(通道,頻道)。
- Connection: 就是一個TCP的連接配接。Producer和Consumer都是通過TCP連接配接到RabbitMQ Server的。以後我們可以看到,程式的起始處就是建立這個TCP連接配接。
- Channels: 虛拟連接配接。它建立在上述的TCP連接配接中。資料流動都是在Channel中進行的。也就是說,一般情況是程式起始建立TCP連接配接,第二步就是建立這個Channel。
- 那麼,為什麼使用Channel,而不是直接使用TCP連接配接?
- 對于OS來說,建立和關閉TCP連接配接是有代價的,頻繁的建立關閉TCP連接配接對于系統的性能有很大的影響,而且TCP的連接配接數也有限制,這也限制了系統處理高并發的能力。但是,在TCP連接配接中建立Channel是沒有上述代價的。對于Producer或者Consumer來說,可以并發的使用多個Channel進行Publish或者Receive。有實驗表明,1s的資料可以Publish10K的資料包。當然對于不同的硬體環境,不同的資料包大小這個資料肯定不一樣,但是我隻想說明,對于普通的Consumer或者Producer來說,這已經足夠了。如果不夠用,你考慮的應該是如何細化split你的設計。
4. 進一步的細節闡明
4.1 使用ack确認Message的正确傳遞
預設情況下,如果Message 已經被某個Consumer正确的接收到了,那麼該Message就會被從queue中移除。當然也可以讓同一個Message發送到很多的Consumer。
如果一個queue沒被任何的Consumer Subscribe(訂閱),那麼,如果這個queue有資料到達,那麼這個資料會被cache,不會被丢棄。當有Consumer時,這個資料會被立即發送到這個Consumer,這個資料被Consumer正确收到時,這個資料就被從queue中删除。
那麼什麼是正确收到呢?通過ack。每個Message都要被acknowledged(确認,ack)。我們可以顯示的在程式中去ack,也可以自動的ack。如果有資料沒有被ack,那麼:
RabbitMQ Server會把這個資訊發送到下一個Consumer。
如果這個app有bug,忘記了ack,那麼RabbitMQ Server不會再發送資料給它,因為Server認為這個Consumer處理能力有限。
而且ack的機制可以起到限流的作用(Benefitto throttling):在Consumer處理完成資料後發送ack,甚至在額外的延時後發送ack,将有效的balance Consumer的load。
當然對于實際的例子,比如我們可能會對某些資料進行merge,比如merge 4s内的資料,然後sleep 4s後再擷取資料。特别是在監聽系統的state,我們不希望所有的state實時的傳遞上去,而是希望有一定的延時。這樣可以減少某些IO,而且終端使用者也不會感覺到。
4.2 Reject a message
有兩種方式,第一種的Reject可以讓RabbitMQ Server将該Message 發送到下一個Consumer。第二種是從queue中立即删除該Message。
4.3 Creating a queue
Consumer和Procuder都可以通過 queue.declare 建立queue。對于某個Channel來說,Consumer不能declare一個queue,卻訂閱其他的queue。當然也可以建立私有的queue。這樣隻有app本身才可以使用這個queue。queue也可以自動删除,被标為auto-delete的queue在最後一個Consumer unsubscribe後就會被自動删除。那麼如果是建立一個已經存在的queue呢?那麼不會有任何的影響。需要注意的是沒有任何的影響,也就是說第二次建立如果參數和第一次不一樣,那麼該操作雖然成功,但是queue的屬性并不會被修改。
那麼誰應該負責建立這個queue呢?是Consumer,還是Producer?
如果queue不存在,當然Consumer不會得到任何的Message。但是如果queue不存在,那麼Producer Publish的Message會被丢棄。是以,還是為了資料不丢失,Consumer和Producer都try to create the queue!反正不管怎麼樣,這個接口都不會出問題。
queue對load balance的處理是完美的。對于多個Consumer來說,RabbitMQ 使用循環的方式(round-robin)的方式均衡的發送給不同的Consumer。
4.4 Exchanges
從架構圖可以看出,Procuder Publish的Message進入了Exchange。接着通過“routing keys”, RabbitMQ會找到應該把這個Message放到哪個queue裡。queue也是通過這個routing keys來做的綁定。
有三種類型的Exchanges:direct, fanout,topic。 每個實作了不同的路由算法(routing algorithm)。
· Direct exchange: 如果 routing key 比對, 那麼Message就會被傳遞到相應的queue中。其實在queue建立時,它會自動的以queue的名字作為routing key來綁定那個exchange。
· Fanout exchange: 會向響應的queue廣播。
· Topic exchange: 對key進行模式比對,比如ab*可以傳遞到所有ab*的queue。
4.5 Virtual hosts
每個virtual host本質上都是一個RabbitMQ Server,擁有它自己的queue,exchagne,和bings rule等等。這保證了你可以在多個不同的application中使用RabbitMQ。
接下來我會使用Python來說明RabbitMQ的使用方法。