1. 程式人生 > >Kafka無法消費?!我的分散式訊息服務Kafka卻穩如泰山!

Kafka無法消費?!我的分散式訊息服務Kafka卻穩如泰山!

在一個月黑風高的夜晚,突然收到現網生產環境Kafka訊息積壓的告警,夢中驚醒啊,馬上起來排查日誌。

問題現象:消費請求卡死在查詢Coordinator

Coordinator為何物?Coordinator用於管理Consumer Group中各個成員,負責消費offset位移管理和Consumer Rebalance。Consumer在消費時必須先確認Consumer Group對應的Coordinator,隨後才能join Group,獲取對應的topic partition進行消費。

那如何確定Consumer Group的Coordinator呢?分兩步走:

1、一個Consumer Group對應一個__consumers_offsets的分割槽,首先先計算Consumer Group對應的__consumers_offsets的分割槽,計算公式如下:

__consumers_offsets partition# = Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount,其中groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定。

2、1中計算的該partition的leader所在的broker就是被選定的Coordinator。

定位過程

Coordinator節點找到了,現在看看Coordinator是否有問題:

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0958c.jpg

不出所料,Coordinator對應分割槽Leader為-1,消費端程式會一直等待,直到Leader選出來為止,這就直接導致了消費卡死。

為啥Leader無法選舉?Leader選舉是由Controller負責的。Controller節點負責管理整個叢集中分割槽和副本的狀態,比如partition的Leader選舉,topic建立,副本分配,partition和replica擴容等。現在我們看看Controller的日誌:

  1. 6月10日15:48:30,006 秒Broker 1成為controller

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a09dea.jpg

此時感知的節點為1和2,節點3 在zk讀不出來:

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0a519.jpg

31847的時候把__consumer_offsets的分割槽3Leader選為1ISR[1,2]leader_epoch14

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0ac64.jpg

再過1秒後才感知到Controller

發生變化,自身清退

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0b377.jpg

  1. Broker 2在其後幾百毫秒後(15:48:30,936)也成為Controller

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0baff.jpg

但是Broker2 是感知到Broker 3節點是活的,日誌如下:

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0c236.jpg

注意這個時間點,Broker1還沒在zk__consumer_offsets的分割槽3 Leader從節點3改為1,這樣Broker 2還認為Broker 3Leader,並且Broker 3在它認為是活的,所以不需要重新選舉Leader。這樣一直保持了相當長的時間,即使Broker 1已經把這個分割槽的Leader切換了,它也不感知。

  1. Broker 2在12號的21:43:19又感知Broker 1網路中斷,並處理節點失敗事件:

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0ca6f.jpg

因為Broker 2記憶體中認為__consumer_offsets分割槽3Leaderbroker 3,所以不會觸發分割槽3Leader切換。

Broker 2但是在處理失敗的節點Broker 1時,會把副本從ISR列表中去掉,去掉前會讀一次zk,程式碼如下:

但是發現zk中分割槽3Leader已經變為1ISR列表為[1,2],當要去掉的節點1就是Leader的時候,Leader就會變為-1 ISR只有[2],從日誌也可以看到:

http://image.hw3static.com/hi/staticimages/hi3msf/images/2017/0718/19/596df12a0da9f.jpg

這樣分割槽Leader一直為-1,直到有新的事件觸發節點2重新選舉才能恢復(例如重啟某個節點)。

根因總結

出現網路異常後,由於新老controller之間感知的可用節點不同,導致新controller對某個分割槽的Leader在記憶體中的資訊與zk記錄元資料的資訊不一致,導致controller選舉流程出現錯誤,選不出Leader 需要有新的選舉事件才能觸發Leader選出來,例如重啟。

問題總結

這是一個典型的由於網路異常導致腦裂,進而出現了多個Controller,菊廠分散式訊息服務Kafka經過電信級的可靠性驗證,已經完美解決了這些問題 。