您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)如何進行Kafka 重啟失敗問題排查,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
收到用戶方反饋,發(fā)現(xiàn)日志 kafka 集群 A 主題 的 34 分區(qū)選舉不了 leader,導(dǎo)致某些消息發(fā)送到該分區(qū)時,會報如下 no leader 的錯誤信息:
In the middle of a leadership election, there is currently no leader for this partition and hence it is unavailable for writes.
接下來運維在 kafka-manager 查不到 broker0 節(jié)點了處于假死狀態(tài),但是進程依然還在,重啟了好久沒見反應(yīng),然后通過 kill -9 命令殺死節(jié)點進程后,接著重啟失敗了,導(dǎo)致了如下問題:
由于 A 主題 34 分區(qū)的 leader 副本在 broker0,另外一個副本由于速度跟不上 leader,已被踢出 ISR,0.11 版本的 kafka 的 unclean.leader.election.enable 參數(shù)默認(rèn)為 false,表示分區(qū)不可在 ISR 以外的副本選舉 leader,導(dǎo)致了 A 主題發(fā)送消息持續(xù)報 34 分區(qū) leader 不存在的錯誤,且該分區(qū)還未消費的消息不能繼續(xù)消費了。
查看了 KafkaServer.log 日志,發(fā)現(xiàn) Kafka 重啟過程中,產(chǎn)生了大量如下日志:
發(fā)現(xiàn)大量主題索引文件損壞并且重建索引文件的警告信息,定位到源碼處:
kafka.log.OffsetIndex#sanityCheck
按我自己的理解描述下:
Kafka 在啟動的時候,會檢查 kafka 是否為 cleanshutdown,判斷依據(jù)為 ${log.dirs} 目錄中是否存在 .kafka_cleanshutDown 的文件,如果非正常退出就沒有這個文件,接著就需要 recover log 處理,在處理中會調(diào)用 sanityCheck() 方法用于檢驗每個 log sement 的 index 文件,確保索引文件的完整性:
entries:由于 kafka 的索引文件是一個稀疏索引,并不會將每條消息的位置都保存到 .index 文件中,因此引入了 entry 模式,即每一批消息只記錄一個位置,因此索引文件的 entries = mmap.position / entrySize;
lastOffset:最后一塊 entry 的位移,即 lastOffset = lastEntry.offset;
baseOffset:指的是索引文件的基偏移量,即索引文件名稱的那個數(shù)字。
索引文件與日志文件對應(yīng)關(guān)系圖如下:
判斷索引文件是否損壞的依據(jù)是:
_entries == 0 || _lastOffset > baseOffset = false // 損壞 _entries == 0 || _lastOffset > baseOffset = true // 正常
這個判斷邏輯我的理解是:
entries 索引塊等于零時,意味著索引沒有內(nèi)容,此時可以認(rèn)為索引文件是沒有損壞的;當(dāng) entries 索引塊不等于 0,就需要判斷索引文件最后偏移量是否大于索引文件的基偏移量,如果不大于,則說明索引文件被損壞了,需要用重新構(gòu)建。
那為什么會出現(xiàn)這種情況呢?
我在相關(guān) issue 中似乎找到了一些答案:
https://issues.apache.org/jira/browse/KAFKA-1112
https://issues.apache.org/jira/browse/KAFKA-1554
總的來說,非正常退出在舊版本似乎會可能發(fā)生這個問題?
有意思的來了,導(dǎo)致開機不了并不是這個問題導(dǎo)致的,因為這個問題已經(jīng)在后續(xù)版本修復(fù)了,從日志可看出,它會將損壞的日志文件刪除并重建,我們接下來繼續(xù)看導(dǎo)致重啟不了的錯誤信息:
問題就出在這里,在刪除并重建索引過程中,就可能出現(xiàn)如上問題,在 issues.apache.org 網(wǎng)站上有很多關(guān)于這個 bug 的描述,我這里貼兩個出來:
https://issues.apache.org/jira/browse/KAFKA-4972
https://issues.apache.org/jira/browse/KAFKA-3955
這些 bug 很隱晦,而且非常難復(fù)現(xiàn),既然后續(xù)版本不存在該問題,當(dāng)務(wù)之急還是升級 Kafka 版本,后續(xù)等我熟悉 scala 后,再繼續(xù)研究下源碼,細(xì)節(jié)一定是會在源碼中呈現(xiàn)。
針對背景兩個問題,矛盾點都是因為 broker0 重啟失敗導(dǎo)致的,那么我們要么把 broker0 啟動成功,才能恢復(fù) A 主題 34 分區(qū)。
由于日志和索引文件的原因一直啟動不起來,我們只需要將損壞的日志和索引文件刪除并重啟即可。
但如果出現(xiàn) 34 分區(qū)的日志索引文件也損壞的情況下,就會丟失該分區(qū)下未消費的數(shù)據(jù),原因如下:
此時 34 分區(qū)的 leader 還處在 broker0 中,由于 broker0 掛掉了且 34 分區(qū) isr 只有 leader,導(dǎo)致 34 分區(qū)不可用,在這種情況下,假設(shè)你將 broker0 中 leader 的數(shù)據(jù)清空,重啟后 Kafka 依然會將 broker0 上的副本作為 leader,那么就需要以 leader 的偏移量為準(zhǔn),而這時 leader 的數(shù)據(jù)清空了,只能將 follower 的數(shù)據(jù)強行截斷為 0,且不大于 leader 的偏移量。
這似乎不太合理,這時候是不是可以提供一個操作的可能:
在分區(qū)不可用時,用戶可以手動設(shè)置分區(qū)內(nèi)任意一個副本作為 leader?
后面我會單獨一篇文章對這個問題進行分析。
制定一個升級方案,將集群升級到 2.2 版本;
每個節(jié)點的服務(wù)器將 systemd 的默認(rèn)超時值為 600 秒,因為我發(fā)現(xiàn)運維在故障當(dāng)天關(guān)閉 33 節(jié)點時長時間沒反應(yīng),才會使用 kill -9 命令強制關(guān)閉。但據(jù)我了解關(guān)閉一個 Kafka 服務(wù)器時,Kafka 需要做很多相關(guān)工作,這個過程可能會存在相當(dāng)一段時間,而 systemd 的默認(rèn)超時值為 90 秒即可讓進程停止,那相當(dāng)于非正常退出了。
將 broker 參數(shù) unclean.leader.election.enable 設(shè)置為 true(確保分區(qū)可從非 ISR 中選舉 leader);
將 broker 參數(shù) default.replication.factor 設(shè)置為 3(提高高可用,但會增大集群的存儲壓力,可后續(xù)討論);
將 broker 參數(shù) min.insync.replicas 設(shè)置為 2(這么做可確保 ISR 同時有兩個,但是這么做會造成性能損失,是否有必要?因為我們已經(jīng)將 unclean.leader.election.enable 設(shè)置為 true 了);
發(fā)送端發(fā)送 acks=1(確保發(fā)送時有一個副本是同步成功的,但這個是否有必要,因為可能會造成性能損失)。
上述就是小編為大家分享的如何進行Kafka 重啟失敗問題排查了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。