kafka第一講:瞭解kafka

一、Kafka 是什麼?

Kafka是一種高吞吐量的分佈式發佈-訂閱消息系統。它最初由LinkedIn公司開發,之後成爲Apache項目的一部分。Kafka是一個分佈式的,可劃分的,冗餘備份的持久性的日誌服務。Kafka 是用於構建實時數據管道和流應用程序。具有橫向擴展,容錯,wicked fast(變態快)等優點。

  • 通過O(1)的磁盤數據結構提供消息的持久化,這種結構對於即使數以TB的消息存儲也能夠保持長時間的穩定性能。
  • 高吞吐量 :即使是非常普通的硬件Kafka也可以支持每秒數百萬 的消息。
  • 支持通過Kafka服務器和消費機集羣來分區消息。
  • 支持Hadoop並行數據加載。

二、簡單理解

舉個例子,生產者消費者,生產者生產雞蛋,消費者消費雞蛋,生產者生產一個雞蛋,消費者就消費一個雞蛋,假設消費者消費雞蛋的時候噎住了(系統宕機了),生產者還在生產雞蛋,那新生產的雞蛋就丟失了。

或者另一種情況:生產者很強勁(大交易量的情況),生產者 1 秒鐘生產 100 個雞蛋,消費者 1 秒鐘只能吃 50 個雞蛋,那要不了一會,消費者就吃不消了(消息堵塞,最終導致系統超時),消費者拒絕再吃了,「雞蛋」又丟失了。

這個時候我們放個籃子在它們中間,生產出來的雞蛋都放到籃子裏,消費者去籃子裏拿雞蛋,這樣雞蛋就不會丟失了,都在籃子裏,而這個籃子就是Kafka。

雞蛋其實就是「數據流」,系統之間的交互都是通過「數據流」來傳輸的,也稱爲報文,也叫「消息」。消息隊列滿了,其實就是籃子滿了,「雞蛋」放不下了,那趕緊多放幾個籃子,其實就是Kafka的擴容。

綜上所述,Kafka 的概念就很好理解了,它就是那個「籃子」。

三、使用場景

通過簡單形象的比喻,相信很多童鞋都大概瞭解Kafka是怎麼一回事了。

那麼我們要不要放「籃子」,以及什麼情況我們需要去放這個「籃子」?

1.消息系統

對於一些常規的消息系統,Kafka是個不錯的選擇。

2.檢測網站活性

Kafka可以作爲「網站活性跟蹤」的最佳工具。可以將網頁/用戶操作等信息發送到Kafka中。並實時監控,或者離線統計分析等。

3.日誌系統

Kafka的特性決定它非常適合作爲「日誌收集中心」;

kafka是一個分佈式消息隊列。一般在架構設計中起到解耦、削峯、異步處理的作用。

四、重要概念

  • Producers:生產者,負責發佈消息到Kafka broker。示例中:就是它來生產「雞蛋」的。
  • Consumers:消費者,向Kafka broker讀取消息的客戶端。示例中:生出的「雞蛋」它來消費。
  • Consumers Group:每個Consumer屬於一個特定的Consumer Group(可爲每個Consumer指定group name,若不指定group name則屬於默認的group)
  • topic:每條發佈到Kafka集羣的消息都有一個類別,這個類別被稱爲Topic。(物理上不同Topic的消息分開存儲,邏輯上一個Topic的消息雖然保存於一個或多個broker上但用戶只需指定消息的Topic即可生產或消費數據而不必關心數據存於何處)。示例中:你把它理解爲標籤,生產者每生產出來一個雞蛋就貼上一個標籤(topic),消費者可不是誰生產的「雞蛋」都吃的,這樣不同的生產者生產出來的「雞蛋」,消費者就可以選擇性的吃了。
  • broker:Kafka集羣包含一個或多個服務器,這種服務器被稱爲broker。示例中:就是籃子的概念。
  • Partition是物理上的概念,每個Topic包含一個或多個Partition.

除了上面幾個概念,還有一個也非常重要,那就是zookeeper。

1)Producer端使用zookeeper用來發現broker列表,以及和Topic下每個partition leader建立socket連接併發送消息。

2)Broker端使用zookeeper用來註冊broker信息,已經監測partition leader存活性。

3)Consumer端使用zookeeper用來註冊consumer信息,其中包括consumer消費的partition列表等,同時也用來發現broker列表,並和partition leader建立socket連接,並獲取消息。

五、Kafka 數據流

看完「雞蛋」,「籃子」,我們逐漸清晰了,可zookeeper又出來攪合了,是不是有點懵比了?不要着急,看看下面這張圖,也許你就瞭然於胸了。

 

Kafka的總體數據流是這樣的:Producer往Broker裏面的指定Topic中寫消息,Consumers從Brokers裏面拉去指定Topic的消息,然後進行業務處理。

圖中有兩個topic,topic 0有兩個partition,topic 1有一個partition,三副本備份。可以看到consumer gourp 1中的consumer 2沒有分到partition處理,這是有可能出現的。

那麼,Kafka又是如何生產數據的?

 

 

 

 

 

如上圖所示:

  • 首先創建一條記錄,記錄中一定要指定對應的topic和value,key和partition可選。
  • 先序列化,然後按照topic和partition,放進對應的發送隊列中。
  • kafka produce都是批量請求,會積攢一批,然後一起發送,不是調send()就進行立刻進行網絡發包。

如果partition沒填,那麼情況會是這樣的:

1.填寫了key:按照key進行哈希,相同key去一個partition。(如果擴展了partition的數量那麼就不能保證了)

2.沒填key:round-robin來選partition。

這些要發往同一個partition的請求按照配置,攢一波,然後由一個單獨的線程一次性發過去。

六、設計原理

Kafka的設計初衷是希望作爲一個統一的信息收集平臺,能夠實時的收集反饋信息,並需要能夠支撐較大的數據量,且具備良好的容錯能力。

1.持久性

kafka使用文件存儲消息,這就直接決定kafka在性能上嚴重依賴文件系統的本身特性.且無論任何OS下,對文件系統本身的優化幾乎沒有可能。

文件緩存/直接內存映射等是常用的手段。

因爲kafka是對日誌文件進行append操作,因此磁盤檢索的開支是較小的。同時爲了減少磁盤寫入的次數,broker會將消息暫時buffer起來,當消息的個數(或尺寸)達到一定閥值時,再flush到磁盤,這樣減少了磁盤IO調用的次數。

2.性能

需要考慮的影響性能點很多,除磁盤IO之外,我們還需要考慮網絡IO,這直接關係到kafka的吞吐量問題。kafka並沒有提供太多高超的技巧:

  • 對於producer端,可以將消息buffer起來,當消息的條數達到一定閥值時,批量發送給broker;
  • 對於consumer端也是一樣,批量fetch多條消息,不過消息量的大小可以通過配置文件來指定;
  • 對於broker端,似乎有個sendfile系統調用可以潛在的提升網絡IO的性能:將文件的數據映射到系統內存中,socket直接讀取相應的內存區域即可,而無需進程再次 `copy` 和交換。

其實對於producer/consumer/broker三者而言,CPU的開支應該都不大,因此啓用消息壓縮機制是一個良好的策略。壓縮需要消耗少量的CPU資源,不過對於kafka而言,網絡IO更應該需要考慮。可以將任何在網絡上傳輸的消息都經過壓縮。

kafka支持gzip/snappy等多種壓縮方式。

3.生產者

負載均衡:producer將會和Topic下所有partition leader保持socket連接。消息由producer直接通過socket發送到broker,中間不會經過任何路由層。

事實上,消息被路由到哪個partition上,有producer客戶端決定。比如可以採用random、key-hash、輪詢等,如果一個topic中有多個partitions,那麼在producer端實現「消息均衡分發」是必要的。

4.消費者

consumer端向broker發送fetch請求,並告知其獲取消息的offset。此後consumer將會獲得一定條數的消息,consumer端也可以重置offset來重新消費消息。

5.消息傳送機制

對於JMS實現,消息傳輸擔保非常直接:有且只有一次(exactly once)。在kafka中稍有不同:

  • at most once: 最多一次,這個和JMS中 「非持久化」消息類似。發送一次,無論成敗,將不會重發。
  • at least once: 消息至少發送一次,如果消息未能接受成功,可能會重發,直到接收成功。
  • exactly once: 消息只會發送一次。
  • at most once: 消費者fetch消息,然後保存offset,然後處理消息。當client保存offset之後,但是在消息處理過程中出現了異常,導致部分消息未能繼續處理。那麼此後「未處理」的消息將不能被fetch到。
  • at least once: 消費者fetch消息,然後處理消息,然後保存offset。如果消息處理成功之後,但是在保存offset階段zookeeper異常導致保存操作未能執行成功,這就導致接下來再次fetch時可能獲得上次已經處理過的消息,原因offset沒有及時的提交給zookeeper,zookeeper恢復正常還是之前offset狀態。
  • exactly once:kafka中並沒有嚴格的去實現(基於2階段提交,事務),我們認爲這種策略在kafka中是沒有必要的。

通常情況下「at-least-once」是我們首選。(相比「at most once」而言,重複接收數據總比丟失數據要好)。

6.複製備份

kafka將每個partition數據複製到多個server上,任何一個partition有一個leader和多個follower(可以沒有),備份的個數可以通過broker配置文件來設定。

  • leader處理所有的read-write請求,follower需要和leader保持同步。
  • follower和consumer一樣,消費消息並保存在本地日誌中;
  • leader負責跟蹤所有的follower狀態,如果follower落後太多或者失效,leader將會把它從replicas同步列表中刪除。
  • 當所有的follower都將一條消息保存成功,此消息才被認爲是committed,那麼此時consumer才能消費它。- 即使只有一個replicas實例存活,仍然可以保證消息的正常發送和接收,只要zookeeper集羣存活即可。(不同於其他分佈式存儲,比如hbase需要「多數派」存活才行)
  • 當leader失效時,需在followers中選取出新的leader,可能此時follower落後於leader,因此需要選擇一個up-to-date的follower。
  • 選擇follower時需要兼顧一個問題,就是新leader server上所已經承載的partition leader的個數,如果一個server上有過多的partition leader,意味着此server將承受着更多的IO壓力。
  • 在選舉新leader,需要考慮到負載均衡。

7.日誌

日誌文件中保存了一序列log entries(日誌條目),每個log entry格式爲「4個字節的數字N表示消息的長度」 + 「N個字節的消息內容」;

每個日誌都有一個offset來唯一的標記一條消息,offset的值爲 8 個字節的數字,表示此消息在此partition中所處的起始位置。

每個partition在物理存儲層面,有多個log file組成(稱爲segment)。segmentfile的命名爲 “最小offset”.kafka

8.分配

kafka使用zookeeper來存儲一些meta信息,並使用了zookeeper watch機制來發現meta信息的變更並作出相應的動作(比如consumer失效,觸發負載均衡等)

參考:https://toutiao.io/posts/6d4d9t

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章