kafka設計與原理詳解

Kafka 設計與原理詳解

[TOC]web

kafka 應用場景

  • 日誌收集算法

  • 消息系統 解耦生產者和消費者、緩存消息。api

  • 用戶活動跟蹤: 就是咱們在作的。緩存

  • 運營指標:生產各類操做的集中反饋。服務器

  • 流式處理:好比spark steaming網絡

kafka的發佈對象是topic。每類數據咱們能夠歸爲一個topic。向topic發送消息的咱們稱爲生產者、從topic訂閱消息的稱爲consumer。producer 和 consumer 能夠同時讀寫數據。數據結構

  • topic: 消息主題。併發

  • producer: 生產者到topic的一方。負載均衡

  • consumer: 訂閱topic消費消息的一方。異步

  • broker :

kafka topic & partition

Alt text

kafka 集羣會保存全部消息,無論消息有沒有被消費;經過設置消息過時時間,能夠來定製的刪除消息。好比咱們設置過時時間爲2天。

一個消息被生產出來,寫入到多個partition。消息就是以partition做爲存儲單位,每一個partition能夠經過調整以適應它所在的機器,而一個topic對應多個partition,這樣整個集羣就能夠適應各個大小的數據了。第二,也能夠提升併發,由於能夠以partition 爲單位來讀寫了。

Kafka 核心組件

replications partitions and leaders

怎麼實現持久化?

kafka可以作數據持久化。能夠爲每一個topic設置副本容量。 若是副本容量設爲3,那麼一份數據就會被放在3臺不一樣的機器上。通常設爲2.

關於partition。

topic的存放形式是partition。每個topic均可以設置partition數量。partition的數量決定了log的數量。producer 在生產消息時,會把消息發佈到topic的各個partition中。
上面說的副本都是以partition爲單位的,不過只有一個partition的副本會被選爲leader做爲讀寫用。

kafka從0.8開始提供partition級別的replication,replication的數量可在$KAFKA_HOME/config/server.properties中配置。

default.replication.factor = 1

如何設置partition值要考慮的因素?

一個partition只能被一個消費者消費(可是一個消費者能夠同時消費多個partition。),因此,運行的partition的數量要大於運行的comsumer的數量,不然就會有消費者消費不到數據。另外一方面,建議partition的數量大於broker 的數量。這樣leader partition 的數據就能均勻的分佈在各個broker中,最終使得集羣負載均衡。

(若是小於會怎樣樣,會形成比較集中的存儲在單個broker之中嗎。)。注意:kafka須要爲每一個partition分配一些內存來緩存消息數據,若是parttion數量越大,分配更大的heap space。

partition每個都會保存做爲一個repilca麼? 不是的。partition的概念是根據partition 方法來將數據分佈存儲。

producers

producer發送消息。

producer 能夠直接發送到broker對應的leader partition中,不須要經歷任何一箇中介的轉發。爲實現這個特性,每一個broker均可以響應producer的請求,並返回topic的一些元信息,這些元信息包括哪些機器是存活的,topic的你leader partition都在哪。現階段哪些leader partition 是能夠直接訪問的?

若是訪問的不是leader partition 怎麼搞? 並且我看是能夠指定多個進行訪問的。

producer 和 partition 。

producer 能夠控制以什麼樣的將消息推送到客戶端。實現方法包括隨機,實現一類隨機負載均衡的算法,或者指定一些分區算法。kafka 提供了用戶自定義分區的方法,用戶能夠爲每個消息指定一個partitionkey,經過這個key來實現一些hash 分區算法。

效率。

batch的方式將有效的提升效率,減小網絡和磁盤io的佔用。這裏batch的大小,能夠再producer來設置,好比煥春100s,緩存1000條,或者數據的大小。

關於消息的完整性。

producer 能夠異步的並行的向kafka發送消息,可是一般你producer在發送完消息以後會獲得一個future的響應,返回的是offset或者發送過程遇到的錯誤。這裏,acks 這參數很重要,這個參數決定了producer要求leader partition收到的確認副本數。若是acks設置數量爲0,表示producer不會等待broker的響應,因此,producer沒法知道消息是否發送成功,這有可能會致使數據丟失,但這也是吞吐量最大的方式。

若是acks設置爲1,表示producer 和laeder partition收到消息的時獲得的broker的一個確認,這樣會有更好的可靠性。若是設置爲-1,則組要等待全部partition收到消息。這樣能保持最高的可靠性。

kafka 消息。

kafka消息有一個定長的header和變長的字節組成。kafka沒有限定單個消息的大小,但通常不超過一mb,一般控制在1-10kb之間。

Consumers

kafka 提供了兩套api。sample api 。是一套無狀態的api。每次請求都須要指定offset。因此也是最靈活的。

在kafka中,當前消息的offset是由consumer來維護的。consumer能夠本身決定讀哪些數據。好比,consumer 能夠從新消費已經消費國的數據。這些數據有一個過時限制。這個限制是可配置的。

high-level api 封裝了對集羣的訪問。能夠透明的消費一個topic。本身自己維持了一個消費隊列,每次消費下一個。

這裏consumer 用組來模擬了廣播和訂閱兩個功能。組是嫁接topic和consumer 的橋樑。 組對topic是來講是組內的成員均可以接受到消息,至關於廣播,組對成員來講,是訂閱,即你在這個組裏才能接受到這個消息。因此都在一個組,就至關於一個大廣播。

kafka 的核心特性

壓縮

kafka 支持以batch的方式來發送消息。在此之上,還支持對消息的壓縮。 producer端進行壓縮以後,在consumer端進行解壓。這麼作的好處是,每每大數據的瓶頸在於網絡,而不是cpu(因此會損耗必定的cpu。)
消息壓縮的信息,存儲在消息頭部的描述壓縮屬性字節。這個字節的後兩位表示消息的壓縮採用的編碼,若後兩位爲0,則表示消息未被壓縮。

消息可靠性

在消息系統中,保證消息的可靠性是很重要的。在實際消息的傳遞過程當中,會出現以下3種狀況:

  • 一個消息傳遞失敗

  • 一個消息被髮送屢次

  • exactly once,一個消息發送成功而且僅發送了一次。

有許多系統聲稱它們實現了exactly-once,但通常沒有考慮生產者或消費者在生產和消費過程當中有可能失敗的狀況。好比雖然一個producer成功發送一個消息,但消息丟失,或者成功發送到broker,也被consumer成功取走,可是這個consumer在處理消息時失敗了。

這裏從兩個角度來分析這個。

從producer的角度:在發送端,看producer會等待broker成功接收到消息的反饋,若是沒有接到broker的反饋信息,producer 會從新發送,(咱們知道kafka有備份機制,能夠經過參數設置是否等待全部節點都收到消息,而自己的消息也有緩存)

從consumer的角度:由於consumer 能夠調整offset,因此能夠重複消費消息。也保證了,一條消息被髮送一次就ok。

備份機制

備份機制是Kafka0.8版本的新特性,備份機制的出現大大提升了Kafka集羣的可靠性、穩定性。有了備份機制後,Kafka容許集羣中的節點掛掉後而不影響整個集羣工做。一個備份數量爲n的集羣容許n-1個節點失敗。在全部備份節點中,有一個節點做爲lead節點,這個節點保存了其它備份節點列表,並維持各個備份間的狀體同步。下面這幅圖解釋了Kafka的備份機制:
Alt text

kafka 高效性相關設計

消息持久化

首先這裏,kafka是高度依賴文件系統和緩存的。

文件系統的速度。文件系統的速度並非想象中的慢或者快。對於,順序寫入和隨機寫入二者有很大速度差。一個7200的硬盤順序寫入有600m/s的速度,隨機寫入有100k/s的速度。

緩存思路。因此,基本的數據寫入思路是,先拿內存緩存數據再刷新到磁盤。可是,衆所周知,內存的垃圾回收的代價很大,尤爲當數據量過大的時候,垃圾回收會很是昂貴。

感受這塊理解的不是很好
基於以上,獲得的一個結論就是利用文件系統而且依靠頁緩存比維護一個內存緩存或者其餘結構要好。而事實上,數據被傳輸到內核頁,稍後會被刷新。這裏加上了一個配置項來控制讓系統的用戶來控制數據在何時被刷新到物理硬盤上。

常數時間性能保證

沒太理解
消息系統中持久化數據結構的設計一般是維護者一個和消費隊列有關的B樹或者其它可以隨機存取結構的元數據信息。B樹是一個很好的結構,能夠用在事務型與非事務型的語義中。可是它須要一個很高的花費,儘管B樹的操做須要O(logN)。一般狀況下,這被認爲與常數時間等價,但這對磁盤操做來講是不對的。磁盤尋道一次須要10ms,而且一次只能尋一個,所以並行化是受限的。
直覺上來說,一個持久化的隊列能夠構建在對一個文件的讀和追加上,就像通常狀況下的日誌解決方案。儘管和B樹相比,這種結構不能支持豐富的語義,可是它有一個優勢,全部的操做都是常數時間,而且讀寫之間不會相互阻塞。這種設計具備極大的性能優點:最終系統性能和數據大小徹底無關,服務器能夠充分利用廉價的硬盤來提供高效的消息服務。
事實上還有一點,磁盤空間的無限增大而不影響性能這點,意味着咱們能夠提供通常消息系統沒法提供的特性。好比說,消息被消費後不是立馬被刪除,咱們能夠將這些消息保留一段相對比較長的時間(好比一個星期)。

進一步提升效率

在web開發中,每次一條log都會產生一次寫操做,這些小的寫操做的量很是大,另外這些log也要至少被一個或以上consumer消費。
因此,這裏出現了兩個比較低效的場景。

  • 太多小的io操做。

  • 過多的字節拷貝。

太多小的io操做。能夠經過發送messageset來搞定。因此對消息的處理,這裏沒有分開的序列化和反序列化的上步驟,消息的字段能夠按需反序列化(若是沒有須要,能夠不用反序列化)。

過多的字節拷貝。 爲了解決這個問題,kafka設計了一個標準字節消息。producer,broker,consumer共享這一種消息格式。kafka的message log 在broker端就是一些目錄文件。這些文件都是按照message set 來存的。

而這種通用的方式,很是重要: 持久化log塊的網絡傳輸。這傳輸經過一鍾很是搞笑的途徑來實現頁面緩存和socket之間的數據傳遞。 叫sendfile

這裏解釋下sendfile的做用,先聲明下通常的數據從文件到socket的路徑:

  1. 操做系統將數據從磁盤讀到內核空間的頁緩存中。

  2. 應用將數據從內核空間讀到用戶空間的頁緩存中。

  3. 應用將數據從用戶空間寫到內核空間的socket緩存。

  4. 操做系統將數據從socket緩存寫入到網卡緩存中。

這鐘方式很是低效,由於這裏有四次拷貝,兩次系統調用。若是使用sendfile,就能夠避免兩次拷貝:操做系統將數據直接從頁緩存發送到網絡上。因此這個過程,只有第一步和最後一步是須要的。利用上述zero copy,數據只須要拷貝到頁緩存一次,就能夠重複被consumer利用。這樣經過頁緩存和sendfile的結合,下游有不少consumers,也不會對整個集羣服務形成壓力。

kafka 集羣部署

爲了提升性能,儘可能與hadoop的集羣分開部署。若是共享節點的話,會影響其使用頁面緩存的性能。

kafka的性能主要在磁盤上。

kafka依賴於zookper,通常使用專用服務器來管理。zookeeper集羣的節點採用偶數個。注意,zookeeper集羣越大其讀寫性能越慢,由於zookeeper 要在節點之間同步數據。一個3節點的zookeeper集羣容許一個節點失敗,一個5節點的集羣容許2個節點失敗。

集羣大小

衡量kafka集羣所需的大小,最好是用模擬負載來測算一下。若是不想用模擬實驗,最好的方法是根據磁盤。

kafka 主要配置

broker config

log.dirs /tmp/kafka-logs Kafka數據存放的目錄。能夠指定多個目錄,中間用逗號分隔,當新partition被建立的時會被存放到當前存放partition最少的目錄。

參考

http://blog.csdn.net/suifeng3051/article/details/48053965

相關文章
相關標籤/搜索