上篇博文已經講解了如何安裝Kafka的集羣環境,今天我們就來一本帶大家瞭解下Kafka,瞭解kafka的特點以及基本概念
kafka的特點
Kafka設計的初衷是爲了解決互聯網公司超大量級數據的實時傳輸,爲了實現這個目標,需要考慮以下四個方面的問題
- 吞吐量/延時
- 消息持久化
- 負載均衡和故障轉移
- 伸縮性
- 吞吐量是Kafka每秒能夠處理的消息數,那麼很顯然,我們都希望系統的吞吐量越大越好,與此同時,還有個客戶端發送指令,kafka服務端接受指令然後反饋給客戶端的時間,這個時間就是延時,那麼對於一個系統而言,延時時間間隔越短越好。而kafka是一個高吞吐量和低延時的系統,那麼他是如何實現的呢?
- 大量使用操作系統頁緩存,內存的操作速度快且命中率高
由於大量使用也緩存,故讀取消息時大部分消息很有可能依然保存在頁緩存中,因此可以直接命中緩存,不用“穿透”到底層的物理磁盤上獲取消息,從而極大的提升了讀取的吞吐量
- kafka不直接參與物理I/O操作,而是交由最擅長此事的操作系統來完成
- 採用追加寫入方式,摒棄了緩慢的磁盤隨機I/O操作
kafka在設計時採用了追加寫入消息的方式,即只能在日誌文件末尾追加寫入新的消息,且不允許修改已經寫入的消息,因此他屬於典型的磁盤順序訪問型操作,這種類型的操作訪問速度堪比內存的讀寫速度,性能是非常高的
- 使用sendfile爲代表的零拷貝技術加強網絡間的數據傳輸效率
kafka在讀取消息時,會首先從OS的頁緩存中讀取,如果命中便把消息經頁緩存直接發送到網絡的Socket上,這個過程就是零拷貝技術
- 消息引擎都必須要具有持久化的機制,持久化的機制有如下的好處:
- 讓消息的生產和消費解耦
消息生產者只需要將消息發送給kafka即可,不必關係消息是被誰消費的,何時消費的
- 靈活的消息處理
消息保存在kafka中,方便實現消息重演這樣的需求,可以很方便的處理消息
- 減少內存的使用
將消息持久化到kafka中,給內存釋放出更多的空間,方便kafka使用頁面緩存技術來提升系統的性能
- kafka是一個分佈式流處理平臺,所以kafka具有分佈式系統的兩個重要的特性——負載均衡和故障轉移
- 負載均衡就是讓系統的負載根據一定的規則均衡的分配到所有參與工作的機器上,從而最大限度的提升整體系統的運行效率,kafka的負載均衡實際上是通過partition以及leader來實現的,後面再詳細介紹
- 當分佈式系統的一個節點出現了問題,無法發送心跳或者會話,則master服務器認爲備份服務器已經無法工作 ,將會根據一系列的算法來計算新的節點,實現了系統的高可用性
- 伸縮性,所謂的伸縮性表示向分佈方式中額外的增加計算資源時吞吐量提升的能力,通俗點來講,就是如何通過增加節點來擴展kafka集羣環境的系統,這點kafka是通過將服務器的狀態的相關的參數交給zookeeper來管理
kafka的基本概念
- 消息
消息是每一個消息引擎的重中之重,好的消息的結構設計能極大的優化系統的性能,這裏kafka處理的非常好,我們也有必要理解下kafka的消息的組成以及爲什麼
首先消息是由:消息頭部、Key和Value組成,其中消息頭部還包括:CRC、版本號、屬性、時間戳和鍵長度。
這裏主要說明4個字段的含義:
- 消息鍵:對消息做partition時使用,即決定消息被保存在某個topic下的哪個partition
- 消息體:保存實際的消息數據
- 時間戳:消息發送的時間戳,主要用於流式處理以及其他依賴時間的處理語義,默認是當前時間
- 屬性:kafka使用一個字節來保存消息的壓縮屬性,當前只支持4中壓縮屬性:0——無壓縮 1——GZIP壓縮 2——Snappy壓縮 3——LZ4壓縮
Kafka使用二進制字節數組來保存消息,這個和RabbitMQ是一樣的,爲什麼要這樣設計呢? 試想一下,如果我們使用Java的類來實現,如果存儲成String字符串格式 ,那麼對於Java內存模型,對象保存的開銷是很大的,隨着堆裏面的數據量越來越大,GC的也就越頻繁,那麼系統的性能也就越差,其他Java的操作系統通常默認是開啓頁緩存機制的,也就是說堆上保存的對象可能在頁緩存中還保留一份,這也造成了極大的資源浪費
因此,kafka在消息設計時,直接使用緊湊二進制字節數據,這樣我們就能有更多的內存使用
- topic和partition
準確來說,topic
是一個邏輯上的概念,一般我們用來作爲業務上的一個區分的尺度,代表一類消息,比如說A發送消息到topicA中,B發送消息到topicB中,一個topic
可能被多個消費者來消費,爲了提供系統的吞吐量,kafka提出了partition
的概念,我們可以認爲一個topic
是由多個partition
組成的
kafka中的partition
是不可修改的有序消息隊列,每個partition
有自己專屬的partition
號,通常是從0開始的,用戶對partition
唯一能做的就是在消息隊列的尾部追加寫入消息,每個消息隊列中都有一個序號,這個序號就是接下里要說的 offset
- offset
partition
中的每個消息隊列都是固定的,並且從0開始遞增
綜合之前所說的topic
和partition
以及offset
我們可以確定一條消息
- replica
我們知道partition
是有序的消息隊列,那麼一定不是保存在一個地方的,否則一旦kafka掛了,其上保存的消息也就丟失了,分佈式要實現高可用性,這裏kafka採用了冗餘機制——備份多個日誌,這些日誌在kafka中就被稱爲replica
副本,他存在的唯一目的就是防止數據丟失
replica
分爲: leader replica
和follower replica
,follower replica
唯一的用途就是leader replica
所在的broker
宕機了,不能對外提供服務了,則kafka就會從剩餘的replica
中選舉新的leader來提供服務
- leader和follower
上面我們說過什麼是leader
和follower
,在kafka中,leader
對外提供服務,follower
只能被動的追隨leader
的狀態,保持與leader
同步,follower
唯一存在的目的就是當leader
宕機了,被選舉稱爲新的leader
來繼續提供服務
kafka保證統一個partition
的多個replica
一定不會分配在同一臺broker
上,畢竟如果同一個broker
上有同一個partition
的多個replica
,那麼將無法實現備份冗餘的效果
- ISR
ISR(in-sync replica)在kafka中是一個重要的概念, 翻譯過來就是與 leader replica保持同步的replica集合, kafka爲partition
動態維護一個replica
集合,該集合中的所有的replica保存的消息日誌都與leader replica
保持同步狀態,只有這個集合中的replica
才能被選爲leader
,也只有該集合中的replica
都同時接收到同一條消息,kafka纔會將該消息置爲“已提交”狀態,即認爲該條消息發送成功
這裏需要注意兩點:
- ISR中至少需要一個“活着”的
replica
- “已提交”消息