天天看點

Kafka Consumer

push vs pull

 Push VS Pull

An initial question we considered is whether consumers should pull data from brokers or brokers should push data to the consumer. In this respect Kafka follows a more traditional design, shared by most messaging systems, where data is pushed to the broker from the producer and pulled from the broker by the consumer.

Kafka遵循傳統設計,也是被大多數消息系統所采用的,即,producer push資料到broker,consumer從broker那裡pull資料。

A push-based system has difficulty dealing with diverse consumers as the broker controls the rate at which data is transferred. The goal is generally for the consumer to be able to consume at the maximum possible rate; unfortunately, in a push system this means the consumer tends to be overwhelmed when its rate of consumption falls below the rate of production. 

基于push的系統在面對不同的消費者的時候需要控制資料傳輸的速率這是很困難的,一般消費者都是以最大速率去消費的,不幸的是這對于push系統來說意味着當消費的速率低于生産的速率時消費者有崩潰的傾向。而基于pull的系統就有很好的屬性,消費者可以簡單的落後,并且在可能的時候迎頭趕上。在消費者感覺快要崩潰的時候可以緩和一下,讓消費者充分利用傳輸速率比看起來要複雜得多。

基于pull的系統的另一個優勢在于broker可以将自己的資料批量的發送給消費者。而基于push的系統必須選擇是立即發送請求還是累積更多的資料再發請求,而且發送以後它不知道消費者是否能很快的處理它。基于pull的系統就能夠很好的解決這個問題,因為消費者總是拉取在目前日志的位置之後的所有可用的消息。

基于pull的系統有一個缺陷就是如果broker沒有資料,消費者會一直循環等待,有效的繁忙的等待直到有資料到達。為了避免這個問題, 我們可以讓消費者在請求的時候以“長輪詢”的形式阻塞,直到有資料到達。

Consumer Position

 大部分的消息系統在broker中維護關于消息是否已經被消費的中繼資料。是以,一個消息被分發給消費者以後broker可以了解處理或者等到消費者确認。

或許你還沒有意識到讓broker和consumer就消息是否已經被消息達成一緻是一個很重要的問題。如果每次消息被分發出去以後broker就立即将這條消息标記為consumed,這個時候如果消費者處理消息失敗了(可能是因為它當機了或者請求逾時了或者其它的原因),那麼這條消息就丢失了。為了解決這個問題,許多消息系統增加一個确認特性,這就意味着在消息被發送以後隻能将它們标記為sent而不是consumed,broker會等待來自消費者的确認,之後才會将這條消息标記為consumed。這個政策雖然解決了丢失消息的問題,但是又帶來了新的問題。首先,如果消費者已經處理完消息,但是在它發送确認之前它失敗了,那麼這種情況下會導緻消息被消費兩次。第二個問題跟性能有關,現在broker對于每條消息必須維護多個狀态(首先鎖定它以至于它不會被分發第二次,然後永久的标記它為consumed以至于它肯能會被删除)。棘手的問題必須被處理,比如消息發送後沒有确認。

Kafka handles this differently. Our topic is divided into a set of totally ordered partitions, each of which is consumed by exactly one consumer within each subscribing consumer group at any given time. This means that the position of a consumer in each partition is just a single integer, the offset of the next message to consume. This makes the state about what has been consumed very small, just one number for each partition. This state can be periodically checkpointed. This makes the equivalent of message acknowledgements very cheap.

Kafka對這些問題的處理不同,主題被劃分為一系列有序的分區,在任意時刻,一個分區隻能被訂閱這個主題的每個消費者組中的一個消費者消費。這就意味着,消費者的位置在每個分區中僅僅是一個整數,這個整數就是即将要消費的下一個消息的offset(偏移量)。這使得标記關于消息是否已經被消費的狀态變得很簡單,每個分區僅僅一個數。這個狀态可以周期性的被檢查。這跟消息确認是等價的,而且也是非常廉價的。

消費者可以故意倒回到一個舊的offset去重新消費資料。當然,這一點違反了隊列的公共契約,但事實上這是許多消費者的一個基本特性。例如,如果消費者的代碼有bug,并且在一些消息被消費以後才發現,那麼消費者可以重新消費這些消息以修複這個bug。

參考 http://kafka.apache.org/documentation/#design

下一篇: Redis叢集