1.生產者消息發送流程
1.發送原理
在消息發送的過程中,涉及到了兩個線程——main 線程和 Sender 線程。在 main 線程中創建了一個雙端隊列 RecordAccumulator。main 線程將消息發送給 RecordAccumulator,Sender 線程不斷從 RecordAccumulator 中拉取消息發送到 Kafka Broker。
2.生產者重要參數列表
參數名稱 | 描述 |
---|---|
bootstrap.servers | 生產者連接集羣所需的 broker 地 址 清 單 。 例 如192.168.58.130:9092,192.168.58.131:9092,192.168.58.132:9092,可以設置 1 個或者多個,中間用逗號隔開。注意這裏並非需要所有的 broker 地址,因爲生產者從給定的 broker裏查找到其他 broker 信息 |
key.serializer 和 value.serializer | 指定發送消息的 key 和 value 的序列化類型。一定要寫全類名 |
buffer.memory | RecordAccumulator 緩衝區總大小,默認 32m |
batch.size | 緩衝區一批數據最大值,默認 16k。適當增加該值,可以提高吞吐量,但是如果該值設置太大,會導致數據傳輸延遲增加 |
linger.ms | 如果數據遲遲未達到 batch.size,sender 等待 linger.time之後就會發送數據。單位 ms,默認值是 0ms,表示沒有延遲。生產環境建議該值大小爲 5-100ms 之間 |
acks | 0:生產者發送過來的數據,不需要等數據落盤應答。 1:生產者發送過來的數據,Leader 收到數據後應答。 -1(all):生產者發送過來的數據,Leader+和 isr 隊列裏面的所有節點收齊數據後應答。 默認值是-1,-1 和all 是等價的 |
max.in.flight.requests.per.connection | 允許最多沒有返回 ack 的次數,默認爲 5,開啓冪等性要保證該值是 1-5 的數字 |
retries | 當消息發送出現錯誤的時候,系統會重發消息。retries表示重試次數。默認是 int 最大值,2147483647。如果設置了重試,還想保證消息的有序性,需要設置MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION=1否則在重試此失敗消息的時候,其他的消息可能發送成功了。 |
retry.backoff.ms | 兩次重試之間的時間間隔,默認是 100ms |
enable.idempotence | 是否開啓冪等性,默認 true,開啓冪等性 |
compression.type | 生產者發送的所有數據的壓縮方式。默認是 none,也就是不壓縮。 支持壓縮類型:none、gzip、snappy、lz4 和 zstd。 |
2.發送API
在操作API之前,需要先創建Java的Maven項目,並引入相關的依賴,其中的核心便是kafka-clients
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>3.6.1</version>
</dependency>
1.異步發送 API
1.普通異步發送
package cn.coreqi.kafka.producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Properties;
public class CustomProducer {
public static void main(String[] args) {
// 1. 創建 kafka 生產者的配置對象
Properties properties = new Properties();
// 2. 給 kafka 配置對象添加配置信息:bootstrap.servers
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.58.130:9092");
// key,value 序列化(必須):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringSerializer");
// 3. 創建 kafka 生產者對象
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
// 4. 調用 send 方法,發送消息
for (int i = 0; i < 5; i++) {
kafkaProducer.send(new ProducerRecord<>("first","coreqi " + i));
}
// 5. 關閉資源
kafkaProducer.close();
}
}
2.帶回調函數的異步發送
回調函數會在 producer 收到 ack 時調用,爲異步調用,該方法有兩個參數,分別是元數據信息(RecordMetadata)和異常信息(Exception),如果 Exception 爲 null,說明消息發送成功,如果 Exception 不爲 null,說明消息發送失敗。
注意:消息發送失敗會自動重試,不需要我們在回調函數中手動重試。
package cn.coreqi.kafka.producer;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
public class CustomProducerCallback {
public static void main(String[] args) throws InterruptedException {
// 1. 創建 kafka 生產者的配置對象
Properties properties = new Properties();
// 2. 給 kafka 配置對象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.58.130:9092");
// key,value 序列化(必須):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
// 3. 創建 kafka 生產者對象
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
// 4. 調用 send 方法,發送消息
for (int i = 0; i < 5; i++) {
// 添加回調
kafkaProducer.send(new ProducerRecord<>("first", "coreqi " + i), new Callback() {
// 該方法在 Producer 收到 ack 時調用,爲異步調用
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if (exception == null) {
// 沒有異常,輸出信息到控制檯
System.out.println(" 主題: " +
metadata.topic() + "->" + "分區:" + metadata.partition());
} else {
// 出現異常打印
exception.printStackTrace();
}
}
});
// 延遲一會會看到數據發往不同分區
Thread.sleep(2);
}
// 5. 關閉資源
kafkaProducer.close();
}
}
2.同步發送 API
只需在異步發送的基礎上,再調用一下 get()方法即可。
package cn.coreqi.kafka.producer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
public class CustomProducerSync {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1. 創建 kafka 生產者的配置對象
Properties properties = new Properties();
// 2. 給 kafka 配置對象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.58.130:9092");
// key,value 序列化(必須):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
// 3. 創建 kafka 生產者對象
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
// 4. 調用 send 方法,發送消息
for (int i = 0; i < 10; i++) {
// 異步發送 默認
// kafkaProducer.send(new ProducerRecord<>("first","kafka" + i));
// 同步發送
kafkaProducer.send(new ProducerRecord<>("first","kafka" + i)).get();
}
// 5. 關閉資源
kafkaProducer.close();
}
}