Kafka基本原理概述

 Kafka的基本介紹nginx

Kafka是最初由Linkedin公司開發,是一個分佈式、分區的、多副本的、多訂閱者,基於zookeeper協調的分佈式日誌系統(也能夠當作MQ系統),常見能夠用於web/nginx日誌、訪問日誌、消息服務等等。web

 

主要應用場景:日誌收集系統和消息系統。算法

 

主要設計目標:網絡

一、以時間複雜度O(1)的方式提供消息持久化能力,即便對TB級以上數據也能保證常數時間的訪問性能。session

二、高吞吐率。即便在很是廉價的商用機器上也能作到單機支持每秒100K條消息的傳輸。app

三、支持kafka server間的消息分區,及分佈式消費,同時保證每一個partition內的消息順序傳輸。負載均衡

四、同時支持離線數據處理和實時數據處理。socket

 

kafka設計原理分析分佈式

一個典型的kafka集羣中包含若干producer,若干broker,若干consumer,以及一個zookeeper集羣。kafka經過zookeeper管理集羣配置,選舉leader,以及在消費組發送變化時進行rebalance。producer使用push模式將消息發佈到broker,consumer使用pull模式從broker訂閱並消費消息。函數

 

kafka專用術語:

一、broker:消息中間件處理結點,一個kafka節點就是一個broker,多個broker能夠組成一個kafka集羣。

二、Topic:一類消息,kafka集羣可以同時負責多個topic的分發。

三、partition:topic物理上的分組,一個topic能夠分爲多個partition,每一個partition是一個有序的隊列。

四、Segment:partition物理上由多個segment組成。

五、offset:每一個partition都由一系列有序的、不可變的消息組成,這些消息被連續的追加到partition中。partition中的每一個消息都有一個連續的序列號叫作offset,用於partition惟一標識一條消息。

六、Producer:負責發佈消息到Kafka broker。

七、Consumer:消息消費者,向Kafka broker讀取消息的客戶端。

八、Consumer Group:每一個Consumer屬於一個特定的Consumer Group。

 

kafka消息存儲格式

Topic & Partition

一個topic能夠任務一個一類消息,每一個topic將被分紅多個partition,每一個partition在存儲層面是append log文件。

在kafka文件存儲中,同一個topic下有多個不一樣partition,每一個partition爲一個目錄,partition命名規則爲:topic名稱+有序序號,第一個partition序號從0開始,序號最大值爲partition數量減1.

一、每一個partitin(目錄)至關於一個巨型文件被平均分配到多個segment(段)數據文件中。但每一個段segment file消息數量不必定相等,這種特性方便old segment file快速被刪除。

二、每一個partition只須要支持順序讀寫就好了,segment文件生命週期由服務端配置參數決定。

上面兩點這樣作的好處就是能快速刪除無用文件,有效提升磁盤利用率。

三、segment file組成:由2大部分組成,分別爲index file和data file,此2個文件一一對應,成對出現,後綴".index"和「.log」分別表示爲segment索引文件、數據文件.

四、segment文件命名規則:partion全局的第一個segment從0開始,後續每一個segment文件名爲上一個segment文件最後一條消息的offset值。數值最大爲64位long大小,19位數字字符長度,沒有數字用0填充。

segment中index與data file對應關係物理結構以下:

上圖中索引文件存儲大量元數據,數據文件存儲大量消息,索引文件中元數據指向對應數據文件中message的物理偏移地址。

其中以索引文件中元數據3,497爲例,依次在數據文件中表示第3個message(在全局partiton表示第368772個message),以及該消息的物理偏移地址爲497。

 

副本(Replication)策略

kafka的高可靠性的保障來源於其健壯的副本(replication)策略。

一、數據同步

kafka在0.8版本前沒有提供Partition的Replication機制,一旦Broker宕機,其上的全部Partition就都沒法提供服務,而Partition又沒有備份數據,數據的可用性就大大下降了。因此0.8後提供了Replication機制來保證Broker的failover(故障轉移)。

引入Replication以後,同一個Partition可能會有多個Replica,而這時須要在這些Replication之間選出一個Leader,Producer和Consumer只與這個Leader交互,其它Replica做爲Follower從Leader中複製數據。

二、副本放置策略:

爲了更好的作負載均衡,kafka儘可能將全部的partition均勻分配到整個集羣上。

kafka分配Replica的算法以下:

  a、將全部存活的N個Brokers和待分配的Partition排序。

  b、將第i個partition分配到第(i mod n)個Broker上,這個Partition的第一個Replica存在於這個分配的Broker上,而且會做爲partition的優先副本

  c、將第i個Partition的第j個Replica分配到第((i + j) mod n)個Broker上

假設集羣一共有4個brokers,一個topic有4個partition,每一個Partition有3個副本。下圖是每一個Broker上的副本分配狀況。

三、同步策略

Producer在發佈消息到某個Partition時,先經過Zookeeper找到該Partition的Leader,而後不管該Topic的Replication Factor爲多少,Producer只將該消息發送到該Partition的Leader。Leader會將該消息寫入其本地log。每一個Fllower都從Leader pull數據。這種方式上,Follower存儲的數據順序與Leader保持一致。Follower在收到該消息並寫入其LOG後,向Leader發送ACK。一旦Leader收到了ISR中的全部Replica的ACK,該消息就被認爲已經commit了,Leader將增長HW而且向Producer發送ACK。

爲了提升性能,每一個Follower在接收到數據後就立馬向Leader發送ACK,而非等到數據寫入Log中。所以,對於已經commit的消息,Kafka只能保證它被存於多個Replica的內存中,而不能保證它們被持久化到磁盤中,也就不能徹底保證異常發生後該條消息必定能被Consumer消費。

Consumer讀消息也是從Leader讀取,只有被commit過的消息纔會暴露給Consumer。

 

Kafka Replication的數據流以下圖所示:

 

對於kafka而言,定義一個Broker是否「活着」包含兩個條件:

  一、一是它必須維護與Zookeeper的session(這個能夠經過ookeeper的心跳機制來實現)

  二、二是Follower必須可以及時將Leader的消息複製過來,不能「落戶太多」

  Leader會跟蹤與其保持同步的Replica列表,該列表稱爲ISR(即in-sync Replica)。若是一個Follower宕機,或者落後太多,Leader將把它從ISR中移除。這裏所描述的「落後太多」指Follower複製的消息落後於Leader後的條數超過預約值或者Follower超過必定時間未向Leader發送fetch請求。

  Kafka只解決fail/recover,一條消息只有被ISR裏的全部Follower都從Leader複製過去纔會被認爲已提交。這樣就避免了部分數據被寫進了Leader,還沒來得及被任何Follower複製就宕機了,而形成數據丟失(Consumer沒法消費這些數據)。而對於Producer而言,它能夠選擇是否等待消息commit。這種機制確保了只要ISR有一個或以上的Follower,一條被commit的消息就不會丟失。

 

四、Leader選舉

Leader選舉本質上是一個分佈式鎖,有兩種方式實現基於ZooKeeper的分佈式鎖:

a、節點名稱惟一性:多個客戶端建立一個節點,只有成功建立節點的客戶端才能得到鎖

b、臨時順序節點:全部客戶端在某個目錄下建立本身的臨時順序節點,只有序號最小的纔得到鎖

 

kafka消息分組,消息消費原理

同一Topic的一條消息只能被同一個Consumer Group內的一個Consumer消費,但多個Consumer Group可同時消費這一消息。

這是Kafka用來實現一個Topic消息的廣播(發給全部的Consumer)和單播(發給某一個Consumer)的手段。一個Topic能夠對應多個Consumer Group。若是須要實現廣播,只要每一個Consumer有一個獨立的Group就能夠了。要實現單播只要全部的Consumer在同一個Group裏。用Consumer Group還能夠將Consumer進行自由的分組而不須要屢次發送消息到不一樣的Topic。

 

Push vs Pull

做爲一個消息系統,Kafka遵循了傳統的方式,選擇由Producer向broker push消息並由Consumer從broker pull消息。

push模式很難適應消費速率不一樣的消費者,由於消息發送速率是由broker決定的。push模式的目標是儘量以最快速度傳遞消息,可是這樣很容易形成Consumer來不及處理消息,典型的表現就是拒絕服務以及網絡擁塞。而pull模式則能夠根據Consumer的消費能力以適當的速率消費消息。

對於Kafka而言,pull模式更合適。pull模式可簡化broker的設計,Consumer可自主控制消費消息的速率,同時Consumer能夠本身控制消費方式——便可批量消費也可逐條消費,同時還能選擇不一樣的提交方式從而實現不一樣的傳輸語義。

 

Kafka順序寫入與數據讀取

生產者(producer)是負責向Kafka提交數據的,Kafka會把收到的消息都寫入到硬盤中,它絕對不會丟失數據。爲了優化寫入速度Kafak採用了兩個技術,順序寫入和MMFile(文件管理系統)。

順序寫入

由於硬盤是機械結構,每次讀寫都會尋址,寫入,其中尋址是一個「機械動做」,它是最耗時的。因此硬盤最「討厭」隨機I/O,最喜歡順序I/O。爲了提升讀寫硬盤的速度,Kafka就是使用順序I/O。

每條消息都被append到該Partition中,屬於順序寫磁盤,所以效率很是高。

對於傳統的message queue而言,通常會刪除已經被消費的消息,而Kafka是不會刪除數據的,它會把全部的數據都保留下來,每一個消費者(Consumer)對每一個Topic都有一個offset用來表示讀取到了第幾條數據。

即使是順序寫入硬盤,硬盤的訪問速度仍是不可能追上內存。因此Kafka的數據並非實時的寫入硬盤,它充分利用了現代操做系統分頁存儲來利用內存提升I/O效率。

在Linux Kernal 2.2以後出現了一種叫作「零拷貝(zero-copy)」系統調用機制,就是跳過「用戶緩衝區」的拷貝,創建一個磁盤空間和內存空間的直接映射,數據再也不復制到「用戶態緩衝區」系統上下文切換減小2次,能夠提高一倍性能。

經過mmap,進程像讀寫硬盤同樣讀寫內存(固然是虛擬機內存)。使用這種方式能夠獲取很大的I/O提高,省去了用戶空間到內核空間複製的開銷(調用文件的read會把數據先放到內核空間的內存中,而後再複製到用戶空間的內存中。)

 

消費者(讀取數據)

試想一下,一個Web Server傳送一個靜態文件,如何優化?答案是zero copy。傳統模式下咱們從硬盤讀取一個文件是這樣的。

先複製到內核空間(read是系統調用,放到了DMA,因此用內核空間),而後複製到用戶空間(一、2);從用戶空間從新複製到內核空間(你用的socket是系統調用,因此它也有本身的內核空間),最後發送給網卡(三、4)。

Zero Copy中直接從內核空間(DMA的)到內核空間(Socket的),而後發送網卡。這個技術很是廣泛,Nginx也是用的這種技術。

實際上,Kafka把全部的消息都存放在一個一個的文件中,當消費者須要數據的時候Kafka直接把「文件」發送給消費者。當不須要把整個文件發出去的時候,Kafka經過調用Zero Copy的sendfile這個函數,這個函數包括:

  • out_fd做爲輸出(通常及時socket的句柄)

  • in_fd做爲輸入文件句柄

  • off_t表示in_fd的偏移(從哪裏開始讀取)

  • size_t表示讀取多少個

 

轉自:http://www.linkedkeeper.com/detail/blog.action?bid=1016

相關文章
相關標籤/搜索