Kafka總結系列(三)

繼續上一篇。

The consumer:

      kafka的消費者通過向broker發送“fetch”請求獲取他要消費的partition的信息。消費者在每個請求中標記他已經消費到的offset值,broker將以該offset作爲起始位置的a chunk of log即一批消息返回給consumer。可見消費者自己維護消費狀態,broker是無狀態的,如有需要可重複消費。

Push vs Pull

      在kafka的設計中,producer將消息push給broker,consumer從broker那裏pull消息進行消費。基於push的模式,很難適應不同特點的consumer,push時,消息的發送速率完全由broker掌控。該設計的初衷是消費者以最大的速率進行消費,但是每個consumer的硬件性能、消費能力不同,一旦消費速度遠遠落後於生產速度,就會出現拒絕服務等異常。pull模式消費者可以依據其自身能力進行消費,每次消費完後他都會pull一批消息(可以設置size),沒有不必要的等待時間。
      pull模式的缺點是:當broker中沒有未被消費的數據時,即offset已經是最新值了,consumer會一直循環,進入忙等待的狀態。爲了避免這種情況,允許consumer阻塞在“long poll”的等待中,直到數據到達,(也可以設置爲一直等待until a given number of bytes)。consumer的配置文件中可以設置:fetch.min.bytes,表示consumer發起一次fetch請求,broker應該返回給他的最小字節數,如果broker端沒有這麼多消息,則請求被阻塞,一直等待,累積夠這麼多數據才返回。同時爲了避免無止境的等待,可以設置:fetch.wait.max.ms,表示等待的最長時間。

Consumer Position

      追蹤記錄已經被消費掉的數據非常重要,kafka中利用offset,且由consumer自己維護。
      許多消息系統會在broker端保存元數據信息,記錄哪些消息已被消費過。這種情況下存在一個問題:當一條消息發送給consumer之後,broker可以立即修改狀態變爲已消費,或者等到consumer的確認後才修改狀態。如果broker發出消息後立即更新狀態標記爲consumed,則可能發生意外,使consumer未真正消費到這條消息,消息被丟失;爲了克服這一點,許多消息系統增加了確認機制,即:發出消息後只是標記爲send,等consumer真正消費完返回確認信號後才標記爲consumed。這種方式確實可以避免丟失消息,但如果consumer已處理了該條消息,但是發送確認信號之前出故障了,那麼確認丟失,消息便會被重複消費兩次;另一個缺點就是增加確認機制必然導致性能降低,broker需要爲每條消息維護多個狀態,還需要處理異常情況。broker負載太重。
     (kafka中broker無狀態,consumer自己維護offset,同樣可以在發出fetch請求後更新offset值,或者消費完這條消息之後才修改offset。你可以根據實際應用對可靠性的需求選擇任意一種方式,立即修改值可能導致發生故障時,例如網絡斷開,消息得不到處理便丟失了。)
      kafka的設計則避免了以上的複雜情況。consumer只消費一個partition,他只需要維護一個整形數值,表明下次消費的消息位置。而且,consumer會定期向zookeeper提交他的offset,避免自己crash之後繼續消費。(可以詳細看一下consumer的參數)

Message Delivery Semantics

      消息傳遞的可靠性保證:(涉及producer到broker、consumer與broker,即生產者端和消費者端)
      at most once:消息可能會丟失但絕不重傳;
      at least once:從不丟失,可能重傳;
      exactly once:最理想的狀態,消息只被傳送一次,不丟失也不重傳,kafka目前不能保證;
      對於producer:發送一條消息給broker,只有消息被commit to the log,纔算發送成功。由於broker 有備份機制,所以用戶可以設置自己想要的可靠性:request.required.acks
  • 0:producer發出消息即完成發送,不等待確認,這種方式延遲最小、可靠性最差,最容易丟失消息;
  • 1:當且僅當leader收到消息返回確認信號後認爲發送成功,只有當leader crash,而且未被同步至其他follower時才丟消息;
  • -1:只有當leader以及所有follower都收到消息確認後,才發送成功,最好的可靠性,延遲也較大。但是還是有可能丟消息;
       對於consumer:消費一條消息,之後更新offset,有以下幾種方式:
  • 讀消息,更新offset,最後處理消費消息:可能未處理之前consumer crash,但已經更新了offset,consumer重啓後或者一個新的consumer會從offset之後的位置繼續消費,所以丟失了數據,at-most-once;
  • 讀消息,處理消費消息,最後更新offset:可能處理之後,更新offset之前crash,消息會被重複處理,at-least-once;
  • 怎麼實現exactly-once:如果可以把offset和消息消費後的output保存在一起,eg都保存在HDFS文件中,就可以保證他們被同時更新,這樣就可以保證output時刻和offset保持同步。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章