Kafka(二)高可用系統設計心得
離上次寫文章過去2個星期了,這2個星期一直在做圍繞Kafka的高可用。今天終於上線了,現在分享一下心得。
主要涉及到的組間有:Kafka,ZABBIX,Flink
業務流程是 Nginx - A - B
Kafka基礎知識(0.8.2):
主要有2個角色,Producer,Consumer,一個生產數據,一個消費數據,A與B、B與C之間的業務交互,就分別是生產者、消費者的關係。他們都會走Kafka集群。
Producer可以選擇開闢很多個Partition,消息會並發地打向這些Partition,這個數字可以指定,目前我們使用了10個分區。Partition之間的數據沒有順序保證,但一個Partition之間的消息是有序的。
這些Partition的消息會發給所有的Consumer Group,這是一種廣播關係,Consumer Group即代碼中的groupId這個屬性,在一個Consumer Group中,如果有多個Consumer,則只有一個消費者可以拿到數據。
如圖,4個Partition,每個都會往2個Consumer Group各發一份數據。但每個Group中,只有一個Consumer可以拿到數據。
這裡還有一個概念,就是Topic,Producer生產數據時會指明一個Topic,Consumer只有使用同樣的Topic才可以拿到數據。
目標是:
A:整個機房掛掉,服務依然可用。(靠Nginx實現)
B:整個Kafka掛掉,服務依然可用.(依靠心跳實現)
C:Kafka的部分Partition掛掉,服務依然可用。(依靠確認實現)
A:整個機房掛掉,服務依然可用
總體思路就是原本1條路,現在2條.由Nginx判斷哪條路是健康的。
原本可以做到雙活,但由於業務特殊需求,這裡只做了熱備。
這裡分為A與B來簡化說明,A是B的上游。
A將消息打入Kafka中,B使用Flink消費,並通過Flink打完下一個Kafka中。
AB各雙路,即2個A,A1,A2,2個B,B1,B2.
消息的來源是ZABBIX,ZABBIX通過http請求,將數據發往Nginx,Nginx發給主路(A1)
那麼Nginx的可用性如何保障呢?這一點我們還沒有想好。
A1,B1使用一個Kafka集群,在一個機房。而A2,B2,以及使用的Kafka集群則在完全不同的另一個機房。
B:整個Kafka集群掛掉,服務依然可用
A1 A2 B1 B2,各使用一個Topic來專門consume心跳數據(自定義一個數據結構)。
A1,A2除了建立自己的心跳consumer,還需要建立2個心跳發送的producer,用來向B1,B2發送帶有命令的心跳(如,要求立刻返回心跳),以及2個發往業務數據的producer,用來隨時切換(但同一時刻只會使用一個producer)。
B1,B2按時發送心跳給A1,A2.在發送的時候,必須在心跳裡帶有自身的標誌(這個可以在運行時輸入參數指定,在代碼里根據System.getProperty("YourKey")獲取),以及時間戳,還有一些別的信息,比如代碼指令,以及每條消息的id。
A1,A2記錄B1,B2的最後一次心跳。
定時檢查最後一次心跳的時間戳。如果超過第一閾值,向B1或者B2發送帶有代碼指令的心跳,B1,B2收到後,立刻會往A1,A2發送心跳。
如果超過第二閾值,把B1(或B2)可用性置為false,然後使用第二個producer,所有的消息打往第二個B——直到收到本機房的B心跳。
C:Kafka的部分Partition掛掉,部分消息丟失,服務依然可用可靠
A1,A2,在內存記錄發往B1,B2的數據,分開存儲,並且在其中(業務數據)防止一些額外的信息,比如:A的身份、A發送的時間、該數據的順序id(以A受到的數據順序定id)。
這裡我可以用業務數據是因為我認為只有這樣,把這些信息跟業務數據牢牢綁定在一起,同時發出、同時接收,走同一個Kafka,使用同一段Flink代碼處理,這樣才算是真正的HA,不然Kafka、Flink等等各個環境的Bug或者事故都可能使得你的心跳數據不能牢靠地反映你的業務數據。
B在收到以後,把這些信息收集起來,做成心跳(帶有A發送該數據的時間、該數據的順序id),通過Http請求,發回源A。然後把這些信息從業務數據中去除。
A在收到之後,就會從內存中,根據順序id,把該數據移除。
同樣,A定時檢查內存中的數據,再次發送超時的數據。
Flink相關:
用到Flink,有些坑。我將在下一篇文章作說明。
希望對你有幫助。
推薦閱讀:
※Kafka Connect內部原理
※如何使用Kafka在生產環境構建大規模機器學習
※重磅發布:Kafka迎來1.0.0版本,正式告別四位數版本號
※大數據平台開發人員的核心競爭力是什麼?
※kafka中的topic為什麼要進行分區?