Kafka到底會不會丟消息

1、kafka是什麼

一種高吞吐量的分佈式、發佈訂閱消息系統,它可以處理消費者規模的,網站中的所有動作流數據,具有高性能、持久化、多副本備份、橫向擴展能力……

  • 以時間複雜度爲 O(1) 的方式提供消息持久化能力,即使對 TB 級以上數據也能保證常數時間複雜度的訪問性能。
  • 高吞吐率。即使在非常廉價的商用機器上也能做到單機支持每秒 100K 條以上消息的傳輸。
  • 支持 Kafka Server 間的消息分區,及分佈式消費,同時保證每個 Partition 內的消息順序傳輸。
  • 同時支持離線數據處理和實時數據處理。
  • Scale out:支持在線水平擴展。

image.png

2、消息從生產到消費

2.1、發送數據

永遠找leader!消息寫入leader後,follower是主動的去leader進行同步的!producer採用push模式將數據發佈到broker,每條消息追加到分區中,順序寫入磁盤,所以保證同一分區內的數據是有序的!

  • partition在寫入的時候可以指定需要寫入的partition,如果有指定,則寫入對應的partition。
  • 如果沒有指定partition,但是設置了數據的key,則會根據key的值hash出一個partition。
  • 如果既沒指定partition,又沒有設置key,則會輪詢選出一個partition。

image.png

發送數據可靠性保證:ACK機制!

0:代表producer往集羣發送數據不需要等到集羣的返回,不確保消息發送成功。安全性最低但是效率最高。
1:代表producer往集羣發送數據只要leader應答就可以發送下一條,只確保leader發送成功。
all:代表producer往集羣發送數據需要所有的follower都完成從leader的同步纔會發送下一條,確保leader發送成功和所有的副本都完成備份。安全性最高,但是效率最低。

敲黑板:所以這裏可能是會丟消息的喲!

0:發丟了,生產端不知道,就是丟了。
1:保證leader不丟,但是如果leader掛了,恰好選了一個沒有ACK的follower,那也丟了。
all:保證leader和follower不丟,但是如果網絡擁塞,沒有收到ACK,會有重複發的問題。

2.2、保存數據

你以爲是這樣的:

image.png

其實是這樣的:

image.png

操作系統本身有一層緩存,叫做 Page Cache,是在內存裏的緩存,我們也可以稱之爲 OS Cache,意思就是操作系統自己管理的緩存。你在寫入磁盤文件的時候,可以直接寫入這個 OS Cache 裏,也就是僅僅寫入內存中,接下來由操作系統自己決定什麼時候把 OS Cache 裏的數據真的刷入磁盤文件中。

Kafka提供了一個參數——producer.type來控制是不是主動flush,如果Kafka寫入到mmap之後就立即flush然後再返回Producer叫 同步 (sync);寫入mmap之後立即返回Producer不調用flush叫異步 (async)。

敲黑板:所以這裏也可能是會丟消息的喲!

假如已經寫在了OS cache中但是還沒來得及刷入磁盤,此時突然機器宕機,或者broker重啓,那就丟了。

2.3、消費數據

消費者通過pull模式主動的去kafka集羣拉取消息,與producer相同的是,消費者在拉取消息的時候也是找leader去拉取。

多個消費者可以組成一個消費者組(consumer group),每個消費者組都有一個組id!同一個消費組者的消費者可以消費同一topic下不同分區的數據,但是不會組內多個消費者消費同一分區的數據。

image.png

在早期的版本中,消費者將消費到的offset維護zookeeper中,consumer每間隔一段時間上報一次,這裏容易導致重複消費,且性能不好!在新的版本中消費者消費到的offset已經直接維護在kafka集羣的__consumer_offsets這個topic中!

消費消息的時候可以大致分爲兩個階段:1、標示該消息已被消費(commit記錄一下);2、處理消息。

敲黑板:所以這裏也可能是會丟消息的喲!

先commit,但是在處理消息的異常了,此時這條消息就丟了。
先處理,再commit,不丟。

3、消息可靠性保證

  • At most once 消息可能會丟,但絕不會重複傳輸
  • At least once 消息絕不會丟,但可能會重複傳輸
  • Exactly once 每條消息肯定會被傳輸一次且僅傳輸一次,很多時候這是用戶所想要的

從 Producer 向 broker 發送消息時,通過ACK機制保證不丟消息,但是不可靠,依賴kafka的參數配置:

  • 0:發丟了,生產端不知道,就是丟了,對應At most once。
  • 1:保證leader不丟,但是如果leader掛了,恰好選了一個沒有ACK的follower,那也丟了,對應At most once。
  • all:保證leader和follower不丟,但是如果網絡擁塞,沒有收到ACK,會有重複發的問題,對應At least once。

在broker存儲消息時,通過主動flush來保證可靠性,但是如果沒設置強制flush,那就有可能丟了。

從 broker 到 Consumer 消費消息時,數據處理與 commit 的順序在很大程度上決定了消息從 broker 和 consumer 的可靠性:

  • 讀完消息先 commit 再處理消息。這種模式下,如果 Consumer 在 commit 後還沒來得及處理消息就 crash 了,下次重新開始工作後就無法讀到剛剛已提交而未處理的消息,這就對應於 At most once
  • 讀完消息先處理再 commit。這種模式下,如果在處理完消息之後 commit 之前 Consumer crash 了,下次重新開始工作時還會處理剛剛未 commit 的消息,實際上該消息已經被處理過了。這就對應於 At least once。在很多使用場景下,消息的處理往往具有冪等性,即多次處理這一條消息跟只處理一次是等效的,那就可以認爲是 Exactly once。
  • 如果一定要做到 Exactly once,就需要協調 offset 和實際操作的輸出。精典的做法是引入兩階段提交。如果能讓 offset 和操作輸入存在同一個地方,會更簡潔和通用。這種方式可能更好,因爲許多輸出系統可能不支持兩階段提交。比如,Consumer 拿到數據後可能把數據放到 HDFS,如果把最新的 offset 和數據本身一起寫到 HDFS,那就可以保證數據的輸出和 offset 的更新要麼都完成,要麼都不完成,間接實現 Exactly once。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章