天天看點

Kafka詳細的設計和生态系統

本譯文自Jean-Paul Azar 在 https://dzone.com 發表的 Kafka Detailed Design and Ecosystem ,文中版權,圖像代碼的資料均歸作者所有。為了本土化,翻譯内容略作修改。

Kafka的核心是經紀人,主題,日志,分區和叢集。核心也包括像MirrorMaker這樣的相關工具。前面提到的是Kafka,因為它存在于Apache中。

Kafka生态系統由Kafka Core,Kafka Streams,Kafka Connect,Kafka REST Proxy和Schema Registry組成。大部分Kafka生态系統的其他部分來自Confluent,不屬于Apache。

Kafka Stream是Streams API,用于轉換、彙總和處理來自流的記錄并生成衍生流。Kafka Connect是API連接配接器,用于建立可重用的生産者和消費者(例如,來自DynamoDB的更改流)。Kafka REST代理通過REST(HTTP)被用于生産者和消費者。該架構注冊管理使用模式的AvroKafka的記錄。Kafka MirrorMaker用于将群集資料複制到另一個群集。

Kafka詳細的設計和生态系統

Kafka連接配接源是記錄的來源。Kafka連接配接水槽是記錄的目的地。

Kafka詳細的設計和生态系統

Kafka Stream API基于核心Kafka原語建構,并擁有自己的生命。Kafka流可以實時處理流。Kafka Streams支援流處理器。流處理器從輸入主題擷取連續的記錄流,對輸入執行一些處理,轉換和聚合,并産生一個或多個輸出流。例如,視訊播放器應用程式可能會接收觀看的視訊事件的輸入流,并暫停視訊,并輸出使用者偏好流,然後基于最近的使用者活動或許多使用者的聚合活動來擷取新的視訊推薦,以檢視哪些新的視訊很熱。Kafka Stream API解決了無序記錄的難題,跨多個流聚合,連接配接來自多個流的資料,允許有狀态的計算等等。

Kafka詳細的設計和生态系統

Kafka流可以實時處理流。它可以聚合多個流,連接配接來自多個流的資料,允許有狀态的計算等等。

Kafka Connect是連接配接器API,用于建立可重用的生産者和消費者(例如,來自DynamoDB的更改流)。Kafka連接配接源是記錄的來源。Kafka連接配接水槽是記錄的目的地。

模式注冊管理使用Avro作為Kafka記錄管理模式。

Kafka MirrorMaker用于将群集資料複制到另一個群集。

Kafka REST代理通過REST(HTTP)被用于生産者和消費者。您可以使用它來輕松整合現有的代碼庫。

如果您不确定Kafka是什麼,請參閱什麼是Kafka?

這篇文章從我們關于Kafka架構的系列文章中有所展現,其中包括Kafka主題架構,Kafka制作者架構, Kafka使用者架構和Kafka生态系統架構。

本文受到Kafka設計部分的啟發。你可以把它想成懸崖筆記。

LinkedIn工程師建構Kafka以支援實時分析。Kafka被設計為提供實時處理流的分析系統。LinkedIn将Kafka開發為實時處理流式資料饋送的統一平台。Kafka背後的目标是建構一個高吞吐量的流媒體資料平台,支援日志聚合,使用者活動等大容量事件流。

為了滿足Kafka的需求擴充,分布式支援分片和負載均衡。擴充需求激發了Kafka的分區和消費者模型。Kafka使用分區,分布式,送出日志來擴充寫入和讀取。Kafka的分片被稱為分區(Kinesis,類似于Kafka,稱為分區“碎片”)。

根據維基百科的說法,“資料庫分片是資料庫或搜尋引擎中資料的水準分區,每個分區被稱為分片或資料庫分片,每個分片被儲存在一個單獨的資料庫伺服器執行個體上,以傳播負載”。

Kafka被設計為處理來自離線系統的周期性大資料加載以及傳統的消息傳遞用例,低延遲。

MOM是面向消息的中間件; 考慮IBM MQSeries,JMS,ActiveMQ和RabbitMQ。像許多MOM一樣,Kafka通過複制和上司選舉來節點故障的容錯。但是,Kafka的設計更像是一個分布式的資料庫事務日志而不是傳統的消息傳遞系統。與許多MOM不同的是,Kafka的複制是建立在低級設計之上的,并不是事後的想法。

Kafka依靠檔案系統來存儲和緩存記錄。

順序寫入硬碟性能的硬碟性能很快(非常快)。JBOD隻是一堆磁盤驅動器。帶有6個7200rpm SATA RAID-5陣列的JBOD配置約為600MB /秒。像Cassandra表一樣,Kafka日志是隻寫結構,意思是資料會被附加到日志的末尾。在使用硬碟驅動器時,順序讀取和寫入速度快,可預測,并且可以通過作業系統進行大量優化。使用HDD時,順序磁盤通路可能比随機存儲器通路和SSD更快。

盡管JVM GC的開銷可能會很高,但是Kafka在作業系統上依賴于緩存,這是一個巨大的,快速且穩定的緩存。而且,現代作業系統使用所有可用的主存儲器來進行磁盤緩存。作業系統檔案緩存幾乎是免費的,沒有作業系統的開銷。實作高速緩存一緻性是正确的挑戰,但是Kafka依靠堅如磐石的作業系統來實作高速緩存一緻性。使用OS進行緩存還會減少緩沖區副本的數量。由于Kafka磁盤使用趨向于順序讀取,是以OS預讀緩存令人印象深刻。

Cassandra,Netty和Varnish使用類似的技術。所有這一切都在Kafka檔案中得到了很好的解釋,在油漆現場還有一個更有趣的解釋。

Kafka主張長時間順序通路磁盤進行讀取和寫入。像Cassandra,LevelDB,RocksDB和其他Kafka使用日志結構化存儲和壓縮的形式,而不是磁盤上可變的BTree。像Cassandra一樣,Kafka使用墓碑而不是立即删除記錄。

由于磁盤這些天有一些無限的空間,并且速度非常快,Kafka可以提供通常在消息系統中不常見的功能,如長時間保持舊消息。這種靈活性允許Kafka有趣的應用。

生産者向Kafka經紀人詢問有關哪個Kafka經紀人具有哪個主題分區上司的中繼資料,是以不需要路由層。這個上司資料允許生産者直接向Kafka經紀人分區上司發送記錄。

生産者用戶端控制它将消息釋出到哪個分區,并且可以根據某些應用程式邏輯選擇一個分區。生産者可以通過密鑰,循環法或使用定制應用程式特定的分區邏輯來分區記錄。

Kafka生産商支援記錄配料。批量可以通過批量記錄的大小來配置。批次可以根據時間自動重新整理。

批量處理對于網絡IO吞吐量非常有利,并大幅提高吞吐量。

緩沖是可配置的,并允許您在更好的吞吐量之間進行額外延遲之間的權衡。或者在大量使用的系統的情況下,它可能是更好的平均吞吐量,并減少總體延遲。

批量處理允許累積更多的位元組發送,相當于Kafka Brokers上較少的I / O操作,并提高了壓縮效率。為了獲得更高的吞吐量,Kafka Producer配置允許基于時間和大小的緩沖。生産者發送多個記錄作為一個批次,而不是逐個發送每個記錄的網絡請求。

Kafka詳細的設計和生态系統

在大型流媒體平台中,瓶頸并不總是CPU或磁盤,而是通常網絡帶寬。雲中存在更多的網絡帶寬問題,如集裝箱化和虛拟化環境,因為多個服務可能共享一個NiC卡。另外,與資料中心或WAN通信時,網絡帶寬問題可能會有問題。

批處理有利于高效壓縮和網絡IO吞吐量。

Kafka提供了端到端的批量壓縮,而不是一次壓縮記錄,Kafka有效地壓縮了整批記錄。相同的消息批處理可以一次壓縮并發送到Kafka代理/伺服器,并以壓縮形式寫入日志分區。您甚至可以配置壓縮,以便在Kafka經紀商将壓縮記錄傳送給使用者之前不進行解壓縮。

Kafka支援GZIP,Snappy和LZ4壓縮協定。

Kafka消費者從經紀人那裡擷取資料。其他系統經紀商将資料或流資料推送給消費者。消息通常是一個基于拉的系統(SQS,大多數MOM使用拉)。在拉動式的情況下,如果消費者落後,它會在晚些時候趕上。

由于Kafka是基于拉式的,是以它實施了大量的資料分批處理。Kafka像許多基于拉的系統實作了長期民意調查(SQS,Kafka都這樣做)。長時間輪詢在請求一段時間後保持連接配接打開并等待響應。

一個基于拉的系統必須拉取資料然後處理它,拉和擷取資料之間總是有一個暫停。

推送資料給消費者(抄寫員,水槽,反應流,RxJava,Akka)。基于推送或流式傳輸系統在處理緩慢或死亡的消費者方面存在問題。當消費率低于生産速度時,推送系統消費者有可能不知所措。一些基于推送的系統使用基于背壓的退避協定,其允許消費者訓示其被壓倒看到反應性流。當試圖跟蹤消息确認時,這種不會淹沒消費者和消費者恢複的問題是棘手的。

基于推送或流式傳輸的系統可以立即發送請求,或者累積請求并批量發送(或基于反壓的組合)。基于推送的系統總是在推送資料。消費者可以在處理已經發送的資料的同時累積消息,這有利于減少消息處理的延遲。但是,如果消費者在加工後死亡,那麼經紀人如何知道消費者在哪裡以及何時将資料再次發送給其他消費者。這個問題不是一個容易解決的問題。Kafka通過使用拉式系統來解決這些複雜問題。

對于大多數MOM,經紀人有責任跟蹤哪些消息被标記為已消耗。消息跟蹤不是一件容易的事情。随着消費者消費資訊,經紀人會跟蹤狀态。

大多數MOM系統的目标是讓經紀人在消費後快速删除資料。還記得大部分的MOM是在磁盤小得多,能力不足,價格昂貴的時候寫的。

這個消息跟蹤比聽起來要複雜(确認功能),因為經紀人必須保持大量狀态來跟蹤每個消息,發送,确認并知道何時删除或重發消息。

請記住,Kafka主題分為有序分區。每條消息在此有序分區中都有一個偏移量。每個主題分區一次僅由一個消費者組消費。

這種分區布局的意思是,Broker跟蹤每個消息跟蹤的偏移資料,如MOM,但隻需要每個使用者組的偏移量,即存儲的分區偏移對。這種偏移追蹤等同于要追蹤的資料少得多。

消費者定期向Kafka經紀人發送位置資料(消費者組,分區偏移對),經紀人将該偏移資料存儲到偏移主題中。

與MOM相比,抵消風格的消息确認要便宜得多。另外,消費者更加靈活,可以倒退到更早的偏移(重放)。如果有錯誤,那麼修複錯誤,倒回消費者并重播主題。這個倒帶功能是Kafka的一個殺手功能,因為Kafka可以儲存很長一段時間的主題日志資料。

有三種消息傳遞語義:最多一次,至少一次,恰好一次。最多一次的消息可能會丢失,但永遠不會重新發送。至少一次消息是永遠不會丢失的,但可以重新傳遞。每個消息恰好一次隻傳送一次。确切地說,曾經是首選的,但更昂貴的,并要求生産者和消費者更多的簿記。

回想一下,所有副本具有相同的偏移量的完全相同的日志分區,并且使用者組在日志每個主題分區中保持其位置。

為了實作“最多一次”消費者讀取消息,然後将其偏移儲存在分區中,并将其發送給代理,最後處理該消息。“最多一次”的問題是消費者可能會在儲存其位置之後,但在處理消息之前死亡。然後,接管或重新啟動的消費者将在最後的位置離開,并且不會處理有問題的消息。

為了實作“至少一次”,消費者讀取消息,處理消息,并最終将代價儲存到代理。“至少一次”的問題是消費者在處理消息之後但在儲存最後偏移位置之前可能崩潰。然後,如果消費者重新啟動或其他消費者接管,消費者可能會收到已處理的消息。“至少一次”是最常見的消息傳遞設定,您的責任是使消息具有幂等性,這意味着兩次獲得相同的消息不會導緻問題(兩個借方)。

為了在消費者方面實作“恰好一次”,消費者需要在消費者位置的存儲與消費者的消息處理輸出的存儲之間的兩階段送出。或者,消費者可以将消息處理輸出存儲在與最後偏移相同的位置。

Kafka提供了前兩個,從消費者的角度來看,實作第三個。

Kafka為耐用性提供了可操作的可預測性語義。釋出消息時,消息被“送出”到日志,這意味着所有ISR都接受消息。隻要至少有一個副本存在,這個送出政策對于耐久性就能很好地工作。

生産者連接配接可能在發送過程中下降,生産者可能不确定它發送的消息是否經過,然後生産者重新發送消息。這個重發邏輯是為什麼使用消息密鑰和使用幂等消息(重複确定)是重要的。Kafka直到最近(2017年6月)才保證消息不會從生産者重試中複制。

生産者可以重新發送一個消息,直到收到确認,即收到确認。生産者重新發送消息而不知道其發送的其他消息是否與否,進而否定“恰好一次”和“最多一次”的消息傳遞語義。

制片人可以指定耐久度級别。制作人可以等待送出的消息。等待送出可確定所有副本都具有該消息的副本。

制片人可以發送沒有确認(0)。生産者可以從分區上司(1)得到一個确認。生産者可以發送并等待來自所有副本(-1)的确認,這是預設的。

Kafka現在支援從生産者“精确地一次”傳遞,性能改進和分區間的原子寫入。他們通過生産者發送一個序列ID來實作這一點,代理跟蹤生産者是否已經發送了這個序列,如果生産者試圖再次發送它,它會得到重複消息的确認,但是沒有任何東西被儲存到日志中。這種改進不需要API改變。

Kafka的另一個改進是Kafka生産者在原子筆劃上進行分割。原子寫入意味着Kafka使用者隻能看到送出日志(可配置)。Kafka有一個協調員,寫一個标記到主題日志,以表示已經成功處理了什麼。事務協調器和事務日志維護原子寫入的狀态。

原子寫入确實需要一個新的生産者API來處理事務。

這是一個使用新的生産者API的例子。

Kafka通過可配置數量的Kafka經紀人複制每個主題的分區。Kafka的複制模式是預設的,而不是像大多數MOM那樣的插入功能,因為Kafka從一開始就打算使用分區和多節點。每個主題分區都有一個上司者和零個或多個關注者。

上司者和追随者被稱為複制品。複制因素是上司者節點加上所有的追随者。分區上司在Kafka經紀人之間平均分享。消費者隻能從上司讀取。制片人隻寫信給上司。

追随者的主題日志分區與上司者的日志同步,ISR是上司者的精确副本減去正在進行中的待複制記錄。追随者像一個普通的Kafka消費者一樣,從他們的上司人那裡批量提取記錄。

Kafka記錄哪些Kafka經紀人還活着。為了活着,Kafka經紀人必須使用ZooKeeper的心跳機制來維護一個ZooKeeper會話,并且必須讓所有的追随者與上司者同步,而不會落後太多。

這個ZooKeeper會話和同步是被稱為同步的代理生存所需要的。同步副本被稱為ISR。每個上司者都跟蹤一組“同步副本”。

如果ISR /追随者死亡,則落後,上司者将從ISR中移除追随者。落後于複制品在<code>replica.lag.time.max.ms</code>時段之後不同步的時候 。

當所有ISR将消息應用到其日志時,消息被認為是“已送出”的。消費者隻看到送出的消息。Kafka保證:隻要至少有一個ISR,承諾的資訊就不會丢失。

Kafka分區是一個複制的日志。複制日志是分布式資料系統原語。複制日志對于使用狀态機來實作其他分布式系統很有用。一個複制的日志模型對有序的一系列值“達成一緻”。

當一個上司人活着的時候,所有的追随者隻需要複制他們上司的價值觀和秩序。如果上司者死了,Kafka從同步的追随者中選擇一個新的上司者。如果一個生産者被告知一個消息被送出,然後上司失敗,那麼新當選的上司者必須有這個送出的消息。

你有更多的ISR; 在上司失敗的時候選舉越多。

法定人數是所需的确認數量,以及必須與選舉上司人進行比較的日志數量,以確定可用性重疊。大多數系統使用多數票,Kafka不使用簡單的多數投票來提高可用性。

在Kafka,上司人的選擇是基于完整的日志。如果我們有一個複制因子3,那麼至少兩個ISR必須在上司者聲明發送的消息送出之前同步。如果一個新的上司者需要當選,不超過3次失敗,新的上司者保證有所有承諾的資訊。

在追随者中,必須至少有一個包含所有送出的消息的副本。大多數投票的問題法定人數是沒有多少失敗,有一個無法操作的群集。

Kafka為每個上司人維護一套情監偵。隻有這一套ISR的成員才有資格上司選舉。在所有ISR确認寫入之前,生産者寫入分區的内容不會被送出。隻要ISR設定發生變化,ISR就會持續到ZooKeeper。隻有屬于ISR成員的副本才有資格當選上司。

ISR法定人數的這種風格允許生産者在沒有大多數所有節點的情況下繼續工作,但隻有ISR多數票。ISR仲裁的這種風格也允許副本重新加入ISR集并且擁有其投票計數,但是在加入之前必須完全重新同步,即使副本在其崩潰期間丢失未重新整理的資料也是如此。

Kafka關于資料丢失的保證隻有在至少一個副本同步的情況下才有效。

如果所有正在複制分區上司者的追随者都立即死亡,那麼資料丢失Kafka保證是無效的。如果分區的所有副本都關閉,則預設情況下,Kafka選擇作為首領活動的第一個副本(不一定在ISR集合中)(config unclean.leader.election.enable = true是預設值)。這種選擇有利于可用性的一緻性。

如果一緻性比您的用例的可用性更重要,那麼您可以設定配置,<code>unclean.leader.election.enable=false</code>那麼如果所有副本都停止運作一個分區,Kafka會等待第一個ISR成員(而不是第一個副本)活躍起來以選出新的上司者。

生産者可以通過設定acks(0),僅前導(1)或所有副本(-1)來選擇耐久性。

acks = all是預設值。總而言之,當所有目前的同步複制品(ISR)都收到該消息時,便會發生這種情況。

您可以在一緻性和可用性之間進行權衡。如果耐用性超過可用性,那麼禁用不幹淨的上司者選舉并指定最小的ISR大小。

最小的ISR規模越大,保證一緻性就越好。但是,如果ISR集的大小小于最小門檻值,則ISR的最小ISR越高,可用性就越低,因為分區不可用。

Kafka已經為消費者和生産者制定了限制他們被允許消費的帶寬的限額。這些配額阻止消費者或生産者占用Kafka經紀人資源。配額是由用戶端ID或使用者。配額資料存儲在ZooKeeper中,是以更改不需要重新啟動Kafka代理。

使用配額限制消費者的帶寬。

所有。這意味着所有ISR必須将消息寫入其日志分區。

Kafka選擇第一個複制品(不一定在ISR集合中),作為上司者活躍起來,<code>unclean.leader.election.enable=true</code>以支援可用性。

通過線路以及磁盤優化IO吞吐量。它還通過壓縮整個批次來提高壓縮效率。

成為高吞吐量,可擴充的流媒體資料平台,用于對日志聚合,使用者活動等大容量事件流進行實時分析。

生産者原子寫入,性能改進和生産者不發送重複的消息。

有三種消息傳遞語義:最多一次,至少一次,恰好一次。