我們在學習Kafka的時候,到底在學習什么?
點擊上方藍色字體,選擇“設為星標”
回復”面試“獲取更多驚喜

之前的文章你可以參考:
我在之前《Kafka源碼閱讀的一些小提示》寫了一些關于Kafka源碼閱讀的注意事項。
本文會從一個小白的角度講Kafka學習的整體方法,包括背景、核心概念、核心原理、源碼閱讀、實際應用等。
注意,本文只是一個學習路徑,不會詳細展開,各位讀者需要根據自己的實際情況針對性的去學習其中的某一個部分。

Kafka的背景
Kafka是LinkedIn開發(fā)并開源的一套分布式的高性能消息引擎服務,后來被越來越多的公司應用在自己的系統中,可以說,截止目前為止Kafka是大數據時代數據管道技術的首選。在設計的時候,它就實現了高可靠、高吞吐、高可用和可伸縮,得益于這些特性,加上活躍的社區(qū),Kafka成為了一個完備的分布式消息引擎解決方案。
Kafka在大數據領域扮演者舉足輕重的角色:
消息系統:Kafka具備系統解耦、冗余存儲、流量削峰、緩沖、異步通信、擴展性、可恢復性等強大的功能。
存儲系統:Kafka 的消息持久化功能和多副本機制,我們可以把Kafka作為長期的數據存儲系統來使用。
流式處理平臺:Kafka還提供了一個完整的流式處理類庫,比如窗口、連接、變換和聚合等各類操作,也是一個分布式流處理平臺。
Kafka的入門
這部分你需要對消息引擎有基本的了解,并且知道對Kafka系統術語、Kafka角色定位、和版本變遷有足夠的了解。
我這里列出了部分核心概念如下:
消息:Record。Kafka 是消息引擎嘛,這里的消息就是指 Kafka 處理的主要對象。
主題:Topic。主題是承載消息的邏輯容器,在實際使用中多用來區(qū)分具體的業(yè)務。
分區(qū):Partition。一個有序不變的消息序列。每個主題下可以有多個分區(qū)。
消息位移:Offset。表示分區(qū)中每條消息的位置信息,是一個單調遞增且不變的值。
副本:Replica。Kafka 中同一條消息能夠被拷貝到多個地方以提供數據冗余,這些地方就是所謂的副本。副本還分為領導者副本和追隨者副本,各自有不同的角色劃分。副本是在分區(qū)層級下的,即每個分區(qū)可配置多個副本實現高可用。
生產者:Producer。向主題發(fā)布新消息的應用程序。
消費者:Consumer。從主題訂閱新消息的應用程序。
消費者位移:Consumer Offset。表征消費者消費進度,每個消費者都有自己的消費者位移。
消費者組:Consumer Group。多個消費者實例共同組成的一個組,同時消費多個分區(qū)以實現高吞吐。
重平衡:Rebalance。消費者組內某個消費者實例掛掉后,其他消費者實例自動重新分配訂閱主題分區(qū)的過程。Rebalance 是 Kafka 消費者端實現高可用的重要手段。
ISR:ISR是In-Sync Replica的縮寫,ISR集合表示的是目前可用且消息量與Leader相差不多的副本集合。
HW:HW(HightWatermark,水位線)標記了一個特殊的offset,消費者處理消息的時候,HW之后的消息對于消費者是不可見的。HW也是由leader副本管理的。
LEO:LEO(Log End Offset)是所有副本都會有的一個offset標記,它指向當前副本的最后一個消息的offset。
除此之外,在Kafka的每一個模塊,我們都能看到更多更細節(jié)的概念。
Kafka的生產者和消費者
這部分也是我們編程的核心,你需要知道生產者和消費者之間的關系。生產者就是負責向 Kafka 發(fā)送消息的應用程序,你需要知道Kafka提供了哪些常用的接口和方法,并且對其中的參數配置有詳細了解。
在生產者中有一個非常重要的參數需要你注意并了解他們的作用:
acks
max.request.size
retries和retry.backoff.ms
具體的參數列表如下:
必選屬性有3個:
bootstrap.servers:該屬性指定broker的地址清單,地址的格式為host:port。清單里不需要包含所有的broker地址,生產者會從給定的broker里查詢其他broker的信息。不過最少提供2個broker的信息,一旦其中一個宕機,生產者仍能連接到集群上。
key.serializer:生產者接口允許使用參數化類型,可以把Java對象作為鍵和值傳broker,但是broker希望收到的消息的鍵和值都是字節(jié)數組,所以,必須提供將對象序列化成字節(jié)數組的序列化器。key.serializer必須設置為實現org.apache.kafka.common.serialization.Serializer的接口類,默認為
org.apache.kafka.common.serialization.StringSerializer,也可以實現自定義的序列化器。
value.serializer:同上。
可選參數:
acks:指定了必須要有多少個分區(qū)副本收到消息,生產者才會認為寫入消息是成功的,這個參數對消息丟失的可能性有重大影響。
acks=0:生產者在寫入消息之前不會等待任何來自服務器的響應,容易丟消息,但是吞吐量高。
acks=1:只要集群的首領節(jié)點收到消息,生產者會收到來自服務器的成功響應。如果消息無法到達首領節(jié)點(比如首領節(jié)點崩潰,新首領沒有選舉出來),生產者會收到一個錯誤響應,為了避免數據丟失,生產者會重發(fā)消息。不過,如果一個沒有收到消息的節(jié)點成為新首領,消息還是會丟失。默認使用這個配置。
acks=all:只有當所有參與復制的節(jié)點都收到消息,生產者才會收到一個來自服務器的成功響應。延遲高。
buffer.memory:設置生產者內存緩沖區(qū)的大小,生產者用它緩沖要發(fā)送到服務器的消息。
max.block.ms:指定了在調用send()方法或者使用partitionsFor()方法獲取元數據時生產者的阻塞時間。當生產者的發(fā)送緩沖區(qū)已滿,或者沒有可用的元數據時,這些方法就會阻塞。在阻塞時間達到max.block.ms時,生產者會拋出超時異常。
batch.size:當多個消息被發(fā)送同一個分區(qū)時,生產者會把它們放在同一個批次里。該參數指定了一個批次可以使用的內存大小,按照字節(jié)數計算。當批次內存被填滿后,批次里的所有消息會被發(fā)送出去。
retries:指定生產者可以重發(fā)消息的次數。
receive.buffer.bytes和send.buffer.bytes:指定TCP socket接受和發(fā)送數據包的緩存區(qū)大小。如果它們被設置為-1,則使用操作系統的默認值。如果生產者或消費者處在不同的數據中心,那么可以適當增大這些值,因為跨數據中心的網絡一般都有比較高的延遲和比較低的帶寬。
linger.ms:指定了生產者在發(fā)送批次前等待更多消息加入批次的時間。一個典型的生產者代碼如下:
public class KafkaProducer {
public static final String brokerList = "localhost:9092";
public static final String topic = "topic-demo";
public static Properties initConfig(){
Properties props = new Properties();
props.put("bootstrap.servers", brokerList);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("client.id", "producer.client.id.demo");
return props;
}
public static void main(String[] args) {
Properties props = initConfig();
KafkaProducer<String, String> producer = new KafkaProducer<>(props);
ProducerRecord<String, String> record =
new ProducerRecord<>(topic, "Hello, Kafka!");
try {
producer.send(record);
} catch (Exception e) {
e.printStackTrace();
}
}
}與生產者對應的是消費者,應用程序可以通過 KafkaConsumer 來訂閱主題,并從訂閱的主題中拉取消息。
消費者(Consumer)負責訂閱 Kafka 中的主題(Topic),并且從訂閱的主題上拉取消息。與其他一些消息中間件不同的是:在 Kafka 的消費理念中還有一層消費組(Consumer Group)的概念,每個消費者都有一個對應的消費組。當消息發(fā)布到主題后,只會被投遞給訂閱它的每個消費組中的一個消費者。
同樣的,消費者端也有很多非常重要的參數,你可以在ConsumerConfig這個類中找到,這里就不一一列舉了。
一個典型的消費者代碼如下:
public class KafkaConsumer {
public static final String brokerList = "localhost:9092";
public static final String topic = "topic-demo";
public static final String groupId = "group.demo";
public static final AtomicBoolean isRunning = new AtomicBoolean(true);
public static Properties initConfig(){
Properties props = new Properties();
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("bootstrap.servers", brokerList);
props.put("group.id", groupId);
props.put("client.id", "consumer.client.id.demo");
return props;
}
public static void main(String[] args) {
Properties props = initConfig();
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList(topic));
try {
while (isRunning.get()) {
ConsumerRecords<String, String> records =
consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
System.out.println("topic = " + record.topic()
+ ", partition = "+ record.partition()
+ ", offset = " + record.offset());
System.out.println("key = " + record.key()
+ ", value = " + record.value());
//do something to process record.
}
}
} catch (Exception e) {
log.error("occur exception ", e);
} finally {
consumer.close();
}
}
}
Kafka中的核心原理
在這部分你需要了解Kafka的最核心的設計原理,主要包括:
存儲機制
備份和副本機制
日志設計
Controller控制器
Rebalance
可靠性設計
延遲、死信、重試隊列等
Kafka的運維和監(jiān)控
Kafka自身提供非常強大的運維和監(jiān)控工具,在這部分如果你的工作包括了線上Kafka集群的運營,那么你需要對這些工具非常了解。
包括:
主題管理
副本和消息管理
權限管理
常見的工具和腳本
跨集群備份
Kafka源碼閱讀
這部分你需要參考:《Kafka源碼閱讀的一些小提示》
Kafka的應用
通常我們使用Kafka大部分情況會搭配Spark的Flink使用。
針對和Spark的結合,你需要對下面這個連接器非常熟悉:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
</dependency>針對和Flink的結合,你需要對下面這個連接器非常熟悉:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.8_2.10</artifactId>
</dependency>Kafka的野心
Kafka還有一個模塊:Kafka Stream。
Kafka Stream定位是輕量級的流計算類庫。他的出現使得Kafka的定位從原來的分布式、分區(qū)、有備份的提交日志服務變成了完整的分布式消息引擎和流式計算處理引擎。
Kafka Stream 的特點如下:
Kafka Stream 提供了一個非常簡單而輕量的 Library,它可以非常方便地嵌入任意Java應用中,也可以任意方式打包和部署
除了 Kafka 外,無任何外部依賴
充分利用 Kafka 分區(qū)機制實現水平擴展和順序性保證
通過可容錯的 state store 實現高效的狀態(tài)操作(如 windowed join 和aggregation)
支持正好一次處理語義
提供記錄級的處理能力,從而實現毫秒級的低延遲
支持基于事件時間的窗口操作,并且可處理晚到的數據(late arrival of records)
同時提供底層的處理原語 Processor(類似于 Storm 的 spout 和 bolt),以及高層抽象的DSL(類似于 Spark 的 map/group/reduce)
Kafka Stream 作為流式處理類庫,直接提供具體的類給開發(fā)者調用,整個應用的運行方式主要由開發(fā)者控制,方便使用和調試。
Kafka作為大數據領域最成熟、最完善的框架之一,仍然在高速迭代和演進中,是每個大數據開發(fā)者都必須掌握的框架。

Flink生產環(huán)境TOP難題與優(yōu)化,阿里巴巴藏經閣YYDS
Flink CDC我吃定了耶穌也留不住他!| Flink CDC線上問題小盤點
4萬字長文 | ClickHouse基礎&實踐&調優(yōu)全視角解析
你好,我是王知無,一個大數據領域的硬核原創(chuàng)作者。
做過后端架構、數據中間件、數據平臺&架構、算法工程化。
專注大數據領域實時動態(tài)&技術提升&個人成長&職場進階,歡迎關注。
