RabbitMQ 與 Kafka:容錯性和高可用性

RabbitMQ 與 Kafka:容錯性和高可用性

В 上一篇文章 我們研究了 RabbitMQ 叢集的容錯性和高可用性。 現在讓我們深入研究 Apache Kafka。

這裡的複製單位是分區。 每個主題都有一個或多個部分。 每個部分都有一個領導者,有或沒有追隨者。 建立主題時,您指定分割區數和複製係數。 通常值為 3,表示三個副本:一個領導者和兩個追隨者。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 1. 四個部分分佈在三個經紀商之間

所有的讀寫請求都會發送給領導者。 Followers 定期向 Leader 發送請求以接收最新訊息。 消費者永遠不會轉向追隨者;追隨者的存在只是為了冗餘和容錯。

RabbitMQ 與 Kafka:容錯性和高可用性

分區失敗

當一個經紀人失敗時,幾個部門的領導者往往都會失敗。 在每個節點中,來自另一個節點的追隨者成為領導者。 事實上,情況並非總是如此,因為同步因素也會影響:是否有同步的跟隨者,如果沒有,則是否允許切換到不同步的副本。 但現在我們不要讓事情變得複雜。

經紀人 3 離開網絡,經紀人 2 為第 2 部分選舉了一位新的領導者。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 2. Broker 3 死亡,其在 Broker 2 上的追隨者被選為分區 2 的新領導者

然後,經紀人 1 離開,部分 1 也失去了領導者,其角色轉移到經紀人 2。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 3. 還剩一名經紀人。 所有領導者都在一個經紀人上,零冗餘

當代理 1 重新上線時,它會添加四個追隨者,為每個分區提供一些冗餘。 但所有領導者仍然留在經紀人 2 上。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 4. 領導者仍留在經紀商 2 上

當代理 3 出現時,我們又回到每個分割區三個副本。 但所有領導者仍然在經紀人 2 上。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 5. 經紀商 1 和 3 恢復後領導者安置不平衡

Kafka 有一個比 RabbitMQ 更好的領導者再平衡工具。 在那裡,您必須使用第三方外掛程式或腳本,透過減少遷移期間的冗餘來更改遷移主節點的策略。 此外,對於大型隊列,我們必須接受同步期間不可用的情況。

Kafka 對於領導者角色有「首選副本」的概念。 在建立主題分區時,Kafka 會嘗試在節點之間均勻分佈領導者,並將這些第一個領導者標記為首選。 隨著時間的推移,由於伺服器重新啟動、故障和連線中斷,領導者可能最終會出現在其他節點上,就像上面描述的極端情況一樣。

為了解決這個問題,Kafka 提供了兩種選擇:

  • 選項 auto.leader.rebalance.enable=true 允許控制節點自動將領導者重新分配回首選副本,從而恢復均勻分佈。
  • 管理員可以執行該腳本 kafka-preferred-replica-election.sh 用於手動重新分配。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 6. 重新平衡後的副本

這是失敗的簡化版本,但現實要複雜得多,儘管這裡並沒有什麼太複雜的。 這一切都歸結為同步副本(In-Sync Replicas,ISR)。

同步副本 (ISR)

ISR 是被視為「同步」(同步)的分區的一組副本。 有領導者,但不一定有追隨者。 如果追隨者在間隔到期之前準確地複製了所有領導者的訊息,則被認為是同步的 副本.延遲時間.最大.ms.

如果某個追蹤者出現以下情況,則會從 ISR 集中刪除:

  • 沒有提出選擇間隔的請求 副本.延遲時間.最大.ms (推定死亡)
  • 期間未能更新 副本.延遲時間.最大.ms (認為很慢)

追蹤者在該時間間隔內提出採樣請求 副本.fetch.wait.max.ms,預設為 500ms。

為了清楚解釋 ISR 的目的,我們需要查看生產者的確認和一些失敗場景。 生產者可以選擇經紀人何時發送確認:

  • acks=0,不發送確認
  • acks=1,領導者向本地日誌寫入訊息後發送確認
  • acks=all,ISR中的所有副本都將訊息寫入本機日誌後發送確認

在 Kafka 術語中,如果 ISR 保存了一條訊息,那麼它就是「已提交」。 Acks=all 是最安全的選項,但也會增加額外的延遲。 讓我們來看看兩個失敗範例以及不同的「ack」選項如何與 ISR 概念互動。

Acks=1 和 ISR

在這個例子中,我們將看到,如果領導者不等待所有追隨者的每個訊息都被保存,那麼如果領導者失敗,資料可能會遺失。 可以透過設定啟用或停用導覽至未同步的追蹤者 不乾淨的領導者選舉啟用.

在此範例中,製造商的值 acks=1。 該部分分佈在所有三個經紀商中。 Broker 3 落後了,它在八秒前與領導者同步,現在落後了 7456 條訊息。 經紀人 1 僅落後一秒。 我們的生產者發送一條訊息並快速收到返回的確認,而不會產生領導者不等待的緩慢或死追隨者的開銷。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 7. 具有三個副本的 ISR

Broker 2 失敗,生產者收到連線錯誤。 在領導權傳遞給代理 1 後,我們遺失了 123 則訊息。 經紀商 1 上的追隨者是 ISR 的一部分,但在下跌時與領導者並不完全同步。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 8.崩潰時訊息遺失

配置中 引導伺服器 製造商列出了多位經紀人,可以詢問另一位經紀人誰是新的部門領導者。 然後它與代理 1 建立連接並繼續發送訊息。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 9. 短暫中斷後恢復發送訊息

Broker 3 甚至更落後。 它發出提取請求但無法同步。 這可能是由於代理之間的網路連接速度慢、儲存問題等造成的。它已從 ISR 中刪除。 現在 ISR 由一個副本組成 - 領導者! 製造商繼續發送訊息並接收確認。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 10. 經紀商 3 上的追隨者已從 ISR 中刪除

代理 1 宕機,領導角色轉移到代理 3,並丟失 15286 則訊息! 製造商收到連線錯誤訊息。 過渡到 ISR 之外的領導者只有在以下情況下才可能實現: unclean.leader.election.enable=true。 如果它安裝在 ,則不會發生轉換,並且所有讀寫請求都將被拒絕。 在這種情況下,我們等待代理 1 返回副本中完整的數據,該副本將再次接管領導權。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 11. 經紀人 1 倒閉。 當發生故障時,大量訊息遺失

製作人與最後一位經紀人建立了連接,並發現他現在是該部分的領導者。 他開始向經紀人 3 發送訊息。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 12. 短暫休息後,訊息再次發送到section 0

我們看到,除了建立新聯繫和尋找新領導者的短暫中斷外,製造商還在不斷發送訊息。 此配置以犧牲一致性(資料安全性)為代價來確保可用性。 卡夫卡丟失了數千條訊息,但繼續接受新的寫入。

Acks=全部和 ISR

讓我們再次重複這個場景,但是 確認=全部。 代理 3 的平均延遲為四秒。 製造商發送一條訊息 確認=全部,現在沒有收到快速回覆。 領導者等待 ISR 中所有副本保存訊息。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 13. 具有三個副本的 ISR。 一是速度慢,導致錄影延遲

經過四秒的額外延遲後,代理 2 發送一個確認。 所有副本現已完全更新。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 14.所有副本保存訊息並發送ack

Broker 3 現在進一步落後並已從 ISR 中刪除。 由於 ISR 中沒有留下慢速副本,因此延遲顯著減少。 經紀人 2 現在只等待經紀人 1,他的平均延遲為 500 毫秒。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 15. 代理 3 上的副本已從 ISR 中刪除

然後代理 2 崩潰,領導權轉移給代理 1,且不會遺失訊息。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 16.經紀人2倒下

製造商找到了一位新的領導者並開始向他發送訊息。 延遲進一步減少,因為 ISR 現在由一個副本組成! 因此選項 確認=全部 不增加冗餘。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 17. Broker 1 上的副本領先且不遺失訊息

然後代理 1 崩潰,領先者轉到代理 3,丟失了 14238 則訊息!

RabbitMQ 與 Kafka:容錯性和高可用性
米。 18. 經紀人 1 死亡和領導層過渡與不乾淨的設定導致大量資料遺失

我們無法安裝該選項 不乾淨的領導者選舉啟用 進入意義 。 預設是相等的 。 設定 確認=全部 с unclean.leader.election.enable=true 提供可訪問性並增加一些資料安全性。 但正如您所看到的,我們仍然可能會丟失訊息。

但如果我們想提高資料安全性怎麼辦? 你可以把 unclean.leader.election.enable = false,但這不一定能保護我們免受資料遺失的影響。 如果領導者摔倒並帶走了數據,那麼訊息仍然會遺失,而且可用性也會遺失,直到管理員恢復情況為止。

最好確保所有訊息都是冗餘的,否則丟棄記錄。 那麼,至少從代理的角度來看,只有在兩個或多個同時發生故障的情況下才可能遺失資料。

Acks=all、min.insync.replicas 和 ISR

帶主題配置 最小同步副本數 我們正在提高資料安全等級。 讓我們再次回顧上一個場景的最後部分,但這次 min.insync.replicas=2.

因此,代理 2 有一個副本領導者,代理 3 上的追隨者已從 ISR 中刪除。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 19.來自兩個副本的 ISR

代理 2 崩潰,領導權轉移給代理 1,且不會遺失訊息。 但現在 ISR 僅包含一個副本。 這不滿足接收記錄的最小數量,因此代理會以錯誤回應寫入嘗試 沒有足夠的副本.

RabbitMQ 與 Kafka:容錯性和高可用性
米。 20. ISR的數量比min.insync.replicas中指定的少XNUMX

這種配置犧牲了可用性以換取一致性。 在確認訊息之前,我們確保將其寫入至少兩個副本。 這讓製造商更有信心。 在這裡,只有當兩個副本在很短的時間內同時失敗,直到訊息被複製到另一個跟隨者時,訊息才有可能丟失,而這是不可能的。 但如果你超級偏執,你可以將複製因子設為 5,然後 最小同步副本數 3. 這裡三個經紀人必須同時下跌才能失去紀錄! 當然,您要為這種可靠性付出額外的延遲代價。

當資料安全需要可存取性時

如在 RabbitMQ 案例,有時可訪問性對於資料安全是必要的。 這是你需要考慮的:

  • 發布者是否可以簡單地返回錯誤並讓上游服務或用戶稍後重試?
  • 發布者可以將訊息保存在本機或資料庫中以便稍後重試嗎?

如果答案是否定的,那麼優化可用性可以提高資料安全性。 如果您選擇可用性而不是不記錄,您會遺失更少的資料。 因此,一切都取決於找到一個平衡點,並根據具體情況做出決定。

ISR的意義

ISR 套件可讓您選擇資料安全性和延遲之間的最佳平衡。 例如,確保大多數副本發生故障時的可用性,最大限度地減少死副本或緩慢副本對延遲的影響。

我們自己選擇意義 副本.延遲時間.最大.ms 根據您的需要。 本質上,這個參數意味著我們願意接受多少延遲 確認=全部。 預設值為十秒。 如果這對您來說太長,您可以減少它。 然後,ISR 更改的頻率將會增加,因為追隨者將更頻繁地被刪除和添加。

RabbitMQ 只是一組需要複製的鏡像。 慢速鏡像會引入​​額外的延遲,而死鏡像可以等到檢查每個節點可用性(網路滴答)的封包做出回應。 ISR 是避免這些延遲問題的有趣方法。 但我們面臨失去冗餘的風險,因為 ISR 只能收縮到領導者。 為了避免這種風險,請使用以下設置 最小同步副本數.

客戶端連線保證

在設置中 引導伺服器 生產者和消費者可以指定多個代理來連接客戶端。 這個想法是,當一個節點發生故障時,會留下幾個備用節點,客戶端可以透過它們打開連線。 這些不一定是部門負責人,而只是初始加載的跳板。 客戶端可以詢問哪個節點託管讀取/寫入分區領導者。

在RabbitMQ中,客戶端可以連接到任何節點,內部路由將請求發送到需要去的地方。 這表示您可以在 RabbitMQ 前面安裝負載平衡器。 Kafka 要求客戶端連接到託管對應分區領導者的節點。 在這種情況下,您無法安裝負載平衡器。 清單 引導伺服器 客戶端在發生故障後能夠存取並找到正確的節點至關重要。

卡夫卡共識架構

到目前為止,我們還沒有考慮集群如何獲知 Broker 的故障以及如何選出新的領導者。 要了解 Kafka 如何處理網路分區,首先需要了解共識架構。

每個 Kafka 叢集都與 Zookeeper 叢集一起部署,Zookeeper 叢集是一種分散式共識服務,允許系統就某些給定狀態達成共識,優先考慮一致性而不是可用性。 讀寫操作需要獲得大多數Zookeeper節點的同意。

Zookeeper儲存叢集的狀態:

  • 主題、部分、配置、目前領導者副本、首選副本的清單。
  • 集群成員。 每個代理程式都會 ping Zookeeper 叢集。 如果在指定時間內未收到 ping,Zookeeper 會將代理程式記錄為不可用。
  • 選擇控制器的主節點和備用節點。

控制節點是負責選舉副本領導者的 Kafka 代理人之一。 Zookeeper 向控制器發送有關叢集成員資格和主題變更的通知,並且控制器必須對這些變更採取行動。

例如,我們採用一個具有 3 個分區且複製因子為 XNUMX 的新主題。控制器必須為每個分區選舉一個領導者,嘗試在代理之間最佳地分配領導者。

對於每個部分控制器:

  • 更新 Zookeeper 中有關 ISR 和領導者的信息;
  • 向託管此分割區副本的每個代理程式發送 LeaderAndISRCommand,通知代理程式有關 ISR 和領導者的資訊。

當具有領導者的代理失敗時,Zookeeper 會向控制器發送通知,並選舉新的領導者。 同樣,控制器首先更新 Zookeeper,然後向每個代理程式發送命令,通知他們領導權變更。

每位領導者負責招募 ISR。 設定 副本.延遲時間.最大.ms 決定誰將進入那裡。 當ISR發生變化時,Leader會向Zookeeper發送新的訊息。

Zookeeper 始終會收到任何更改,以便在發生故障時,管理層可以順利過渡到新的領導者。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 21.卡夫卡共識

複製協議

了解複製的詳細資訊有助於您更了解潛在的資料遺失情況。

取樣查詢、對數結束偏移 (LEO) 和高水位線 (HW)

我們認為追隨者會定期向領導者發送獲取請求。 預設間隔為 500 毫秒。 這與 RabbitMQ 的不同之處在於,RabbitMQ 中的複製不是由佇列鏡像發起的,而是由 master 發起的。 主伺服器將變更推送到鏡像。

領導者和所有追隨者保存對數結束偏移 (LEO) 和高水位 (HW) 標籤。 LEO 標記儲存最後一則訊息在本機副本中的偏移量,HW 保存最後一次提交的偏移量。 請記住,對於提交狀態,訊息必須在所有 ISR 副本中持久保存。 這意味著 LEO 通常略領先 HW。

當領導者收到訊息時,會將其儲存在本地。 跟隨者透過傳輸他的 LEO 來發出獲取請求。 然後,領導者從該 LEO 開始發送一批訊息,並傳輸當前的 HW。 當領導者收到所有副本都已在給定偏移量處儲存訊息的資訊時,它會移動 HW 標記。 只有領導者可以移動硬件,因此所有追隨者都會知道對其請求的回應中的當前值。 這意味著追隨者在訊息和硬體知識方面可能落後於領導者。 消費者僅接收當前硬體的訊息。

請注意,「持久化」意味著寫入內存,而不是磁碟。 為了效能,Kafka 以特定的時間間隔同步到磁碟。 RabbitMQ 也有這樣的間隔,但只有在主伺服器和所有映像都將訊息寫入磁碟後,它才會向發布者發送確認。 出於效能原因,Kafka 開發人員決定在訊息寫入記憶體後立即發送 ack。 Kafka 認為冗餘可以抵消僅在記憶體中短暫儲存已確認訊息的風險。

領導失敗

當領導者失效時,Zookeeper 會通知控制器,並選擇新的領導者副本。 新領導者根據他的 LEO 設定了新的 HW 標記。 然後追隨者會收到有關新領導者的信息。 根據 Kafka 的版本,follower 將選擇以下兩個場景之一:

  1. 它將截斷本地日誌到已知的硬件,並向新的領導者發送請求以獲取此標記後的消息。
  2. 會向leader發送請求,找出當選leader時的HW,然後將日誌截斷到這個offset。 然後它將開始從該偏移量開始發出定期獲取請求。

由於以下原因,追蹤者可能需要截斷日誌:

  • 當領導者失敗時,向 Zookeeper 註冊的 ISR 集中的第一個追隨者將贏得選舉並成為領導者。 ISR 上的所有追隨者雖然被認為是“同步”,但可能並未收到前領導者發送的所有訊息的副本。 特色追蹤者完全有可能沒有最新的副本。 Kafka 確保副本之間不存在分歧。 因此,為了避免差異,每個追隨者必須將其日誌截斷為新領導者選舉時的 HW 值。 這是設置的另一個原因 確認=全部 對於一致性非常重要。
  • 訊息會定期寫入磁碟。 如果所有叢集節點同時發生故障,則具有不同偏移量的副本將儲存在磁碟上。 當經紀人重新上線時,當選的新領導者可能會落後於他的追隨者,因為他先於其他人保存到磁碟。

與集群重聚

當重新加入叢集時,副本會執行與領導者失敗時相同的操作:它們檢查領導者的副本並將其日誌截斷到其硬體(在選舉時)。 相較之下,RabbitMQ 同樣將重新組合的節點視為全新的節點。 在這兩種情況下,代理都會丟棄任何現有狀態。 如果使用自動同步,那麼主伺服器必須以「讓全世界等待」的方式將當前所有內容絕對複製到新鏡像。 在此操作期間,主機不接受任何讀取或寫入操作。 這種方法在大隊列中會產生問題。

Kafka 是一種分散式日誌,通常它比 RabbitMQ 佇列儲存更多的訊息,而 RabbitMQ 佇列中的資料在讀取後就會從佇列中刪除。 活動隊列應該保持相對較小。 但Kafka是一個日誌,有自己的保留策略,可以設定幾天或幾週的時間段。 佇列阻塞和全同步的方式對於分散式日誌來說是絕對不能接受的。 相反,如果 Kafka 追隨者的副本領先於領導者,他們只需將他們的日誌截斷到領導者的硬體(在他當選時)。 在更可能的情況下,當跟隨者落後時,它只是開始從當前的 LEO 開始發出獲取請求。

新的或重新加入的追蹤者在 ISR 之外開始,並且不參與提交。 他們只是與小組一起工作,盡快接收訊息,直到追上領導者並進入情監偵。 沒有鎖定,也無需丟棄所有資料。

失去連接

Kafka 比 RabbitMQ 有更多的元件,因此當叢集斷開連接時它有一組更複雜的行為。 但Kafka最初是為集群設計的,所以解決方案是經過深思熟慮的。

以下是幾種連結失敗的場景:

  • 場景1:follower看不到leader,但仍然看到Zookeeper。
  • 場景 2:領導者看不到任何追隨者,但仍然看到 Zookeeper。
  • 場景3:follower看到leader,但看不到Zookeeper。
  • 場景 4:領導者看到追隨者,但看不到 Zookeeper。
  • 場景 5:follower 與其他 Kafka 節點和 Zookeeper 完全分開。
  • 場景 6:領導者與其他 Kafka 節點和 Zookeeper 完全分開。
  • 情境 7:Kafka 控制節點看不到另一個 Kafka 節點。
  • 場景 8:Kafka 控制器看不到 Zookeeper。

每個場景都有自己的行為。

場景1:Follower看不到leader,但仍然看到Zookeeper

RabbitMQ 與 Kafka:容錯性和高可用性
米。 22. 場景一:三個副本的ISR

連線故障使代理 3 與代理 1 和 2 分離,但不與 Zookeeper 分離。 Broker 3 無法再發送提取請求。 時間過去後 副本.延遲時間.最大.ms 它已從 ISR 中刪除,並且不參與訊息提交。 一旦連線恢復,它將恢復獲取請求並在追上領導者時加入 ISR。 Zookeeper 將繼續接收 ping 並假設代理還活著並且運作良好。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 23. 情境 1:如果在replica.lag.time.max.ms 間隔內沒有收到來自代理的提取請求,則從ISR 中刪除代理

沒有像 RabbitMQ 那樣的裂腦或節點暫停。 相反,減少了冗餘。

場景2:Leader看不到任何follower,但仍然看到Zookeeper

RabbitMQ 與 Kafka:容錯性和高可用性
米。 24. 場景 2. 領導者和兩個追隨者

網路連線故障將領導者與追隨者分開,但代理商仍然可以看到 Zookeeper。 與第一種情況一樣,ISR 縮小,但這次僅針對領導者,因為所有追隨者停止發送獲取請求。 再次強調,沒有邏輯上的劃分。 相反,在連線恢復之前,新訊息的冗餘會遺失。 Zookeeper 繼續接收 ping 並相信代理還活著並且運作良好。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 25. 情境 2. ISR 已縮減至僅領導者

場景 3. Follower 看到了 Leader,但看不到 Zookeeper

follower與Zookeeper分離,但與leader的broker不分離。 結果,追隨者繼續發出獲取請求並成為 ISR 的成員。 Zookeeper 不再接收 ping 並註冊代理程式崩潰,但由於它只是一個跟隨者,因此恢復後不會產生任何後果。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 26.場景3:follower持續向leader發送fetch請求

場景 4. Leader 看到了 follower,但沒有看到 Zookeeper

RabbitMQ 與 Kafka:容錯性和高可用性
米。 27. 場景 4. 領導者和兩個追隨者

領導者與 Zookeeper 分離,但與具有追隨者的經紀人不分離。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 28.場景4:Leader與Zookeeper隔離

一段時間後,Zookeeper 將註冊代理故障並通知控制器。 他將從他的追隨者中選出一位新的領導者。 然而,原來的領導者將繼續認為自己是領導者,並將繼續接受來自 確認=1。 追隨者不再向他發送獲取請求,因此他會認為這些請求已死亡並嘗試將 ISR 縮小到自身。 但由於它沒有與 Zookeeper 的連接,因此它無法執行此操作,並且屆時將拒絕接受任何進一步的條目。

Сообщения 確認=全部 將不會收到確認,因為 ISR 首先打開所有副本,並且訊息不會到達它們。 當原來的領導者試圖將它們從 ISR 中刪除時,它將無法做到這一點,並且根本停止接受任何訊息。

客戶端很快就會注意到領導者的變化並開始向新伺服器發送記錄。 一旦網路恢復,原來的領導者發現自己不再是領導者,並將其日誌截斷為新領導者故障時的 HW 值,以避免日誌發散。 然後它將開始向新的領導者發送獲取請求。 原始領導者中未複製到新領導者的所有記錄都會遺失。 也就是說,在兩個領導者工作的幾秒鐘內沒有被原始領導者確認的消息將會遺失。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 29. 情境 4. 網路復原後,broker 1 上的領導者成為跟隨者

情境 5:follower 與其他 Kafka 節點和 Zookeeper 完全分離

follower 與其他 Kafka 節點和 Zookeeper 完全隔離。 他只是將自己從 ISR 中移除,直到網路恢復,然後追上其他人。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 30. 情境 5:從 ISR 中刪除孤立的跟隨者

情境 6:領導者與其他 Kafka 節點和 Zookeeper 完全分開

RabbitMQ 與 Kafka:容錯性和高可用性
米。 31. 場景 6. 領導者和兩個追隨者

領導者與他的追隨者、控制器和動物園管理員完全隔離。 在短時間內,它將繼續接受來自 確認=1.

RabbitMQ 與 Kafka:容錯性和高可用性
米。 32.場景6:將leader與其他Kafka和Zookeeper節點隔離

過期後未收到請求 副本.延遲時間.最大.ms,它會嘗試將 ISR 縮小到自身,但由於沒有與 Zookeeper 通訊而無法這樣做,然後它將停止接受寫入。

同時,Zookeeper 將把孤立的 Broker 標記為死亡,控制器將選出一個新的領導者。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 33. 場景 6. 兩位領導者

原始領導者可能會接受幾秒鐘的條目,但隨後會停止接受任何訊息。 客戶端每 60 秒更新一次最新元資料。 他們將被告知領導者變更,並將開始向新領導者發送條目。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 34. 情境 6:製造商更換新領導者

自失去連接以來由原始領導者所做的所有已確認條目都將丟失。 一旦網路恢復,原來的leader會透過Zookeeper發現自己不再是leader了。 然後它會在選舉時將其日誌截斷到新領導者的硬體上,並開始作為追隨者發送請求。

RabbitMQ 與 Kafka:容錯性和高可用性
米。 35. 場景6:網路連線恢復後,原來的leader變成了follower

在這種情況下,邏輯分離可能會在短時間內發生,但前提是 確認=1 и 最小同步副本數 另外1. 邏輯分離會在網路恢復後,當原始領導者意識到他不再是領導者時,或者當所有客戶端意識到領導者已更改並開始寫入新領導者時自動結束- 以先發生者為準。 無論如何,一些訊息都會丟失,但僅限於 確認=1.

這種情況還有另一種變體,即在網路分裂之前,追隨者落後了,領導者將 ISR 壓縮到只有他自己。 然後由於連接丟失而變得孤立。 新的領導者當選,但原來的領導者繼續接受條目,即使 確認=全部,因為 ISR 裡除了他就沒有其他人了。 一旦網路恢復,這些記錄就會遺失。 避免此選項的唯一方法是 最小同步副本數 = 2.

情境 7:Kafka 控制器節點看不到另一個 Kafka 節點

一般來說,一旦與 Kafka 節點的連線遺失,控制器將無法向其傳輸任何領導者變更資訊。 在最壞的情況下,這將導致短期的邏輯分離,如場景 6 所示。通常,如果後者失敗,經紀人將根本不會成為領導候選人。

場景 8:Kafka 控制器看不到 Zookeeper

Zookeeper 將不會收到來自失效控制器的 ping,並將選擇一個新的 Kafka 節點作為控制器。 原始控制器可以繼續這樣呈現自己,但它不會收到來自 Zookeeper 的通知,因此它不會執行任何任務。 一旦網路恢復,他就會意識到自己不再是一個控制器,而是成為了一個普通的Kafka節點。

情景得出的結論

我們看到追隨者連線的遺失不會導致訊息遺失,而只是暫時減少冗餘,直到網路恢復。 當然,如果一個或多個節點遺失,這可能會導致資料遺失。

如果領導者因連線遺失而與 Zookeeper 分離,這可能會導致訊息遺失 確認=1。 與 Zookeeper 缺乏溝通導致與兩位領導人短暫的邏輯分歧。 這個問題透過參數解決 確認=全部.

參數 最小同步副本數 分成兩個或多個副本提供了額外的保證,即這種短期場景不會導致像場景 6 中那樣丟失訊息。

遺失訊息摘要

讓我們列出在 Kafka 中丟失資料的所有方式:

  • 如果使用確認訊息,則任何領導者失敗 確認=1
  • 任何不乾淨的領導階層過渡,即向情監偵之外的追隨者過渡,即使有 確認=全部
  • 如果使用以下命令確認訊息,則將領導者與 Zookeeper 隔離 確認=1
  • 已經將情監偵小組縮小到自己一人的領導人被完全孤立。 所有訊息都會遺失,甚至 確認=全部。 這僅在以下情況成立: min.insync.replicas=1.
  • 所有分區節點同時發生故障。 由於訊息是從記憶體中確認的,因此某些訊息可能尚未寫入磁碟。 重新啟動伺服器後,某些訊息可能會遺失。

可以透過禁止或確保至少兩次裁員來避免不純粹的領導層換屆。 最耐用的配置是組合 確認=全部 и 最小同步副本數 超過 1.

RabbitMQ和Kafka的可靠性直接對比

為了確保可靠性和高可用性,兩個平台都實現了主複製系統和輔助複製系統。 然而,RabbitMQ 有一個致命弱點。 當發生故障後重新連線時,節點會丟棄其資料並且同步會被阻止。 這種雙重打擊讓人對 RabbitMQ 中大型隊列的壽命產生疑問。 您將不得不接受減少冗餘或較長的阻塞時間。 減少冗餘會增加大量資料遺失的風險。 但如果隊列很小,那麼為了冗餘,可以使用重複的連線嘗試來處理短時間的不可用(幾秒鐘)。

卡夫卡就沒有這個問題。 它僅丟棄領導者和追隨者之間分歧點的數據。 所有共享資料均已儲存。 此外,複製不會阻塞系統。 當新的追隨者趕上時,領導者繼續接受帖子,因此對於 DevOps 來說,加入或重新加入集群成為一項微不足道的任務。 當然,複製時仍存在網路頻寬等問題。 如果您同時新增多個追蹤者,您可能會遇到頻寬限制。

當叢集中的多台伺服器同時發生故障時,RabbitMQ 的可靠性優於 Kafka。 正如我們已經說過的,RabbitMQ 僅在訊息被主伺服器和所有鏡像寫入磁碟後才向發布者發送確認。 但這會增加額外的延遲,原因有二:

  • 每幾百毫秒一次 fsync
  • 只有在檢查每個節點可用性的資料包(網路滴答)的生命週期到期後,才能注意到鏡像的故障。 如果鏡子減慢或掉落,就會增加延遲。

Kafka 的賭注是,如果一條訊息儲存在多個節點上,那麼它可以在訊息到達記憶體後立即確認。 因此,存在丟失任何類型訊息的風險(甚至 確認=全部, min.insync.replicas=2)在同時發生故障的情況下。

總體而言,Kafka 表現出了更好的軟體效能,並且是專為叢集而設計的。 如果需要可靠性,追隨者的數量可以增加到 11 個。 複製因子 5 和同步的最小副本數 min.insync.replicas=3 將使訊息遺失成為非常罕見的事件。 如果您的基礎架構可以支援此複製比率和冗餘級別,那麼您可以選擇此選項。

RabbitMQ 叢集適用於小型佇列。 但當交通繁忙時,即使是很小的隊列也會迅速成長。 一旦佇列變得很大,您就必須在可用性和可靠性之間做出艱難的選擇。 RabbitMQ 群集最適合非典型情況,在這種情況下,RabbitMQ 的靈活性優勢超過了群集的任何劣勢。

針對 RabbitMQ 對大型隊列的脆弱性,一種解決方法是將它們分成許多較小的隊列。 如果您不需要對整個佇列進行完整排序,而只需要相關訊息(例如來自特定客戶端的消息),或者根本不排序任何內容,那麼此選項是可以接受的:查看我的項目 再平衡器 拆分隊列(該項目仍處於早期階段)。

最後,不要忘記 RabbitMQ 和 Kafka 的群集和複製機制中的一些錯誤。 隨著時間的推移,系統變得更加成熟和穩定,但沒有任何消息可以 100% 不會丟失! 此外,資料中心還發生大規模事故!

如果我遺漏了某些內容、犯了錯誤,或您不同意其中的任何觀點,請隨時發表評論或與我聯絡。

常常有人問我:「Kafka 還是 RabbitMQ 選擇什麼?」、「哪個平台比較好?」。 事實是,這實際上取決於您的情況、當前的經驗等。我不太願意發表自己的意見,因為為所有用例和可能的限制推薦一個平台過於簡單化。 我寫了這一系列文章,以便您可以形成自己的觀點。

我想說,這兩個系統都是這個領域的領導者。 我可能有點偏見,因為根據我的專案經驗,我傾向於重視諸如保證訊息排序和可靠性之類的東西。

我看到其他技術缺乏這種可靠性和保證的排序,然後我研究了 RabbitMQ 和 Kafka,並意識到這兩個系統令人難以置信的價值。

來源: www.habr.com

添加評論