Kafka精進 | 一文讀懂Producer消息發送機制

前面我們總結了broker端的核心參數,一些服務端原理細節後面文章再聊。本文我們重點討論Producer端的消息發送機制,希望通過本文我們能整體掌握Producer端的原理。

1、Producer架構

一圖勝千言,這裏筆者畫了一張Producer端消息發送的基本流程,如下圖:

總的來說,Kafka生產端發送數據過程涉及到序列化器Serializer、分區器Partitioner,消息緩存池Accumulator,還可能會涉及到攔截器Interceptor(這部分暫不做介紹)。由於篇幅有限這裏儘量做到言簡意賅。

2、客戶端與數據結構

2.1 新舊Producer

Kafka 0.8.2引入了新版本Producer客戶端,並自0.9.0版本開始穩定並建議生產使用,新版本Producer是o.a.k.clients.producer.KafkaProducer,見:

//新版本Producer
org.apache.kafka.clients.producer.KafkaProducer<K,V>
//舊版本Producer
kafka.javaapi.producer.Producer<K,V>

與舊版本相比,新版本Producer有點不同,一是連接Kafka方式上,舊版本連接的是Zookeeper,而新版本Producer連接的則是Broker;二是新版本Producer採用異步方式發送消息,與之前同步發送消息相對性能上大幅提升。

2.2 消息數據結構

Kafka將一條待發送的消息抽象爲ProducerRecord對象,其數據結構是:

public class ProducerRecord<K, V> {
    private final String topic; //目標topic
    private final Integer partition; //目標partition
    private final Headers headers;//消息頭信息
    private final K key;   //消息key
    private final V value; //消息體
    private final Long timestamp; //消息時間戳
    //省略構造方法與成員方法
}

目前消息結構包括6個核心屬性,分別是topic,partition,headers,key,value與timestamp,各屬性含義如上也比較好理解,其中headers屬性是Kafka 0.11.x 版本引入的,可以用它存儲一些應用或業務相關的信息。

3、序列化機制

3.1 序列化與反序列化

Kafka遵守生產者消費者模式,這中間涉及到序列化與反序列化。Producer發送消息要通過序列化器(Serializer)將消息對象轉換成字節數組,才能通過網絡傳輸到服務端,消費端則需要通過反序列化器(Deserializer)從服務端拉取字節數組轉成消息對象。可以用下圖表示:

生產端使用序列化器的方式非常簡單,只要指定key.serializer與value.serializer即可,如下示例:

props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

消費端使用的反序列化器要和生產端的序列化器要一一對應,否則將無法解析出想要的數據。

3.2 默認序列化器

目前Kafka提供了十幾張序列化器,常見的序列化器有:

ByteArraySerializer // 序列化Byte數組,本質上什麼都不用做。
ByteBufferSerializer // 序列化ByteBuffer。
BytesSerializer // 序列化Kafka自定義的Bytes類。
StringSerializer // 序列化String類型。
LongSerializer   // 序列化Long類型。
IntegerSerializer // 序列化Integer類型。
ShortSerializer  // 序列化Short類型。
DoubleSerializer // 序列化Double類型。
FloatSerializer  // 序列化Float類型。

除了使用Kafka自帶的序列化器,我們也可以自定義序列化器,只要實現Kafka Serializer接口並實現序列化邏輯即可,不過一般自帶序列化器已經夠用了。

4、消息分區機制

4.1 Topic分區

首先簡單說一下分區的概念,可以用下圖表示:

分區即partition是Kafka中非常重要的概念,分區的作用主要是爲Kafka提供負載均衡的能力,同時也是Kafka高吞吐量的保證。生產端要將數據發送到具體topic的某一個分區中,並且消息只在分區內有序。

4.2 分區器

消息通過send方法發送過程中,可能會經過分區器(Partitioner)的作用才能發往broker端。如果消息ProducerRecord中指定了partition字段,那麼就不需要分區器的作用,因爲partition代表的就是所要發往的分區號。

Kafka提供了默認分區器o.a.k.clients.producer.internals.DefaultPartitioner,並通過其partition()定義主要的分區分配邏輯。接下來我們看一下Kafka相關的分區策略。

4.3 分區策略

所謂分區策略就是決定消息發往具體分區所採用的算法或邏輯。目前Kafka主要提供兩種分區策略:哈希策略與輪詢策略。

當沒有爲消息指定key即key爲null時,消息會以輪詢的方式發送到各個分區(各個版本實現可能不一樣,還有一種隨機策略,有待考證);當key不爲null時,默認分區器會使用key的哈希值(採用Murmur2Hash算法)對partition數量取模,決定要把消息發送到哪個partition上。

5、消息緩衝池

5.1 緩存池介紹

生產端ProducerRecord經過序列化器、分區器處理後,並不是直接發往broker端,而是發送到客戶端的消息緩衝池(Accumulator) 中,最後交由Sender線程發往broker端。

緩衝池最大大小由參數buffer.memory控制,默認是32M,當生產消息的速度過快導致buffer滿了的時候,將阻塞max.block.ms時間,超時拋異常,所以buffer的大小可以根據實際的業務情況進行適當調整。

5.2 批量發送

發送到緩衝池中消息將會被分爲一個一個的batch,分批次的發送到broker 端,批次大小由參數batch.size控制,默認16KB。這就意味着正常情況下消息會攢夠16KB時纔會批量發送到broker端,所以一般減小batch大小有利於降低消息延時,增加batch大小有利於提升吞吐量。

但是消息並不是必須要達到一個batch尺寸纔會批量發送到服務端呢,Producer端提供了另一個重要參數linger.ms,用來控制batch最大的空閒時間,超過該時間的batch也會被髮送到broker端。

6、總結

本文先是介紹了Producer客戶端與ProducerRecord數據結構,然後重點介紹了序列化器Serializer、分區器Partitioner以及消息緩衝池Accumulator的基本原理,由於篇幅有限,還有一些細節比如攔截器、Sender線程並未涉及到,後續我們再來討論。希望通過本文讀者可以對Producer端消息發送機制有一個比較整體的認識。

往期推薦  點擊標題可跳轉

Kafka精進 | Broker服務端核心參數解析

如何快速全面掌握Kafka?5000字吐血整理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章