我們在學(xué)習(xí)Kafka的時候,到底在學(xué)習(xí)什么?
點擊上方藍(lán)色字體,選擇“設(shè)為星標(biāo)”
回復(fù)”面試“獲取更多驚喜

之前的文章你可以參考:
《我們在學(xué)習(xí)Flink的時候,到底在學(xué)習(xí)什么》
《我們在學(xué)習(xí)Spark的時候,到底在學(xué)習(xí)什么》
我在之前《Kafka源碼閱讀的一些小提示》寫了一些關(guān)于Kafka源碼閱讀的注意事項。
本文會從一個小白的角度講Kafka學(xué)習(xí)的整體方法,包括背景、核心概念、核心原理、源碼閱讀、實際應(yīng)用等。
注意,本文只是一個學(xué)習(xí)路徑,不會詳細(xì)展開,各位讀者需要根據(jù)自己的實際情況針對性的去學(xué)習(xí)其中的某一個部分。

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

八千里路云和月 | 從零到大數(shù)據(jù)專家學(xué)習(xí)路徑指南
我們在學(xué)習(xí)Flink的時候,到底在學(xué)習(xí)什么?
193篇文章暴揍Flink,這個合集你需要關(guān)注一下
Flink生產(chǎn)環(huán)境TOP難題與優(yōu)化,阿里巴巴藏經(jīng)閣YYDS
Flink CDC我吃定了耶穌也留不住他!| Flink CDC線上問題小盤點
我們在學(xué)習(xí)Spark的時候,到底在學(xué)習(xí)什么?
硬剛Hive | 4萬字基礎(chǔ)調(diào)優(yōu)面試小總結(jié)
4萬字長文 | ClickHouse基礎(chǔ)&實踐&調(diào)優(yōu)全視角解析
【面試&個人成長】2021年過半,社招和校招的經(jīng)驗之談
大數(shù)據(jù)方向另一個十年開啟 |《硬剛系列》第一版完結(jié)
我寫過的關(guān)于成長/面試/職場進(jìn)階的文章
你好,我是王知無,一個大數(shù)據(jù)領(lǐng)域的硬核原創(chuàng)作者。
做過后端架構(gòu)、數(shù)據(jù)中間件、數(shù)據(jù)平臺&架構(gòu)、算法工程化。
專注大數(shù)據(jù)領(lǐng)域?qū)崟r動態(tài)&技術(shù)提升&個人成長&職場進(jìn)階,歡迎關(guān)注。
