http://www.rabbitmq.com/
最近使用 rabbitmq 來架構一個 High available 的 message framework, 不過使用了一陣子之後發現其實它在 HA 的部份仍然有不少的問題, 分享出來給大家參考.
Rabbitmq 是一個 broker 的角色, 整個傳遞訊息的詳細流程是
clientA -> broker -> queue -> clientB
所以如果要確保 clientA 送出去的訊息 clientB 一定會收到, 那 broker/queue 都必須要有 redundant 的機制, 否則任一個環節出問題時, 都會造成訊息無法傳送到對方手裡, 先看 broker 的部份
http://www.rabbitmq.com/clustering.html
文件中寫的還滿清楚的, 有幾個要注意的點
1. /var/lib/rabbitmq/.erlang.cookie 要同步
2. 加入 cluster 的方式有兩種, 一種是 disk, 另一種是 ram
除此之外, 魔鬼就藏在細節中
第一個問題是 RabbitMQ clustering does not tolerate network partitions well
前陣子的文檔並沒有說明這點, 我也是在實驗之後才發現這件事, 用下面這張圖來解釋, 原本的 B1 ~ B5 組成 cluster, 但可能因為 B1 和 B2 所在的 Switch 壞掉了, 所以把 B1 ~ B5 切成了上下兩個 cluster. 在這種狀況下, 雙方都可以正常運作, 但當我們把壞掉的 Switch 換掉之後, 卻發現上下兩個 cluster 卻不會自動回復成一個 cluster. 你再也無法從 cluster A 內的點送訊息到 cluster B 內的點.
這篇是討論一樣的問題
http://rabbitmq.1065348.n5.nabble.com/Cluster-recovery-due-to-network-outages-td14359.html
在文檔中雖然有提到 cluster 不適合 WAN, 所以建議使用 shovel/federation 但就實際面來看, 即使是 LAN 也還是會遇到 network partition 的事件, 當遇到這種狀況時, 你必須要重啟其中任何一個 broker, 讓它重新去掃所有的 cluster 成員, 這時候上下兩個 cluster 就會再合併起來了.
第二個問題是 broker cluster 對於 fail recover 的程序不是很方便
There are some important caveats:
- All disk nodes must be running for certain operations, most notably leaving a cluster, to succeed.
- At least one disk node should be running at all times.
- When all nodes in a cluster have been shut down, restarting any node will suspend for up to 30 seconds and then fail if the last disk node that was shut down has not been restarted yet. Since the nodes do not know what happened to that last node, they have to assume that it holds a more up-to-date version of the broker state. Hence, in order to preserve data integrity, they cannot resume operation until that node is restarted.
上面的說明的情況就是當你的 cluster 建立起來之後, 如果你要全面關機維修時, 你一定要記得最後關的是那一台, 而那一台在關機維修之後, 必須要先開機, 你無法以任意的順序開機. 其實這種狀況一般來說是不太容易遇到的, 因為"全面"關機不是一個機房該做的事, 應該是依序維修, 一台維修完就立即開機, 再繼續維修下一台. 但考慮到一個機房遇到最糟的事情就是發生了斷電, 即使全部的機器依序自動關機, 那請問下次開機時, 你要如何知道那一台是最後關機的?!
另外我也針對某個特殊狀況進行模擬, 如果最後有三台機器在同一秒內關機, 那下次開機時, 誰要先開啟? 答案是誰先開啟都沒用, 這三台必須要同步開機後, 同步把 rabbitmq-server 重啟, 才能夠把 cluster 重建回來. 相當的麻煩, 我在下面這個連結內也看到同樣的討論, 目前是還沒有解答的.
http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2012-June/020594.html
第三個問題是 Upgrade cluster 必須要將全部的服務停止
All nodes in a cluster must be running the same versions of Erlang and RabbitMQ, although they may have different plugins installed. Therefore it is necessary to stop all nodes in the cluster, then start all nodes when performing an upgrade. While not strictly necessary, it is a good idea to decide ahead of time which disc node will be the upgrader, stop that node last, and start it first
升級竟然需要把 cluster 全部停止, 而且最後停止服務的點在升級後, 必須要先啟動, 我想升級需要把 cluster 全部停止這件事, 應該是一件滿嚴重的事情
討論完了 broker 的部份, 再來看一下 queue 的部份, 為什麼 queue 也需要 HA 呢?
在 http://www.rabbitmq.com/clustering.html 內有這樣一句話
An exception to this are message queues, which by default reside on the node that created them.
這表示 queue 只存在在某一個特定的 broker node 上, 如果當這個 broker 壞掉時, 你這個 queue 也就跟著消失, 無法透過其它的 broker 來存取, 下面這個網頁第一段話也寫的很清楚
http://www.rabbitmq.com/ha.html
If your RabbitMQ broker consists of a single node, then a failure of that node will cause downtime, temporary unavailability of service, and potentially loss of messages (especially non-persistent messages held by non-durable queues)
所以 rabbitmq 提供了 mirrored queue 這個機制, 然而機制只把這個故事講完了一半, 網頁中還寫到
Clients that were consuming from the mirrored-queue and support our Consumer Cancellation Notifications extension will receive a notification that their subscription to the mirrored-queue has been abruptly cancelled. At this point they should re-consume from the queue, which will pick up the new master
也就是 client 端還必須要自行 handle 一個 cancel event, 然後要自動的連結到新的 queue, 才有辦法拿到 message, 就我目前 survey 的狀況來看, 目前還沒有 client 端的程式 (kombu/pika/pyamqp), 有處理好這個問題. 如果這個狀況有變化的話, 還麻煩也通知我一聲.
有關 rabbitmq HA 的問題, 在官網上他們也寫了一篇目前 rabbitmq 還缺少的部份, 我覺得還滿有誠意的, 至少把問題都列出來, 除了表示他們已注意到這些問題, 未來可能會修掉之外, 使用者也可以先自行了解如果使用 rabbitmq 會有什麼副作用, 可以先打預防針
http://www.rabbitmq.com/blog/2011/10/25/high-availability-in-rabbitmq-solving-part-of-the-puzzle/
因為 Openstack 也很仰賴 rabbitmq, 所以類似的討論串我也 openstack 的論壇上也有看到
http://wiki.openstack.org/RabbitmqHA
http://www.mail-archive.com/openstack@lists.launchpad.net/msg07495.html
http://www.mail-archive.com/openstack@lists.launchpad.net/msg07502.html
http://www.mail-archive.com/openstack@lists.launchpad.net/msg07595.html
有些是 Celery 的討論區看到的
http://comments.gmane.org/gmane.comp.python.amqp.celery.user/1291
https://groups.google.com/forum/#!searchin/celery-users/cluster/celery-users/8EqwvV4IZ2g/MGmSv-P8Q8kJ
其它相關討論
http://www.vnext.org/mirrored-queues-and-preserving-messages
如果有朋友對 distributed message queue 也有興趣的話, 也歡迎一起討論, 台灣對這塊的東西討論實在不太多.