學(xué)過大數(shù)據(jù)的同學(xué)應(yīng)該都知道 Kafka胳赌,它是分布式消息訂閱系統(tǒng)逃呼,有非常好的橫向擴(kuò)展性,可實(shí)時存儲海量數(shù)據(jù)岗憋,是流數(shù)據(jù)處理中間件的事實(shí)標(biāo)準(zhǔn)。本文將介紹 Kafka 是如何保證數(shù)據(jù)可靠性和一致性的锚贱。
文章目錄
數(shù)據(jù)可靠性
Kafka 作為一個商業(yè)級消息中間件仔戈,消息可靠性的重要性可想而知。本文從 Producter 往 Broker 發(fā)送消息拧廊、Topic 分區(qū)副本以及 Leader 選舉幾個角度介紹數(shù)據(jù)的可靠性监徘。
Topic 分區(qū)副本
在 Kafka 0.8.0 之前,Kafka 是沒有副本的概念的吧碾,那時候人們只會用 Kafka 存儲一些不重要的數(shù)據(jù)凰盔,因?yàn)闆]有副本,數(shù)據(jù)很可能會丟失倦春。但是隨著業(yè)務(wù)的發(fā)展户敬,支持副本的功能越來越強(qiáng)烈落剪,所以為了保證數(shù)據(jù)的可靠性,Kafka 從 0.8.0 版本開始引入了分區(qū)副本(詳情請參見 KAFKA-50)尿庐。也就是說每個分區(qū)可以人為的配置幾個副本(比如創(chuàng)建主題的時候指定 replication-factor
忠怖,也可以在 Broker 級別進(jìn)行配置 default.replication.factor
),一般會設(shè)置為3抄瑟。
Kafka 可以保證單個分區(qū)里的事件是有序的凡泣,分區(qū)可以在線(可用),也可以離線(不可用)皮假。在眾多的分區(qū)副本里面有一個副本是 Leader问麸,其余的副本是 follower,所有的讀寫操作都是經(jīng)過 Leader 進(jìn)行的钞翔,同時 follower 會定期地去 leader 上的復(fù)制數(shù)據(jù)严卖。當(dāng) Leader 掛了的時候,其中一個 follower 會重新成為新的 Leader布轿。通過分區(qū)副本哮笆,引入了數(shù)據(jù)冗余,同時也提供了 Kafka 的數(shù)據(jù)可靠性汰扭。
Kafka 的分區(qū)多副本架構(gòu)是 Kafka 可靠性保證的核心稠肘,把消息寫入多個副本可以使 Kafka 在發(fā)生崩潰時仍能保證消息的持久性。
Producer 往 Broker 發(fā)送消息
如果我們要往 Kafka 對應(yīng)的主題發(fā)送消息萝毛,我們需要通過 Producer 完成项阴。前面我們講過 Kafka 主題對應(yīng)了多個分區(qū),每個分區(qū)下面又對應(yīng)了多個副本笆包;為了讓用戶設(shè)置數(shù)據(jù)可靠性环揽, Kafka 在 Producer 里面提供了消息確認(rèn)機(jī)制。也就是說我們可以通過配置來決定消息發(fā)送到對應(yīng)分區(qū)的幾個副本才算消息發(fā)送成功庵佣∏附海可以在定義 Producer 時通過 acks
參數(shù)指定(在 0.8.2.X 版本之前是通過 request.required.acks
參數(shù)設(shè)置的,詳見 KAFKA-3043)巴粪。這個參數(shù)支持以下三種值:
- acks = 0:意味著如果生產(chǎn)者能夠通過網(wǎng)絡(luò)把消息發(fā)送出去通今,那么就認(rèn)為消息已成功寫入 Kafka 。在這種情況下還是有可能發(fā)生錯誤肛根,比如發(fā)送的對象無能被序列化或者網(wǎng)卡發(fā)生故障辫塌,但如果是分區(qū)離線或整個集群長時間不可用,那就不會收到任何錯誤派哲。在 acks=0 模式下的運(yùn)行速度是非尘拾保快的(這就是為什么很多基準(zhǔn)測試都是基于這個模式),你可以得到驚人的吞吐量和帶寬利用率狮辽,不過如果選擇了這種模式一也, 一定會丟失一些消息巢寡。
- acks = 1:意味若 Leader 在收到消息并把它寫入到分區(qū)數(shù)據(jù)文件(不一定同步到磁盤上)時會返回確認(rèn)或錯誤響應(yīng)。在這個模式下椰苟,如果發(fā)生正常的 Leader 選舉抑月,生產(chǎn)者會在選舉時收到一個 LeaderNotAvailableException 異常,如果生產(chǎn)者能恰當(dāng)?shù)靥幚磉@個錯誤舆蝴,它會重試發(fā)送悄息谦絮,最終消息會安全到達(dá)新的 Leader 那里。不過在這個模式下仍然有可能丟失數(shù)據(jù)洁仗,比如消息已經(jīng)成功寫入 Leader层皱,但在消息被復(fù)制到 follower 副本之前 Leader發(fā)生崩潰。
- acks = all(這個和 request.required.acks = -1 含義一樣):意味著 Leader 在返回確認(rèn)或錯誤響應(yīng)之前赠潦,會等待所有同步副本都收到悄息叫胖。如果和
min.insync.replicas
參數(shù)結(jié)合起來,就可以決定在返回確認(rèn)前至少有多少個副本能夠收到悄息她奥,生產(chǎn)者會一直重試直到消息被成功提交瓮增。不過這也是最慢的做法,因?yàn)樯a(chǎn)者在繼續(xù)發(fā)送其他消息之前需要等待所有副本都收到當(dāng)前的消息哩俭。
根據(jù)實(shí)際的應(yīng)用場景绷跑,我們設(shè)置不同的 acks
,以此保證數(shù)據(jù)的可靠性凡资。
另外砸捏,Producer 發(fā)送消息還可以選擇同步(默認(rèn),通過 producer.type=sync
配置) 或者異步(producer.type=async
)模式隙赁。如果設(shè)置成異步垦藏,雖然會極大的提高消息發(fā)送的性能,但是這樣會增加丟失數(shù)據(jù)的風(fēng)險鸳谜。如果需要確保消息的可靠性膝藕,必須將 producer.type
設(shè)置為 sync。
Leader 選舉
在介紹 Leader 選舉之前咐扭,讓我們先來了解一下 ISR(in-sync replicas)列表。每個分區(qū)的 leader 會維護(hù)一個 ISR 列表滑废,ISR 列表里面就是 follower 副本的 Borker 編號蝗肪,只有跟得上 Leader 的 follower 副本才能加入到 ISR 里面,這個是通過 replica.lag.time.max.ms
參數(shù)配置的蠕趁,具體可以參見 《一文了解 Kafka 的副本復(fù)制機(jī)制》薛闪。只有 ISR 里的成員才有被選為 leader 的可能。
所以當(dāng) Leader 掛掉了俺陋,而且 unclean.leader.election.enable=false
的情況下豁延,Kafka 會從 ISR 列表中選擇第一個 follower 作為新的 Leader昙篙,因?yàn)檫@個分區(qū)擁有最新的已經(jīng) committed 的消息。通過這個可以保證已經(jīng) committed 的消息的數(shù)據(jù)可靠性诱咏。
綜上所述苔可,為了保證數(shù)據(jù)的可靠性,我們最少需要配置一下幾個參數(shù):
- producer 級別:acks=all(或者 request.required.acks=-1)袋狞,同時發(fā)生模式為同步 producer.type=sync
- topic 級別:設(shè)置 replication.factor>=3焚辅,并且 min.insync.replicas>=2;
- broker 級別:關(guān)閉不完全的 Leader 選舉苟鸯,即 unclean.leader.election.enable=false同蜻;
數(shù)據(jù)一致性
這里介紹的數(shù)據(jù)一致性主要是說不論是老的 Leader 還是新選舉的 Leader,Consumer 都能讀到一樣的數(shù)據(jù)早处。那么 Kafka 是如何實(shí)現(xiàn)的呢湾蔓?
如果想及時了解Spark、Hadoop或者HBase相關(guān)的文章砌梆,歡迎關(guān)注微信公眾號:iteblog_hadoop
假設(shè)分區(qū)的副本為3卵蛉,其中副本0是 Leader,副本1和副本2是 follower么库,并且在 ISR 列表里面傻丝。雖然副本0已經(jīng)寫入了 Message4,但是 Consumer 只能讀取到 Message2诉儒。因?yàn)樗械?ISR 都同步了 Message2葡缰,只有 High Water Mark 以上的消息才支持 Consumer 讀取,而 High Water Mark 取決于 ISR 列表里面偏移量最小的分區(qū)忱反,對應(yīng)于上圖的副本2泛释,這個很類似于木桶原理。
這樣做的原因是還沒有被足夠多副本復(fù)制的消息被認(rèn)為是“不安全”的温算,如果 Leader 發(fā)生崩潰怜校,另一個副本成為新 Leader,那么這些消息很可能丟失了注竿。如果我們允許消費(fèi)者讀取這些消息茄茁,可能就會破壞一致性。試想巩割,一個消費(fèi)者從當(dāng)前 Leader(副本0) 讀取并處理了 Message4裙顽,這個時候 Leader 掛掉了,選舉了副本1為新的 Leader宣谈,這時候另一個消費(fèi)者再去從新的 Leader 讀取消息愈犹,發(fā)現(xiàn)這個消息其實(shí)并不存在,這就導(dǎo)致了數(shù)據(jù)不一致性問題闻丑。
當(dāng)然漩怎,引入了 High Water Mark 機(jī)制勋颖,會導(dǎo)致 Broker 間的消息復(fù)制因?yàn)槟承┰蜃兟敲聪⒌竭_(dá)消費(fèi)者的時間也會隨之變長(因?yàn)槲覀儠鹊却?fù)制完畢)勋锤。延遲時間可以通過參數(shù) replica.lag.time.max.ms
參數(shù)配置饭玲,它指定了副本在復(fù)制消息時可被允許的最大延遲時間。