OpenStack訊息佇列AMQP技術具體實現 [分析基於icehouse]
本文系技術總結,供將來需要時翻開看看, 如有錯誤, 歡迎交流
第一部分:關鍵技術
先發下感慨, 社群的code真是變化太快, code結構發生了很大的重構增強, 關於訊息佇列, openstack.common.rpc慢慢的都會轉移到oslo.messaging上,以我2014年3月的code為例, 僅有heat, neutron, ceilometer沒有轉移。無論架構和部分實現如何變化,技術原理還是原來的原理。
OpenStack中的訊息佇列技術使用的AMQP(Advanced Message Queue Protocol)非同步訊息處理機制。AMQP使用的是釋出/訂閱的模式, 它的好處是
1) 實現訊息釋出方(伺服器端)和訊息處理方(客戶端)的解耦和。
2) 訊息釋出方和訊息處理方可以是非同步的
3) 可以做到負載均衡。這個就涉及到訊息佇列中介軟體的實現問題, 當多個server端在執行, 請求就會被它們平衡到各個server端
OpenStack支援RabiitMQ或者Qpid,也可以使用Zero MQ等等訊息中介軟體,一般通過指定rpc_backend
rpc_backend = nova.openstack.common.rpc.impl_qpid #impl_qpid為qpid, impl_kommu為Rabbitmq,impl_zmq為Zero MQ, 當發現沒有nova.openstack.common.rpc路徑時不要驚訝, 主要是為了相容havana與之前版本, icehouse的程式碼中對此路徑進行了處理。
本文以Qpid為例總結OpenStack中的訊息佇列技術,Qpid除了基本訊息佇列功能, 還有很多增強功能,實現高可用性, 如HA, ssl連線等.
使用訊息佇列broker包含invoker和worker, invoker向訊息佇列中發訊息, worker處理訊息。在nova中api會通過rpcapi發出訊息到訊息佇列,這是invoker端的工作, 而compute會收到訊息, 通過它的Manager(也可以說為endpoint)處理訊息[worker端], 如下圖所示, 左邊為invoker, 右側為worker, invoker中發出訊息的方式有兩種, 一種是請求/響應模式 rpc.call; 另一種是廣播模式rpc.cast
圖1 以nova/compute目錄下code為例, 講述API與compute之間的訊息傳送過程
圖2 oslo.messaging._drivers.impl_qpid.py中類結構
TopicPublisher: Topic訊息釋出, 也就是釋出訊息到訊息佇列, 是invoker工作內容, 無論是rpc.call還是rpc.cast這個都是有的
TopicConsumer:Topic訊息處理, 從訊息佇列接收訊息並處理,是worker工作內容,無論是rpc.call還是rpc.cast這個都是有的
DirectPublisher:這個是在rpc.call模式時, 當訊息被TopicConsumer處理後, 為了給invoker以響應, 必須通過DirectPublisher釋出direct訊息到訊息佇列
DirectConsumer:僅當rpc.call呼叫時才會出現, 負責在invoker端接收訊息佇列中worker端發來的響應資訊, 完成rpc.call整個流程
FanoutPublisher:這個就是所謂的fanout模式了, 一個訊息被廣播, 多個worker端都要接收此訊息並處理, FanoutPublisher為invoker端
FanoutConsumer:這個就是fanout模式的處理端worker端了
NotifyPublisher:負責發出notification訊息, notification listener將會處理這些訊息
下面幾張圖摘自http://docs.openstack.org/developer/nova/devref/rpc.html,它以api作為invoker, compute作為worker, 講述了TopicPublisher、TopicConsumer、DirectPublisher、DirectConsumer的關係。
圖3 以RabbitMQ為例 闡述Publisher/Consumer關係
解釋一下,Exchange: 訊息交換機, 指定訊息按照什麼規則, 路由到哪個queue;Queue:訊息佇列承載者
圖3中有兩個Exchange,針對一個訊息佇列節點, 針對訊息的type(topic或者direct, fault),每個type在一個訊息中介軟體節點上,只能有一個Exchange。
圖4為rpc.call流程圖,Invoker 端Topic Publisher釋出訊息如key為“topic.host”, 因為是rpc.call, 所以同時啟動Direct Consumer偵聽msg_id訊息,訊息發出後, Exchange就會根據訊息, 路由相應的Queue, 監聽此Queue的Worker端Topic Consumer就會收到訊息, 並處理, 同時會開始給Invoker給與響應, 告知訊息被處理,對應圖4中的Direct Publisher釋出訊息msg_id到訊息佇列, Invoker端的Direct Consumer接收。
圖5為rpc.cast流程圖,與rpc.call相比, 只是沒有Direct Publisher和Direct Consumer來處理返回, 其他一樣。
圖4 rpc.call 流程
圖5 rpc.cast流程
第二部分 OpenStack中rpc部分程式碼的實現
本部分的實現基本都使用了oslo/messaging, 在另一文章oslo/messaging 說明