閱讀482 返回首頁    go 阿裏雲 go 技術社區[雲棲]


消息隊列的exclusive consumer功能是如何保證消息有序和防止腦裂的

一般來說,消息隊列都會保證queue當中的消息的順序。然而如果有多個consumer同時消費同一個queue,那麼這時就不能保證的消息的順序性。

有時候,消息的順序是非常重要的,為了能順序的消費消息,我們隻能啟動一個consumer來消費這個queue。但是這樣做的問題就是,如果這個consumer宕調了話,消息就不能得到處理了,consumer的可用性不能得到保證。

那麼如何提高consumer的可用性那,通常的做法是啟動多個consumer,讓其中一個consumer成為master,其他的為slave,成為master的consumer才去消費queue中的消息(通常的做法是使用zookeeper進行選主)。

但是這仍然沒有解決全部問題。假設master在要消費一條消息之前,發生了一次很長的gc(假設我們是一個java的程序,當然也有其他的導致這個問題的場景),zookeeper認為master掛了,重新選主,一個slave被提升為master,並且開始消費這個queue的消息,這時原來的master從gc中恢複,在一定的時間範圍內,原master還沒有收到zookeeper通知它已經不是主了,這時它會繼續消費queue中的消息。也就是說,在這段時刻,我們有2個認為自己是master的consumer。這種現象是分布係統中所說的腦裂。Zookeeper可以用來選主,zookeeper會保證隻選出一個主,但是zookeeper並不能保證在某一時間係統中隻有一個主,也就是說用了zookeeper並不能保證腦裂不會發生。Zookeeper不是用來防止腦裂的。

那麼如何解決這問題那?很多mq都有exclusive consumer的概念,我們可以用它來解決這個問題。首先我們來說一下,什麼是exclusive consumer。

拿activemq來說,我們在創建queue時,可以指定這個queue是exclusive,比如

queue = new ActiveMQQueue("TEST.QUEUE?consumer.exclusive=true");

如果一個queue設置為exclusive,broker會調選一個consumer,並且將所有的消息都發給這個consumer。如果這個consumer掛了,broker會自動挑選另外一個consumer。

對於rabbitmq來說,有2個exclusive參數可以設置:第一個是declare一個queue時可以指定exclusive=ture(也即queue_declare方法),那麼這個queue隻能被當前連接訪問,當連接斷開時queue會被刪除。也可以這麼理解exclusive queue是私有queue,non-exclusive queue是共享queue。第二個是consumer一個queue時可以指定exclusive=ture(也即basic_consume),那麼這個queue隻能被這個consumer訪問。

腦裂問題我們是不能避免的,可以避免的時在發生腦裂時,2個master能同時去消費queue中的數據。所以我們應該用zookeeper來選主,讓主去消費隊列,並且隊列要設置成exclusive。這樣我們就保證隊列中的消息是被順序消費的。

最後更新:2017-04-13 14:00:31

  上一篇:go Java培訓都培訓什麼內容
  下一篇:go 創業公司如何做數據分析(三)用戶行為數據采集係統