kafka發送消息至指定分區

前言

在實際使用中,我們可能需要對某個topic下不同的消息進行分類管理,比如確保消費的順序性,在這種場景下,我們可以首先確保生產者發送消息到指定的分區即可

本文的測試基於docker搭建的一個雙節點的簡單集羣,有興趣搭建的同學可參考我的另一篇博客

1、創建一個名爲second的topic

在該topic下,有3個分區,兩個副本

$KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper zoo1:2181 --replication-factor 2 --partitions 3 --topic second

2、從某個docker節點下進入控制檯,輸入如下命令等待消費

$KAFKA_HOME/bin/kafka-console-consumer.sh --bootstrap-server kafka1:9092 --from-beginning --topic second

在使用Java客戶端連接kafka進行消息發送時,提供了2種發送消息到指定的分區的方式,下面分別進行演示

3、pom文件添加如下依賴

		<dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>0.11.0.0</version>
        </dependency>

方式1:直接在發送消息時指定

下面貼出生產者的主要代碼

/**
 * 生產者將消息發到指定的主題分區下
 */
public class SpecialPartionProducer {

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("bootstrap.servers", "106.15.37.147:9092")
        properties.put("acks", "all");
        properties.put("retries", "3");
        properties.put("batch.size", "16384");
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        //key和value的序列化
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        //構造生產者對象
        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);
        //發送消息
        for (int i = 0; i < 10; i++) {
            producer.send(new ProducerRecord<String, String>("second", 0,"congge " ,"val = "+ i)
                    , new ProducerCallBackV2());
        }
        //關閉連接資源
        producer.close();

    }
}

/**
 * 生產者回調消息
 */
class ProducerCallBackV2 implements Callback {

    public void onCompletion(RecordMetadata metadata, Exception e) {
        if(e == null){
            System.out.println("offset : " + metadata.offset());
            System.out.println("partition : " + metadata.partition());
            System.out.println("topic : " +metadata.topic());
            System.out.println("===============================");
        }
    }
}

在這種方式下,我們只需要在producer.send()方法中指定具體的分區值即可,運行這段代碼,從控制檯可以看到,消息發送到分區爲0的裏面
在這裏插入圖片描述

方式2:實現Partitioner接口

這種方式看起來更加靈活,重寫裏面的partition方法,可以更好的結合具體的業務場景對分區進行指定,因此首先需提供一個自定義的分區類,假如我這裏直接返回分區1,當然,也可以通過一定的取模算法,或者根據業務逐漸寫個路由算法進行指定也可

public class MyPartion implements Partitioner {

    public int partition(String s, Object o, byte[] bytes, Object o1, byte[] bytes1, Cluster cluster) {
        return 1;
    }

    public void close() {

    }

    public void configure(Map<String, ?> map) {

    }
}

生產者代碼,這一次,通過上面的這種方式做,則需要在參數裏面進行分區的指定,即只需要將實現上面Partitioner接口的完整的類加上即可

public class PartionProducer {

    public static void main(String[] args) {

        Properties properties = new Properties();
        properties.put("bootstrap.servers", "106.15.37.147:9092");
        properties.put("acks", "all");
        properties.put("retries", "3");
        properties.put("batch.size", "16384");
        properties.put("linger.ms", 1);
        properties.put("buffer.memory", 33554432);
        //key和value的序列化
        properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        //添加自定義分區器
        properties.put("partitioner.class", "com.congge.partion.MyPartion");

        //構造生產者對象
        KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);
        //發送消息
        for (int i = 0; i < 10; i++) {
            producer.send(new ProducerRecord<String, String>("second", "congge-self ", "val = " + i)
                    , new ProducerCallBackV3());
        }
        //關閉連接資源
        producer.close();

    }
}

/**
 * 生產者回調消息
 */
class ProducerCallBackV3 implements Callback {

    public void onCompletion(RecordMetadata metadata, Exception e) {
        if (e == null) {
            System.out.println("offset : " + metadata.offset());
            System.out.println("partition : " + metadata.partition());
            System.out.println("topic : " + metadata.topic());
            System.out.println("===============================");
        }
    }

}

運行上面的代碼,觀察控制檯輸出,同樣也能達到預期的效果
在這裏插入圖片描述

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