Kafka Java API 简单使用

生产者

注意点:
  1. 可以使用消息的同步发送和异步发送, send 方法返回的是一个 future 对象, 可以使用 get 进行阻塞等待返回. 或传入 callBack 方法进行异步回调.
  2. 可以在创建 record 的时候指定分区, 如果不指定, 则使用默认的负载均衡分配分区.
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.IntegerSerializer;
import org.apache.kafka.common.serialization.StringSerializer;

import java.util.Properties;

/**
 * @author djh
 * @date 2020/2/29 16:53
 * @description 描述信息
 */
public class KafkaProductDemo {

    public static final String TOPIC = "This_is_a_topic";

    public static void main(String[] args) throws InterruptedException {

        Properties properties = new Properties();

        properties.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop3-host:9092,hadoop4-host:9092,hadoop5-host:9092");
        properties.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName());
        properties.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());


        // 创建生产者.
        KafkaProducer<Integer, String> kafkaProducer = new KafkaProducer<>(properties);
        for (int i = 1; i < 100000; i++) {
            Thread.sleep(500);
            ProducerRecord<Integer, String> record = new ProducerRecord<>(TOPIC, i, "这是第" + i + "条消息");
            kafkaProducer.send(record, (metadata, exception) -> {
                System.out.println(metadata.toString());
                exception.printStackTrace();
            });
        }

        kafkaProducer.close();
    }
}
运行结果:
This_is_a_topic-0@0
This_is_a_topic-3@0
This_is_a_topic-1@0
This_is_a_topic-3@1
This_is_a_topic-4@0
This_is_a_topic-9@0
This_is_a_topic-3@2
This_is_a_topic-6@0
This_is_a_topic-8@0
This_is_a_topic-1@1
This_is_a_topic-9@1
This_is_a_topic-7@0
This_is_a_topic-3@3
This_is_a_topic-9@2
This_is_a_topic-8@1
This_is_a_topic-9@3
This_is_a_topic-1@2

我们可以看到,每个分区都有分配到消息, 我这默认设置成了十个分区.



消费者

注意点:
  1. 属于不同进程的消费者, 只要 group_id 相同则属于同一个消费者组, 对同一个分区存在争夺消费的情况.
  2. 如果不为某一消费者指定分区, 则使用默认的负债均衡, 消费某几个分区, 如果一个消费者组只有一个消费者, 那就会消费所有分区的数据.
  3. 可以使用 assign 指定某一个消费者指定消费哪一个分区.
  4. 消费者需要不断的对 kafka 进行轮询, 如果一定时间段内, 没有接受到来之消费者的轮询, 则认为该消费者死亡.
关于消费的顺序性:
  1. 如果整个 topic 只有一个消费者在消费, 无论这一个 topic 有多少个分区, 依旧可以保证消费的顺序性, 从头到尾都是顺序的.
  2. 如果动态的在一个消费者组中添加消费者, 那么此时便在不同消费者之间不会顺序, 因为一个消费者只能消费某一个对应的分区嘛, 但是在一个消费者内部, 对同一个分区的消费还是保有顺序性的.
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.IntegerDeserializer;
import org.apache.kafka.common.serialization.StringDeserializer;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

/**
 * @author djh
 * @date 2020/2/29 17:13
 * @description 描述信息
 */
public class KafkaConsumerDemo {
    public static final String CONSUMER_GROUP = "consumer_two";

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop3-host:9092,hadoop4-host:9092,hadoop5-host:9092");
        properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class.getName());
        properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

        // 指定消费者组,组名称相同的不同消费者进程仍然属于同一个消费者组.
        properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, CONSUMER_GROUP);

        KafkaConsumer<Integer, String> kafkaConsumer = new KafkaConsumer<>(properties);
        kafkaConsumer.subscribe(Collections.singletonList(KafkaProductDemo.TOPIC));
        //kafkaConsumer.assign(Arrays.asList(new TopicPartition(KafkaProductDemo.TOPIC, 0), new TopicPartition(KafkaProductDemo.TOPIC, 2)));
        //kafkaConsumer.seek(new TopicPartition(KafkaProductDemo.TOPIC, 0), 0);

        // 一直处于消费状态.
        while (true) {
            ConsumerRecords<Integer, String> records = kafkaConsumer.poll(Duration.ofSeconds(5));
            for (ConsumerRecord<Integer, String> record : records) {
                System.out.println("消费第" + record.key() + "条消息, \t 内容为:" + record.value() + "\t 偏移量为:" + record.offset() +
                        "\t 分区为:" + record.partition());
            }
        }
    }
}
运行结果:

当有三个消费者时:

消费者 1 的日志:

消费第4102条消息, 	 内容为:这是第4102条消息	 偏移量为:429	 分区为:4
消费第4115条消息, 	 内容为:这是第4115条消息	 偏移量为:430	 分区为:4
消费第4117条消息, 	 内容为:这是第4117条消息	 偏移量为:399	 分区为:5
消费第4121条消息, 	 内容为:这是第4121条消息	 偏移量为:467	 分区为:6
消费第4122条消息, 	 内容为:这是第4122条消息	 偏移量为:431	 分区为:4
消费第4123条消息, 	 内容为:这是第4123条消息	 偏移量为:400	 分区为:5
消费第4126条消息, 	 内容为:这是第4126条消息	 偏移量为:432	 分区为:4

消费者 2 的日志:

消费第4232条消息, 	 内容为:这是第4232条消息	 偏移量为:440	 分区为:3
消费第4235条消息, 	 内容为:这是第4235条消息	 偏移量为:432	 分区为:2
消费第4236条消息, 	 内容为:这是第4236条消息	 偏移量为:390	 分区为:1
消费第4238条消息, 	 内容为:这是第4238条消息	 偏移量为:409	 分区为:0
消费第4240条消息, 	 内容为:这是第4240条消息	 偏移量为:391	 分区为:1
消费第4242条消息, 	 内容为:这是第4242条消息	 偏移量为:441	 分区为:3
消费第4244条消息, 	 内容为:这是第4244条消息	 偏移量为:433	 分区为:2
消费第4245条消息, 	 内容为:这是第4245条消息	 偏移量为:410	 分区为:0

消费者 3 的日志:

消费第4043条消息, 	 内容为:这是第4043条消息	 偏移量为:379	 分区为:9
消费第4046条消息, 	 内容为:这是第4046条消息	 偏移量为:380	 分区为:9
消费第4061条消息, 	 内容为:这是第4061条消息	 偏移量为:400	 分区为:8
消费第4065条消息, 	 内容为:这是第4065条消息	 偏移量为:381	 分区为:9
消费第4066条消息, 	 内容为:这是第4066条消息	 偏移量为:397	 分区为:7
消费第4067条消息, 	 内容为:这是第4067条消息	 偏移量为:398	 分区为:7
消费第4068条消息, 	 内容为:这是第4068条消息	 偏移量为:399	 分区为:7
消费第4075条消息, 	 内容为:这是第4075条消息	 偏移量为:401	 分区为:8

当只有一个消费者时的日志:
消费第4630条消息, 	 内容为:这是第4630条消息	 偏移量为:493	 分区为:4
消费第4631条消息, 	 内容为:这是第4631条消息	 偏移量为:470	 分区为:2
消费第4632条消息, 	 内容为:这是第4632条消息	 偏移量为:448	 分区为:8
消费第4633条消息, 	 内容为:这是第4633条消息	 偏移量为:480	 分区为:3
消费第4634条消息, 	 内容为:这是第4634条消息	 偏移量为:431	 分区为:9
消费第4635条消息, 	 内容为:这是第4635条消息	 偏移量为:427	 分区为:1
消费第4636条消息, 	 内容为:这是第4636条消息	 偏移量为:454	 分区为:7
消费第4637条消息, 	 内容为:这是第4637条消息	 偏移量为:461	 分区为:0
消费第4638条消息, 	 内容为:这是第4638条消息	 偏移量为:432	 分区为:9
消费第4639条消息, 	 内容为:这是第4639条消息	 偏移量为:471	 分区为:2
消费第4640条消息, 	 内容为:这是第4640条消息	 偏移量为:455	 分区为:7
消费第4641条消息, 	 内容为:这是第4641条消息	 偏移量为:428	 分区为:1
消费第4642条消息, 	 内容为:这是第4642条消息	 偏移量为:433	 分区为:9
消费第4643条消息, 	 内容为:这是第4643条消息	 偏移量为:447	 分区为:5

通过上面我们看到, 结果很明显, 要想使 kafka 的消息得到顺序消费, 要么只要有一个分区, 要么多个分区只要有一个消费者即可. 动态的添加或删除消费者, 如果没指定消费那个分区, 则会进行自动的负债均衡.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值