導語:疫情期間,為了保障國內學子的正常學習進度,騰訊課堂積極響應國家“停工不停學”的號召,緊急上線疫情期間專用的“老師極速版”,使廣大師生足不出戶,即可快速便捷的完成線上開課。面對線上課堂百萬量級的互動訊息,如何保證訊息的實時性和準確性無疑是一個技術挑戰。那麼如何解決問題呢?接下來,就和小編一起來看看騰訊雲中介軟體CKafka如何為騰訊課堂百萬級訊息提供技術支撐。
背景
兩年前,騰訊線上教育部就在探索如何實現架構轉型。在梳理過騰訊課堂初始技術架構的痛點後,規劃出架構演進的三個重點方向:微服務、中介軟體、DevOps。尤其在訊息中介軟體的選取上,從自研Hippo訊息佇列切換到雲CKafka。這主要歸於以下幾點原因:
- 實現技術棧的統一,降低元件適配成本。
- 使用符合開源標準的元件,便於系統切換優秀的開源元件。
- CKafka具備高效能、高可用性和高可靠性的特點:免除複雜的引數配置,提供專業的效能調優;磁碟高可靠,即使伺服器壞盤50%也不影響業務;多副本備份,更有多可用區容災方案可選,零感知服務遷移。
- CKafka提供安全的資料保障:提供鑑權與授權機制、主子賬號等功能,為企業資料做好安全防護。
在剛剛過去的2019年,騰訊線上教育部已全面實現了業務上雲,不僅提升了團隊研發效率,還實現了快速交付。同時,CKafka在訊息流處理上的高效能特點得以實踐驗證。
而現在,疫情當前,面對全國千萬師生同時線上的線上課堂,互動訊息猛增至百萬級別,無疑對線上教育平臺的穩定性提出更高要求。為了保證線上課堂廣大師生的穩定互動,CKafka作為騰訊課堂的底層訊息支撐,在訊息的實時性和可靠性上提供了更優化的技術方案。
騰訊課堂線上課程頁面
CKafka在騰訊課堂的實踐
Ckafka在騰訊課堂系統架構中的應用是非常典型的場景,即訊息匯流排和業務解耦。使用了GB頻寬、TB儲存規格的例項。我們先來看一下CKafka作為訊息匯流排在騰訊課堂的架構中所處的位置,如下圖:
從架構圖可知,CKafka處於訊息管道的中心位置。同時接收多個訊息源資料,等待下游元件的訂閱消費。並利用其自身高分散式、高吞吐、高可靠的特性,實現流量削峰和業務解耦。騰訊課堂中的聊天訊息、簽到、舉手、獻花、答題卡等功能都使用了該能力。
線上課堂的業務場景不允許出現如訊息延遲、資料丟失等情況,否則就會立刻被線上課堂的師生們感知業務的不穩定,造成不良的使用者體驗。我們來假設一個場景:老師在課堂釋出一個問題,學生們舉手回答問題,如果老師發出的訊息出現延時或丟失的情況,學生們就不能收到訊息,無法及時給老師反饋問題答案,線上課堂的互動效果就會很差,嚴重影響課堂教學質量。
如何避免上述問題呢?我們從CKafka保障訊息的實時性和可靠性兩方面進行闡述。
訊息的實時性
Apache Kafka架構上設計的底層資料讀寫和儲存是以分割槽為最小單位進行的。首先來看一下Kafka Topic的生產消費模型。
如上圖所示,生產者將資料寫入到分佈在叢集內不同節點的不同分割槽上,一個或多個消費者從多臺Borker的分割槽上消費訂閱資料。
從這個模型可知,如果資料的讀寫都集中在單個分割槽上,則Topic的的所有壓力都會集中在該分割槽上,從而落到單臺Broker上面。假設單臺機器能承受的流量是300MB,則此時以騰訊教育的GB/s的流量規模,則會出現訊息處理過慢,會導致訊息延時。那怎麼辦呢?此時就應該提升分割槽的數量,提高資料處理的並行度,從而將整個topic的壓力均分到多臺機器上。
這時就會有一個疑問,Topic需要多少分割槽合適呢?是不是越多的分割槽越好呢?
影響分割槽數量的因素
從生產者的角度來看,資料向不同的分割槽寫入是完全並行的;從消費者的角度來看,併發數完全取決於分割槽的數量(如果 consumer 數量大於 分割槽 數量,則必有 consumer 閒置)。因此選取合適的分割槽對於發揮 CKafka 例項的效能十分重要。
Topic的分割槽數量是由多種因素決定的,一般可以根據以下幾個因素綜合考慮:
- 生產者的峰值頻寬
假設單機單partiton的生產消費吞吐各自最高為300,峰值生產頻寬是900MB,則單純生產至少需要3個Partiton。
- 消費者的峰值頻寬
有人可能會覺得消費的峰值頻寬應該等於生產的峰值頻寬。這樣是不對的。生產者只會生產一份資料,但是可以有N個消費者消費同一份資料,則此時消費頻寬=N*生產頻寬。 另外如果是離線計算,可能會在某一時刻,消費歷史所有資料,此時消費頻寬可能會遠遠高於生產頻寬。 此時如果Topic只設計3個分割槽就有問題了。假設消費峰值頻寬是生產頻寬的2倍。則此時至少需要6個分割槽。
- 消費者的處理能力
假設建立了6個分割槽。此時6個分割槽最多隻會有6個消費者,每個消費者最多每秒可以從Kafka Server拉到300MB的資料。但是每個消費者因為還需處理業務邏輯的關係,只能消費100MB的資料,這樣就會容易導致出現消費堆積的情況。 為了增大消費能力,則需要多加入消費者。因為Kafka的consumer group機制裡同一個消費組裡同一個分割槽只能被一個消費者消費。所以,就應該增大分割槽的數量。為滿足如上需求,此時至少需要18個分割槽,18個消費者,才能滿足消費需求。
在上面的Case中,分割槽數的設計也需要存在一定的冗餘,因為很多情況下,效能是無法達到最優的。所以,分割槽數量需要綜合考慮多個因素,可以適當的多一點分割槽數量,以提高例項的效能。但也不能太大,太大也會導致一系列的其他問題。
選取合適的分割槽數量
考慮到上面提到的實際因素,是否有一個相對簡單的判斷方法來設計分割槽數量呢?
在理想情況下,可以通過如下公式來判斷分割槽的數目:
Num = max( T/PT , T/CT ) = T / min( PT , CT )
複製程式碼
其中,Num 代表分割槽數量,T 代表目標吞吐量,PT 代表生產者寫入單個 分割槽 的最大吞吐,CT 代表消費者從單個分割槽消費的最大吞吐。則分割槽數量應該等於 T/PT 和 T/CT 中的較大值。
在實際情況中,生產者寫入分割槽的最大吞吐 PT 的影響因素和批處理的規模、壓縮演算法、確認機制、副本數等有關。消費者從單個分割槽消費的最大吞吐 CT 的影響因素和業務邏輯有關,需要在不同場景下實測得出。
通常建議分割槽的數量一定要大於等於消費者的數量來實現最大併發。 如果消費者數量為5,則分割槽的數目也應該 ≥ 5 的。但需要注意的是:過多的分割槽會導致生產吞吐的降低和選舉耗時的增加,因此也不建議過多分割槽。
提供如下資訊供參考:
- 單個分割槽是可以實現訊息的順序寫入的。
- 單個分割槽只能被同消費者組的單個消費者程式消費。
- 單個消費者程式可同時消費多個分割槽,即分割槽限制了消費端的併發能力。
- 分割槽越多,當Leader節點失效後,其他分割槽重新進行Leader選舉的耗時就會越長。
- 分割槽的數量是可以動態增加的,只能增加不能減少。但增加會出現訊息 rebalance 的情況。
在上述方法的基礎上,我們還綜合考慮了騰訊課堂的生產消費峰值頻寬、消費的行為特徵和單個消費者的消費能力等因素,為其設計了合理的分割槽數量,以滿足其對訊息實時性的要求。
訊息的可靠性
訊息的可靠性從不同的角度看是不一樣的。從Apache Kafka自身角度看來,訊息的可靠性是訊息的可靠儲存。從業務的角度來看,訊息的可靠性是指訊息傳輸、儲存、消費的可靠性。
從服務提供商來看,我們希望訊息的可靠性是站在客戶這一邊的,即可靠的傳輸,儲存,消費。CKafka在做好可靠性儲存的基礎上,還從配置調優、異常告警等方面儘量做到訊息的可靠傳輸和消費。
關於副本
在介紹下面的方案前,我們先聊聊一下副本。為什麼要有副本的存在呢?
在分散式的場景下,資料損壞和機械故障是被認為常見事件。資料副本是指在不同節點上持久化同一份資料,當某一個節點上儲存的資料丟失時,可以從副本上讀取該資料,這是解決分散式系統資料丟失問題最為有效的方法。
那麼我們來思考下:有多少個副本的資料才是安全的?理論上2個副本就可以大概率範圍的保證資料安全,但是當兩個副本都損壞時,資料也會丟失,此時就需要更多的副本,或者需要副本跨可用區、跨地域分佈。當然更多的副本就意味著要儲存更多的資料,需要更高的成本投入。所以使用者需要在冗餘和安全之間權衡出一種平衡。這也是騰訊雲上建立topic需要使用者指定副本數量的原因,如下圖:
服務端的可靠性
假設TopicA有3個分割槽,每個分割槽有三個副本。來看一下如下的Topic分割槽分佈示意圖。
如圖所示,三個分割槽和三個副本均勻的分佈在三個Broker中,每臺Broker分佈了一個分割槽的Leader分割槽。從上一節關於副本的描述可知,除非所有的Broker在同一時間掛掉,否則即使同時掛掉2臺Borker,服務也可以正常執行。而在我們當前的運營架構中,三臺broker同時掛掉的概率微乎其微,當然如果真的出現這種情況,那就是整個機房掛掉了。
為了避免整個機房掛掉的情況,騰訊雲Ckafka也可以配置跨機房容災和跨可用區容災,來保證資料的可靠性。關於跨可用區容災相關的技術點可以查閱:《蘑菇街千億級訊息Kafka上雲實踐》。
我們可以通過引數配置來儘可能的保證可靠性傳輸和消費,用告警來做兜底策略,讓研發感知介入處理。下面來看一下生產和消費端的引數調優。
客戶端引數調優
生產的可靠傳輸,主要來看一下如下三個配置: ack、retries。
- ack
Kafka producer 的 ack 有 3 種機制,分別說明如下:
-1:Broker 在 leader 收到資料並同步給所有 ISR 中的 follower 後,才應答給 Producer 繼續傳送下一條(批)訊息。 這種配置提供了最高的資料可靠性,只要有一個已同步的副本存活就不會有訊息丟失。
0:生產者不等待來自 broker 同步完成的確認,繼續傳送下一條(批)訊息。這種配置生產效能最高,但資料可靠性最低(當伺服器故障時可能會有資料丟失) 。
1:生產者在 leader 已成功收到的資料並得到確認後再傳送下一條(批)訊息。這種配置是在生產吞吐和資料可靠性之間的權衡(如果leader已死但是尚未複製,則訊息可能丟失)
使用者不顯式配置時,預設值為1。如果是需要可靠性要求高的,建議設定為-1。設定為-1會影響吞吐的效能。
- retries
請求發生錯誤時重試次數,建議將該值設定為大於0,失敗重試最大程度保證訊息不丟失。
消費的穩定,看一下以下配置,主要避免重複消費和頻繁的消費組Rebalance:
- auto.offset.reset
表示當Broker端沒有offset(如第一次消費或 offset超過7天過期)時如何初始化 offset。earliest:表示自動重置到 分割槽 的最小 offset
latest:預設為 latest,表示自動重置到分割槽的最大 offset
none:不自動進行 offset 重置,丟擲 OffsetOutOfRangeException 異常
預設值為latest。當設定為earliest的時候,需要注意的是:當offset失效後,就會從現存的最早的資料開始消費的情況,可能會出現資料重複消費的情況。
- session.timeout.ms
使用 Kafka 消費分組機制時,消費者超時的時間。當 Broker 在該時間內沒有收到消費者的心跳時,就會認為該消費者發生故障,Broker 發起重新 Rebalance 過程。目前該值的在 Broker 的配置必須在group.min.session.timeout.ms=6000和group.max.session.timeout.ms=300000 之間。
- heartbeat.interval.ms
使用 Kafka 消費分組機制時,消費者傳送心跳的間隔。這個值必須小於 session.timeout.ms,一般小於它的三分之一。
- max.poll.interval.ms
使用 Kafka 消費分組機制時,再次呼叫 poll 允許的最大間隔。如果在該時間內沒有再次呼叫 poll,則認為該消費者已經失敗,Broker 會重新發起 Rebalance 把分配給它的分割槽 分配給其他消費者。
引數調優只能最大程度保證服務的可用,並不能保證服務的百分百可用。客戶端需要具有捕獲生產,消費等行為異常的行為。當出現異常時,能夠告警,以便人工處理。這樣才能最大的保證業務的高可用。
CKafka的其他優勢
CKafka除了作為訊息管道幫助業務實現資料解耦、流量削峰外,還可以在其他場景有所作為。
日誌分析系統
CKafka 結合大資料套件 EMR,可構建完整的日誌分析系統。首先通過部署在客戶端的 agent 進行日誌採集,並將資料聚合到訊息佇列 CKafka,之後通過後端的大資料套件如 Spark 等進行資料的多次計算消費,並且對原始日誌進行清理,落盤儲存或進行圖形化展示。
流資料處理平臺
CKafka 結合流計算 SCS , 可用於實時/離線資料處理及異常檢測,滿足不同場景需要:
- 對實時資料進行分析和展示,並做異常檢測,快速定位系統問題。
- 消費歷史資料進行落盤儲存和離線分析,對資料進行二次加工,生成趨勢報表等。
結語
騰訊雲CKafka作為高效能、高吞吐量的訊息中介軟體,為千萬師生有序穩定的線上課堂提供了效能支撐,有效的解決了資料的實時性和可靠性問題。特別是在業務故障時,可實現快速擴縮容,並以其全面的容錯機制和故障處理機制為使用者提供解決方案。
在2020年突如其來的疫情期間,CKafka將與騰訊課堂一起努力,為莘莘學子們百萬級的課堂互動訊息做好技術支撐,為構建良好的線上課堂體驗貢獻一份力量。
作者簡介
許文強, 騰訊雲中介軟體訊息佇列資深研發工程師。騰訊雲Ckafka核心研發,擁有多年分散式系統研發經驗。主要負責騰訊雲CKafka定製化開發及優化工作。專注於Kafka在公有云多租戶和大規模叢集場景下的效能分析和優化。
歡迎掃碼關注我們的微信公眾號,期待與你相遇~