你猜:為什麼Kafka不支援讀寫分離
在 Kafka 中,生產者寫入訊息、消費者讀取訊息的操作都是與 leader 副本進行互動的,從 而實現的是一種主寫主讀的生產消費模型。資料庫、Redis 等都具備主寫主讀的功能,與此同時還支援主寫從讀的功能,主寫從讀也就是讀寫分離,為了與主寫主讀對應,這裡就以主寫從讀來稱呼。Kafka 並不支援主寫從讀,這是為什麼呢?
從程式碼層面上來說,雖然增加了程式碼複雜度,但在 Kafka 中這種功能完全可以支援。對於 這個問題,我們可以從“收益點”這個角度來做具體分析。主寫從讀可以讓從節點去分擔主節 點的負載壓力,預防主節點負載過重而從節點卻空閒的情況發生。但是主寫從讀也有 2 個很明 顯的缺點:
-
(1)資料一致性問題。資料從主節點轉到從節點必然會有一個延時的時間視窗,這個時間 視窗會導致主從節點之間的資料不一致。某一時刻,在主節點和從節點中 A 資料的值都為 X, 之後將主節點中 A 的值修改為 Y,那麼在這個變更通知到從節點之前,應用讀取從節點中的 A 資料的值並不為最新的 Y,由此便產生了資料不一致的問題。
-
(2)延時問題。類似 Redis 這種元件,資料從寫入主節點到同步至從節點中的過程需要經 歷網路→主節點記憶體→網路→從節點記憶體這幾個階段,整個過程會耗費一定的時間。而在 Kafka 中,主從同步會比 Redis 更加耗時,它需要經歷網路→主節點記憶體→主節點磁碟→網路→從節 點記憶體→從節點磁碟這幾個階段。對延時敏感的應用而言,主寫從讀的功能並不太適用。
現實情況下,很多應用既可以忍受一定程度上的延時,也可以忍受一段時間內的資料不一 致的情況,那麼對於這種情況,Kafka 是否有必要支援主寫從讀的功能呢?
主寫從讀可以均攤一定的負載卻不能做到完全的負載均衡,比如對於資料寫壓力很大而讀 壓力很小的情況,從節點只能分攤很少的負載壓力,而絕大多數壓力還是在主節點上。而在 Kafka 中卻可以達到很大程度上的負載均衡,而且這種均衡是在主寫主讀的架構上實現的。我們來看 一下 Kafka 的生產消費模型,如下圖所示。
在 Kafka 叢集中有 3 個分割槽,每個分割槽有 3 個副本,正好均勻地分佈在 3個 broker 上,灰色陰影的代表 leader 副本,非灰色陰影的代表 follower 副本,虛線表示 follower 副本從 leader 副本上拉取訊息。當生產者寫入訊息的時候都寫入 leader 副本,對於圖 8-23 中的 情形,每個 broker 都有訊息從生產者流入;當消費者讀取訊息的時候也是從 leader 副本中讀取 的,對於圖 8-23 中的情形,每個 broker 都有訊息流出到消費者。
我們很明顯地可以看出,每個 broker 上的讀寫負載都是一樣的,這就說明 Kafka 可以通過 主寫主讀實現主寫從讀實現不了的負載均衡。上圖展示是一種理想的部署情況,有以下幾種 情況(包含但不僅限於)會造成一定程度上的負載不均衡:
-
(1)broker 端的分割槽分配不均。當建立主題的時候可能會出現某些 broker 分配到的分割槽數 多而其他 broker 分配到的分割槽數少,那麼自然而然地分配到的 leader 副本也就不均。
-
(2)生產者寫入訊息不均。生產者可能只對某些 broker 中的 leader 副本進行大量的寫入操 作,而對其他 broker 中的 leader 副本不聞不問。
-
(3)消費者消費訊息不均。消費者可能只對某些 broker 中的 leader 副本進行大量的拉取操 作,而對其他 broker 中的 leader 副本不聞不問。
-
(4)leader 副本的切換不均。在實際應用中可能會由於 broker 宕機而造成主從副本的切換, 或者分割槽副本的重分配等,這些動作都有可能造成各個 broker 中 leader 副本的分配不均。
對此,我們可以做一些防範措施。針對第一種情況,在主題建立的時候儘可能使分割槽分配 得均衡,好在 Kafka 中相應的分配演算法也是在極力地追求這一目標,如果是開發人員自定義的 分配,則需要注意這方面的內容。對於第二和第三種情況,主寫從讀也無法解決。對於第四種 情況,Kafka 提供了優先副本的選舉來達到 leader 副本的均衡,與此同時,也可以配合相應的 監控、告警和運維平臺來實現均衡的優化。
在實際應用中,配合監控、告警、運維相結合的生態平臺,在絕大多數情況下 Kafka 都能 做到很大程度上的負載均衡。總的來說,Kafka 只支援主寫主讀有幾個優點:可以簡化程式碼的 實現邏輯,減少出錯的可能;將負載粒度細化均攤,與主寫從讀相比,不僅負載效能更好,而 且對使用者可控;沒有延時的影響;在副本穩定的情況下,不會出現資料不一致的情況。為此, Kafka 又何必再去實現對它而言毫無收益的主寫從讀的功能呢?這一切都得益於 Kafka 優秀的 架構設計,從某種意義上來說,主寫從讀是由於設計上的缺陷而形成的權宜之計。