1. 程式人生 > 實用技巧 >[Kafka]進一步瞭解kafka

[Kafka]進一步瞭解kafka

Kafka的架構


一個Kafka叢集中包含多個Producer,Producer可以是日誌,系統CPU,Memory等,包含若干個Broker,若干個ConsumerGroup,以及一個Zookeeper叢集,Kafka通過Zookeeper管理叢集配置,選舉Leader,以及在ConsumerGroup發生變化的時候進行Rebalance。Producer採取Push模式將訊息釋出到Broker,Consumer採取Poll模式從Broker裡訂閱並消費訊息。

Topic

Topic在邏輯上可以被認為是一個Queue,每條消費必須指定Topic意思就是指定這個訊息放在哪個Queue裡面,同時在kafka裡面,為了使得吞吐率提高,物理上將Topic分成了多個Partition,每個Partition在物理上對應一個資料夾,該資料夾下儲存這個Partition的所有訊息和索引檔案,建立一個Topic的時候,可以指定分割槽數目,分割槽的數目越多,其吞吐量也就越大,但是需要的資源也越多,同時也會增加不可用的風險,kafka在接收到生產者傳送的訊息之後,會根據均衡策略將訊息儲存在不同的分割槽當中,因為每條資訊都被追加到這個partition中,屬於順序寫磁碟,因為效率非常高。(區別順序寫和隨機寫)。

舊資料刪除策略

kafka叢集會保留所有的訊息,無論這個訊息是否被消費,但是事實上在現實中因為資源的問題,不可能永久保留所有資料,所以kafka有相應的刪除策略。一種是基於時間,第二種是基於Partition的檔案大小。策略選擇需要結合業務實際情況。

Producer訊息路由

Producer傳送資訊到Broker的時候,會根據Partition機制選擇將其儲存到哪個Partition,如果Partition機制設定合理,所有訊息可以均勻分佈在不同的Partition裡面,即實現了負載均衡,如果一個topic對應一個檔案,那麼這個檔案所在的機器IO將會成為整個Topic的效能瓶頸,而有了Partition之後,不同的訊息可以並行地寫到不同Broker的不同Partition裡,提高了吞吐率。這一點可以通過配置項來指定新建Topic的預設Partition的數量,也可以在建立Topic的時候通過引數來指定。

而在傳送一條訊息時候,可以指定此訊息的key,Producer通過這個Key和Partition機制來判斷應該將這條資訊傳送到哪個Partition。Partition機制可以通過指定Producer的Partition.class引數來指定,該Class實現了kafka.producer.Partitioner介面。

ConsumerGroup

同一個Topic的一條訊息只能被同一個ConsumerGroup中的一個Consumer消費,但多個ConsumerGroup可以同時消費一條訊息。

這就是kafka來實現一個Topic訊息的廣播(發給所有的Consumer)和單播(傳送給某一個Consumer)的手段,一個Topic可以對應多個ConsumerGroup。如果需要實現廣播,那麼只要一個Consumer有一個獨立的Group就行了。要實現單播只要所有的Consumer在同一個Group裡,用ConsumerGroup還可以將Consumer進行自由的分組而不需要多次傳送訊息到不同的Topic。

Kafka delivery guarantee

at most once 訊息可能會丟,但是絕對不會重複傳輸
at least one 訊息絕對不會丟失,但是可能會重複傳輸(預設)
exactly onece 每條訊息肯定只會被傳輸一次且只傳輸一次

kafka預設保證At least once,並且允許通過設定Producer非同步提交來實現At most once,而exactly once要與外部儲存相互協作。

Replication

在kafka0.8以前的版本中,是沒有
replication的,這就導致一旦一個Broker宕機,那麼其他所有的partition資料都不可用被消費,同時生產者也不能將訊息存入到這些partition中。
如果生產者使用同步模式則生產者會嘗試重新發送message.send.max.retries次後丟擲異常,使用者可以選擇停止傳送後續資料也可以繼續傳送資料,停止傳送會造成資料阻塞,繼續傳送會導致整個Broker的資料丟失。
如果生產者使用非同步模式,那麼生產者會嘗試重新發送message.send.max.retries後記錄該異常並且繼續傳送資料,這樣會造成資料丟失並且使用者只能通過日誌才能發現問題,因為kafka的生產者並沒有對非同步模式提高回撥。
所以沒有replication的情況下,一旦機器宕機或者某個Broker停止工作,會造成整個系統的可用性降低。

選舉Leader

有了replication之後,同一個partition可能會有多個replication,這時候就需要在這些replication中選舉出leader,消費者生產者只與leader互動,其他replication作為follower從leader當中複製資料。這樣做的目的是因為,如果不設定一個leader,那麼為了確保多個replication中能夠同步資料,就必須需要保證多個replication能夠互相同步資料,假設replication有N個,那麼就有N*N個通路,資料一致性很難保證,而有了leader之後,只需要從leader中同步資料即可,相當於N條通路,簡單高效。

Kafka 高可用設計

將所有replication均勻分佈到叢集

分配演算法:
1,將所有broker和待分配的partition排序
2,將第i個partition分配到第(i%n)個broker上
3,將第i個partition的第j個replication分配到第(i+j)%n個broker上。

副本策略

也就是上面replication策略。

訊息傳遞同步策略

生產者在釋出訊息到某個partition中的時候,先通過Zookeeper找到這個partition的leader,將該資訊傳送給這個leader,leader會將資訊寫入日誌。每個follower都從leader拉資料,這種方式下,follower儲存的資料和leader是一致的。follower在收到資訊也寫入日誌,並且向leader傳送ACK訊息,一旦leader把所有的replication的ACK都收到了,說明訊息已經被commit了。隨之leader會向生產者傳送ACK資訊。
為了效能,上面的描述中,其實每個follower在接收到資料之後會立馬傳送ACK到leader,而不是等待寫入日誌,對於已經commit的訊息,kafka只能保證它被存到多個replication的記憶體中,而不保證持久化,當然,也不能保證異常發生後這個訊息一定會被消費者消費。但是隻有commit的訊息才會暴露給消費者。

ACK前的備份

判斷一個Broker是否存活,一是broker必須維護其和Zookeeper的session,說到程式碼上就是心跳機制。二是follower必須能夠及時地將leader的訊息複製過來。
leader會跟蹤它的follower列表,如果其中一個宕機或者落後太多,那麼會將它從列表中移除,kafka的複製機制並不是完全的同步複製和非同步複製,因為完全同步會影響吞吐率,而非同步的情況下,資料只要被寫入日誌就會被認為已經commit,這種情況下,如果follower都複製完都落後於leader,那麼如果leader突然掛了,就會造成資料丟失。採用列表的方式就可以很好的均衡了確保資料不丟失以及吞吐率,follower可以批量的從leader複製資料,提高複製效能,減少leader和follower的差距。

leader的選舉演算法

選舉機制具體來講是一個分散式鎖,有兩種方式實現基於Zookeeper的分散式鎖:

節點名稱的唯一性:即多個客戶端建立一個節點,只有成功建立節點的客戶端才能獲得鎖。
臨時順序節點:所有客戶端在某個目錄下建立自己的臨時順序節點,只有序號小的才能獲得鎖。

參考

部落格備份