實時數據倉庫必備技術:Kafka 知識梳理

-     爲什麼使用消息隊列?     -

(1) 解耦

現有系統 A,B,C,系統 B 和 C 需要系統 A 的數據,然後我們就修改系統 A 的代碼,給系統 B,C 發送數據。這時系統 D 也需要系統 A 的數據,我們又要修改系統 A 的代碼,給系統 D 發送數據。如果這時系統 B 不需要系統 A 的數據了呢? 簡直崩潰了,新增或減少一個系統,我們都要去修改系統 A 的代碼,而且我們還需要考慮調用的系統掛掉了怎麼辦,是否要將數據存起來,是否要重發等等,這是非常不合理的一種設計,我們需要引入消息隊列。

引入消息隊列後,系統 A 產生的數據直接發送到消息隊列中,哪個系統需要系統 A 的數據就直接去消息隊列中消費,這樣系統 A 就和其他系統徹底解耦了。

(2) 異步

客戶端調用 A 系統的一個接口處理某個功能,該功能需要調用 B,C,D 系統進行處理,如果 A 系統自身耗時爲 20ms,B,C,D 系統耗時分別是 300ms,450ms,200ms,最終接口返回時總共耗時 970ms,這肯定是不可接受的,我們需要引入消息隊列。

引入消息隊列後,系統 A 將消息發送到消息隊列中就可以直接返回,接口總共耗時很短,用戶體驗非常棒。

(3) 削峯

在高併發場景下 (比如秒殺活動) 某一刻的併發量會非常高,如果這些請求全部到達 MySQL,會導致 MySQL 崩潰,這時我們需要引入消息隊列,先將請求積壓到消息隊列中,讓 MySQL 正常處理。

-     消息隊列有什麼優缺點     -

(1) 優點

(2) 缺點

ActiveMQ、RabbitMQ、Kafka、RocketMQ 優點和缺點

(1) ActiveMQ 和 RabbitMQ 單擊吞吐量是萬級,Kafka 和 RocketMQ 的單機吞吐量是 10 萬級。

(2) 四種 MQ 的時效性,可用性,消息可靠性都很高。

(3) ActiveMQ 的社區不太活躍,其他三種 MQ 的社區比較活躍。

(4) RabbitMQ 是基於 Erlang 語言開發,對 Java 開發者不太友好。

(5) Kafka 當 topic 數量達到 1000 時吞吐量會大幅度下降,而 RocketMQ 影響不太 (這是 RocketMQ 相對於 Kafka 的一大優勢)。

(6) Kafka 的功能簡單,吞吐量高,天然適合大數據實時計算以及日誌採集。

-     如何保證消息隊列的高可用     -

回答自己熟悉的消息隊列,如 Kafka。

Kafka 是一個分佈式的消息隊列,一個 topic 有多個 partition,每個 partition 分佈在不同的節點上。此外,Kafka 還可以爲 partition 配置副本機制,一個主副本對外提供服務,多個從副本提供冷備功能 (即只起備份作用,不提供讀寫)。

(1) 從副本爲什麼不提供讀寫服務,只做備份?

因爲如果 follower 副本也提供寫服務的話,那麼就需要在所有的副本之間相互同步。n 個副本就需要 n x n 條通路來同步數據,如果採用異步同步的話,數據的一致性和有序性是很難保證的,而採用同步方式進行數據同步的話,那麼寫入延遲其實是放大 n 倍的,反而適得其反。

(2) 從服務爲什麼不提供讀服務呢?

這個除了因爲同步延遲帶來的數據不一致之外,不同於其他的存儲服務(如 ES,MySQL),Kafka 的讀取本質上是一個有序的消息消費,消費進度是依賴於一個叫做 offset 的偏移量,這個偏移量是要保存起來的。如果多個副本進行讀負載均衡,那麼這個偏移量就不好確定了。

總結一下,從副本不提供讀寫服務的原因就是很難保證數據的一致性與有序性,而且也沒必要提供讀寫服務,Kafka 是一個消息隊列,副本的作用是保證消息不丟失。

partition 主從副本數據同步

生產者發佈消息到某個分區時,先通過 ZooKeeper 找到該分區的 leader 副本,然後將消息只發送給 leader 副本,leader 副本收到消息後將其寫入本地磁盤。接着每個 follower 副本都從 leader 副本上 pull 消息,follower 副本收到消息後會向 leader 副本發送 ACK(acknowledge)。一旦 leader 副本收到了 ISR (in-sync replicas) 中的所有副本的 ACK,該消息就被認爲已經 commit 了,然後 leader 副本向生產者發送 ACK。消費者讀消息只會從 leader 副本中讀取,只有被 commit 過的消息纔會暴露給消費者。

ISR(in-sync replicas) 是與 leader 副本保持同步狀態的 follower 副本列表,如果一段時間內 (replica。lag。time。max。ms) leader 副本沒有收到 follower 副本的拉取請求,就會被 leader 副本從 ISR 中移除。ISR 中的副本數必須大於等於 min。insync。replicas,否則 producer 會認爲寫入失敗,進行消息重發。

主副本選舉

當 leader 副本掛掉後,集羣控制器 (即 Master 節點) 會從 ISR 中選出一個新的主副本(ISR 中的第一個,不行就依次類推 )。

集羣控制器選舉

集羣中的第一個 broker 通過在 Zookeeper 的 /controller 路徑下創建一個臨時節點來成爲控制器,當其他 broker 啓動時,也會試圖創建一個臨時節點,但是會收到 “節點已存在” 的異常,這樣便知道集羣控制器已存在。這些 broker 會監聽 Zookeeper 的這個控制器臨時節點,當控制器發生故障時,該臨時節點會消失,這些 broker 便會收到通知,然後嘗試去創建臨時節點成爲新的控制器。

如何保證消息不被重複消費(如何保證消息消費時的冪等性)?

(1) 導致消息重複消費的原因? 分區重平衡消費者重啓或宕機這兩個原因都會導致消費者在消費消息後沒有提交 offset。

(2) 解決辦法這個問題只能通過業務手段來解決,比如我們在消費前先查詢數據庫,判斷是否已消費 (status = 1),或消費後在 Redis 中做個記錄,下次消費前先從 Redis 中判斷是否已消費。

如果保證消息不丟失 (如何保證消息的可靠性傳輸)?

(1) 導致消息丟失的原因?

kafka 沒有保存消息。消費者還沒消費就提交了 offset,然後消費者重啓或宕機,分區重平衡。

(2) 解決辦法

配置 partition 副本機制。

•default。replication。factor 每個分區的副本數必須大於 1。

•min。insync。replicas 與主副本保存同步狀態的從副本數必須大於等於 1。

•Producer 端的配置 acks=all,指數據寫入 min。insync。replicas 個從副本後纔算寫入成功。

•Producer 端的配置 retries=MAX(一個很大的值,表示無線重試的意思),指數據一旦寫入失敗,就無限重試。關閉自動提交 offset,改爲手動提交。先消費,消費成功後再手動提交 offset。

-     如何保證消息的順序性?     -

kafka 只保證單個分區內的消息有序,所以要想保證消息的順序性,只能一個 topic,一個 partition,一個 consumer。

如果在 consumer 端開多個線程來進行消費,如何保證消息的順序性?

一個 topic,一個 partition,一個 consumer,consumer 內部單線程消費,寫 N 個內存 queue,然後開 N 個線程分別消費一個內存 queue 中的消息。

消息隊列快寫滿了怎麼辦?

一般出現這種問題的原因就是消費端出了故障,導致無法消費或消費極慢,這時有兩種解決辦法,根據不同的場景選擇不同的解決辦法。

(1) 緊急擴容臨時徵用 10 倍的機器來部署 consumer,新建一個 topic,partition 是原來的 10 倍。寫一個臨時分發數據的 consumer 程序,將積壓的數據不做處理,直接分發給臨時建好的 topic。以 10 倍的速度消費積壓的消息,消費完之後再恢復原來的部署。

(2) 批量重導寫一個臨時分發數據的 consumer 程序,將積壓的數據直接丟棄。等高峯期過後,寫個臨時程序,將丟失的那批數據重新導入消息隊列中。

**
如果讓你自己寫一個消息隊列,該如何進行架構設計?**

我們可以用 Kafka 的架構設計來回答這個問題。

(1) 分佈式這個消息隊列必須分佈式的,這樣通過水平擴展集羣就可以增加消息隊列的吞吐量與容量。分佈式的消息隊列必須要有一個 master 節點來管理整個集羣,可以通過 Zookeeper 來實現 master 節點選舉算法。

(2) 可用性一個 topic 必須支持多個 partition,且 partition 數量可以增加,每個 partition 分佈在不同的節點上。partition 內通過 offset 來保證消息的順序。同時爲了保證可用性,每個分區必須設置副本,主副本提供讀寫服務,從副本只作備份即可。當主副本所在的節點宕機後,master 節點會在從副本中選出一個作爲主副本,然後當宕機的節點修復後,master 節點會將缺失的副本分配過去,同步數據後,集羣恢復正常。

(3) 高性能爲了保證高吞吐量,我們可以使用批量壓縮,順序寫,零拷貝技術。

(4) 解決消息丟失方案消息必須寫入所有副本中才算寫入成功。

-     Kafka 爲什麼速度那麼快?     -

我們都知道 Kafka 的核心特性之一就是高吞吐率,但 Kafka 的數據是存儲在磁盤上的,一般認爲在磁盤上讀寫數據性能很低,那 Kafka 是如何做到高吞吐率的呢?

Kafka 高吞吐率的祕訣在於,它把所有的消息都進行批量壓縮,提升網絡 IO,通過順序寫和零拷貝技術提升磁盤 IO。

作者:椰子 Tyshawn

來源:

https://blog.csdn.net/litianxiang_kaola/article/details/104138183

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/OZspOzSdA1aUoy0C4-XArQ