本系列主要講解kafka基本設計和原理分析,分以下內容:html
本節討論Kafka如何確保消息在producer和consumer之間傳輸。有如下三種可能的傳輸保障(delivery guarantee):算法
Kafka的消息傳輸保障機制很是直觀。當producer向broker發送消息時,一旦這條消息被commit,因爲副本機制(replication)的存在,它就不會丟失。可是若是producer發送數據給broker後,遇到的網絡問題而形成通訊中斷,那producer就沒法判斷該條消息是否已經提交(commit)。雖然Kafka沒法肯定網絡故障期間發生了什麼,可是producer能夠retry屢次,確保消息已經正確傳輸到broker中,因此目前Kafka實現的是at least once。編程
consumer從broker中讀取消息後,能夠選擇commit,該操做會在Zookeeper中存下該consumer在該partition下讀取的消息的offset。該consumer下一次再讀該partition時會從下一條開始讀取。如未commit,下一次讀取的開始位置會跟上一次commit以後的開始位置相同。固然也能夠將consumer設置爲autocommit,即consumer一旦讀取到數據當即自動commit。若是隻討論這一讀取消息的過程,那Kafka是確保了exactly once, 可是若是因爲前面producer與broker之間的某種緣由致使消息的重複,那麼這裏就是at least once。緩存
考慮這樣一種狀況,當consumer讀完消息以後先commit再處理消息,在這種模式下,若是consumer在commit後還沒來得及處理消息就crash了,下次從新開始工做後就沒法讀到剛剛已提交而未處理的消息,這就對應於at most once了。安全
讀完消息先處理再commit。這種模式下,若是處理完了消息在commit以前consumer crash了,下次從新開始工做時還會處理剛剛未commit的消息,實際上該消息已經被處理過了,這就對應於at least once。網絡
要作到exactly once就須要引入消息去重機制。併發
如上一節所述,Kafka在producer端和consumer端都會出現消息的重複,這就須要去重處理。分佈式
Kafka文檔中說起GUID(Globally Unique Identifier)的概念,經過客戶端生成算法獲得每一個消息的unique id,同時可映射至broker上存儲的地址,即經過GUID即可查詢提取消息內容,也便於發送方的冪等性保證,須要在broker上提供此去重處理模塊,目前版本尚不支持。高併發
針對GUID, 若是從客戶端的角度去重,那麼須要引入集中式緩存,必然會增長依賴複雜度,另外緩存的大小難以界定。性能
不僅是Kafka, 相似RabbitMQ以及RocketMQ這類商業級中間件也只保障at least once, 且也沒法從自身去進行消息去重。因此咱們建議業務方根據自身的業務特色進行去重,好比業務消息自己具有冪等性,或者藉助Redis等其餘產品進行去重處理。
Kafka提供了很高的數據冗餘彈性,對於須要數據高可靠性的場景,咱們能夠增長數據冗餘備份數(replication.factor),調高最小寫入副本數的個數(min.insync.replicas)等等,可是這樣會影響性能。反之,性能提升而可靠性則下降,用戶須要自身業務特性在彼此之間作一些權衡性選擇。
要保證數據寫入到Kafka是安全的,高可靠的,須要以下的配置:
replication.factor
>=3,即副本數至少是3個;2<=min.insync.replicas
<=replication.factor
unclean.leader.election.enable=false
request.required.acks=-1
(all),producer.type=sync
關於做者
愛編程、愛鑽研、愛分享、愛生活
關注分佈式、高併發、數據挖掘
如需捐贈,請掃碼