
Apache Kafka®的核心是日志。日志是一個簡單的資料結構,它通過順序讀寫與底層硬體密切配合。以日志為中心的設計利用了高效的磁盤緩沖、CPU 緩存、預讀、零拷貝等許多特性,進而帶來了衆所周知的高效率和吞吐量。對于那些剛接觸 Kafka 的人來說,這些主題以及它作為送出日志的底層實作,通常是他們學習 Apache Kafka 的第一件事。
但是日志本身的代碼在整個系統中隻占相對較小的一部分。Kafka 的代碼庫中有很大一部分是負責在叢集中多個 broker 之間配置設定分區(即日志)、配置設定上司權、處理故障等。這些代碼使 Kafka 成為一個可靠和可信的分布式系統。
從曆史上看,Apache ZooKeeper 是分布式代碼工作的關鍵部分。ZooKeeper 提供了可靠的中繼資料存儲,這些中繼資料存儲了系統中最重要的資訊:比如分區在哪裡,哪個副本是 Leader 等等。項目早期使用 ZooKeeper 是有意義的,因為它是一個強大且經過驗證的工具。但歸根結底,ZooKeeper 是一個基于一緻性日志的特殊檔案系統/觸發器 API。Kafka 是一個建立在一緻性日志之上的釋出/訂閱 API。這使得作業系統的人員可以跨兩個日志實作、兩個網絡層和兩個安全實作(每個實作都有不同的工具和監視鈎子)對通信和性能進行調優、配置、監視、保護和評估。它變得不必要的複雜。這種固有的和不可避免的複雜性促使了最近的一個倡議,即用一個完全運作在 Kafka 内部的仲裁服務來取代 ZooKeeper。
當然,更換 ZooKeeper 是一項相當大的工作,去年 4 月,我們啟動了一個社群倡議,以加快進度,并在年底前傳遞一個工作系統。
我剛剛和 Jason, Colin 以及 KIP-500 團隊坐在一起,經曆了 Kafka 伺服器的完整生命周期,生産,消費和所有 zookeeper 免費。非常甜蜜!
Ben Stopford@benstopford
是以我們很高興地說,KIP-500 代碼的早期通路已經送出到 trunk,預計将包括在即将釋出的 2.8 版本中。第一次,你可以在沒有 ZooKeeper 的情況下運作 Kafka。我們稱之為 Kafka Raft 中繼資料模式,通常縮寫為 KRaft(發音像 craft)模式。
注意,有一些特性在這個早期版本中是不可用的。我們還不支援使用 acl 和其他安全特性或事務。而且,在 KRaft 模式下,不支援分區重配置設定和 JBOD(預計在今年晚些時候的 Apache Kafka 版本中會提供這些功能)。是以,考慮 Quorum 控制器是一個實驗性的功能,我們不建議将其置于生産工作負載之下。然而,如果你确實嘗試過這個軟體,你會發現它有很多新的優點:它的部署和操作更簡單,你可以把 Kafka 作為一個單獨的程序來運作,而且它可以在每個叢集中容納更多的分區(見下面的資料資訊)。
Quorum 控制器: 事件驅動的共識
如果你選擇使用新的 Quorum 控制器運作 Kafka,所有以前由 Kafka 控制器和 ZooKeeper 承擔的中繼資料功能,都會合并到這個新的服務中,運作在 Kafka 叢集中。如果有需要的話,Quorum 控制器還可以在專用硬體上運作。
但在内部,它變得有趣起來。Quorum 控制器使用新的 KRaft 協定來確定中繼資料在仲裁中被精确地複制。這個協定在很多方面與 ZooKeeper 的 ZAB 協定和 Raft 相似,但有一些重要的差別,其中一個顯著且合适的差別是它使用了事件驅動的架構。
Quorm 控制器使用事件源存儲模型存儲其狀态,這確定始終可以準确地重新建立内部狀态機。用于存儲此狀态的事件日志(也稱為中繼資料主題)通過快照定期地進行壓縮,以確定日志不會無限增長。Quorm 中的其他控制器通過響應活動控制器,建立并存儲在其日志中的事件來跟蹤活動控制器。是以,如果一個節點由于分區事件而暫停,那麼它可以在重新登入時通過通路日志來快速地趕上它錯過的任何事件。這大大減少了不可用視窗,改善了系統的最壞情況恢複時間。
事件驅動的内部共識
KRaft 協定的事件驅動特性意味着,與基于 ZooKeeper 的控制器不同,仲裁控制器在成為活動狀态之前不需要從 ZooKeeper 加載狀态。當上司權發生變化時,新的活動控制器已經在記憶體中擁有所有送出的中繼資料記錄。此外,KRaft 協定中使用的事件驅動機制也用于跨叢集跟蹤中繼資料。以前使用 rpc 處理的任務現在得益于事件驅動以及使用實際日志進行通信。這些改變帶來的一個令人愉快的結果是,Kafka 現在可以比以前支援更多的分區。讓我們更詳細地讨論一下。
擴充 Kafka:支援數百萬個分區
Kafka 叢集可以支援的分區數由兩個屬性決定: 每個節點的分區數限制和叢集範圍的分區限制。兩者都很有趣,但是到目前為止,中繼資料管理一直是叢集範圍限制的主要瓶頸。以前的 Kafka 改進建議(KIPs)已經改進了每個節點的限制,盡管總有更多的事情可以做。但是 Kafka 的可伸縮性主要依賴于增加節點來獲得更多的容量。這就使叢集範圍限制變得重要的地方,因為它定義了系統内可伸縮性的上限。
新的 Quorum 控制器旨在處理每個叢集中更多的分區。為了評估這一點,我們進行了類似于 2018 年運作的那些測試,以公布 Kafka 固有的分區限制。這些測試測量關閉和恢複所花費的時間,這是指舊控制器的 O(#partitions)操作。正是這個操作為 Kafka 在單個叢集中所能支援的分區數量設定了上限。
之前的實作,正如 Jun Rao 在上面的文章中解釋的那樣,可以達到 200K 分區,限制因素是在外部共識(ZooKeeper)和内部 leader 管理(Kafka controller)之間移動關鍵中繼資料所花費的時間。使用新的仲裁控制器,這兩個角色由相同的元件提供服務。事件驅動的方法意味着控制器故障轉移現在幾乎是即時的。下面是在我們的實驗室中運作 200 萬個分區(是上一個上限的 10 倍)的叢集:
With ZooKeeper-Based ControllerWith Quorum Controller
Controlled Shutdown Time (2 million partitions)135 sec.32 sec.
Recovery from Uncontrolled Shutdown (2 million partitions)503 sec.37 sec.
控制和不控制停機的兩種措施都很重要。受控關閉會影響常見的操作場景,如滾動重新開機:部署軟體更改的标準過程,同時保持整個過程的可用性。從不受控制的關閉中恢複可能更重要,因為它設定了系統的恢複時間目标(RTO),例如在發生意外故障後,例如 VM 或 pod 崩潰或資料中心不可用。雖然這些度量隻是更廣泛的系統性能名額,但它們直接度量了衆所周知的 ZooKeeper 使用帶來的瓶頸。
注意,控制和非控制的測量是不能直接比較的。不受控制的政府停擺案包括了選出新上司人所需的時間,而控制案則沒有。這種差異是故意的,以保持控制病例與 Jun Rao 的原始測量。
叢集規模下降: 單一程序運作 Kafka
Kafka 經常被認為是重量級的基礎設施,比如管理 zookeeper 的複雜性(因為它是一個單獨的分布式系統) 就是這種看法存在的重要原因。這通常會導緻項目在開始時選擇更輕量級的消息隊列,比如 ActiveMQ 或 rabbitmq 這樣的傳統隊列,然後在規模需要時轉移到 Kafka。
這是不幸的,因為 Kafka 提供的抽象,形成了一個送出日志,是适用于小規模的工作負載,你可能看到在一個初創公司,因為它是在 Netflix 或 Instagram 的高吞吐量。更重要的是,如果你想添加流處理,你需要 Kafka 和它的送出日志抽象,不管它是使用 Kafka Streams, ksqlDB,還是其他的流處理架構。但是由于管理兩個獨立系統 kafka 和 zookeeper 的複雜性,使用者常常覺得他們必須在規模和入門的友善性之間做出選擇。
現在已經不是這樣了。KIP-500 和 KRaft 模式提供了一種很棒的、輕量級的方式來開始使用 Kafka,或者使用它作為 ActiveMQ 或 RabbitMQ 等單片代理的替代方案。輕量級的單程序部署也更适合于邊緣場景和那些使用輕量級硬體的場景。雲為這個問題增加了一個有趣的切入角度。像融合雲這樣的托管服務完全消除了操作負擔。是以,無論您是希望運作自己的叢集,還是讓它為您運作,都可以從小規模開始,随着底層用例的擴充(可能)擴充到大規模——所有這些都使用相同的基礎設施。讓我們看看單程序部署是什麼樣子的。
帶着沒有 ZooKeeper 的的 Kafka 兜風
新的 Quorm 控制器今天在 trunk 中已經以試驗性的功能提供出來,預計将包含在即将釋出的 Apache Kafka 2.8 版本中。那麼你能用它做什麼呢? 如上所述,一個簡單但非常酷的新特性是建立單個程序 Kafka 叢集的能力,如下面的簡短示範所示。
示範文檔位址: https://asciinema.org/a/403794/embed?
當然,如果您想要擴充它以支援更高的吞吐量并添加複制以容錯,您隻需要添加新的代理程序。如你所知,這是基于 kraft 的 Quorm 控制器的早期通路版本。請不要将它用于高負載的工作環境中。在接下來的幾個月裡,我們将添加最後缺失的部分,執行協定的 TLA+模組化,并在融合雲中完善 Quorm 控制器。
您現在可以自己嘗試新的 Quorm 控制器。在 GitHub 上檢視完整的描述。