kafka生产者和消费者api的简单使用

一、背景

此处主要是简单记录一下,使用 kafka api 发送消息和接收消息。

二、需要实现的功能

1、生产者实现功能

1、KafkaProducer线程安全的,可以在多线程中使用。

2、消息发送的key和value的序列化

3、自定义分区的使用

4、自定义拦截器的使用

5、消息发送完成后的回调使用

2、消费者实现功能

1、消息接收的key和value的序列化

2、指定消费者组

3、自动提交 offset (生产环境可以使用手动提交offset)

4、重置消费者的偏移量,此配置生效的条件

5、自定义消息消费拦截器

6、每次从服务器获取多少数据

3、详细实现

详细实现,请参考代码中的注释。

三、代码实现

1、jar包的引入

<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>

2、生产者代码实现

1、自定义分区器

主要目的是为了能自己控制自己的消息需要发送到那个分区中。

import org.apache.kafka.clients.producer.internals.DefaultPartitioner;
import org.apache.kafka.common.Cluster; /**
* @author huan.fu 2021/1/5 - 上午9:57
*/
public class CustomPartitioner extends DefaultPartitioner { @Override
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster) {
int partition = super.partition(topic, key, keyBytes, value, valueBytes, cluster);
System.err.println("消息被分配到分区: " + partition);
return partition;
} @Override
public void onNewBatch(String topic, Cluster cluster, int prevPartition) {
System.err.println("topic: " + topic + " 产生了一个新的批次");
super.onNewBatch(topic, cluster, prevPartition);
}
}

2、自定义消息生产拦截器

主要是消息在发送到kafka服务器之前,最消息进行一个拦截。


import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; import java.util.Map; /**
* 自定义生产者消息拦截器,此类不是线程安全的,需要自己控制线程安全问题
*
* @author huan.fu 2021/1/5 - 上午10:04
*/
public class CustomProducerInterceptor implements ProducerInterceptor<String, String> { @Override
public void configure(Map<String, ?> configs) { } @Override
public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) {
System.out.println("此方法是在消息发送的业务线程中,可以在消息发送到kafka服务器时做一些处理");
return record;
} @Override
public void onAcknowledgement(RecordMetadata metadata, Exception exception) {
System.out.println("此方法是在kafka 生产者的 I/O 线程中执行,需要立即返回,否则影响消息发送的速度");
if (exception != null) {
System.out.println("消息发送到服务器时发生了异常");
return;
}
System.out.println("消息发送到了服务器 - offset:" + metadata.offset() + " partition:" + metadata.partition());
} @Override
public void close() {
System.out.println("释放资源");
}
}

3、生产者代码

import org.apache.kafka.clients.producer.*;

import java.util.Properties;

/**
* 测试kafka发送者
* 1、KafkaProducer线程安全的,可以在多线程中使用。
* 2、消息发送的key和value的序列化
* 3、自定义分区的使用
* 4、自定义拦截器的使用
* 5、消息发送完成后的回调使用
*
* @author huan.fu 2021/1/4 - 上午10:11
*/
public class KafkaProducerDemo { public static void main(String[] args) {
Properties properties = new Properties();
// kafka服务器的地址,端口,可以不用全写,写几个既可
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092,127.0.0.1:9093,127.0.0.1:9094");
// kafka 消息key的序列化方式
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
// kafka 消息value的序列化方式
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
// 0: 消息只要发送出去了,就认为是发送成功
// 1: 消息被 leader 分区保存后,就认为发送成功
// all: 消息被 leader + isr 都保存成功后,才认为发送成功
properties.put(ProducerConfig.ACKS_CONFIG, "all");
// 设置消息重试的次数
properties.put(ProducerConfig.RETRIES_CONFIG, 0);
// 消息发送失败后,重试的间隔,即等待多少毫秒后在重试
properties.put(ProducerConfig.RETRY_BACKOFF_MS_CONFIG, 300);
// kafka 的消息默认是批量发送,即等批次消息达到一定大小(单位字节)的时候发送,此参数控制批次消息的大小
properties.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
// batch.size 设置kafka消息批次达到一定的字节时才发送,那万一一直没有达到,此时就由linger.ms控制,即等待多少毫秒之后发送,等于0表示立即发送
properties.put(ProducerConfig.LINGER_MS_CONFIG, 100);
// 表示生产者可以用来缓存等待发送到服务器上消息的可用内存大小。
properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
// 控制一次请求的大小,防止出现一个非常大的请求,默认是一兆
properties.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, 1048576);
// 控制客户端等待服务端响应的最大时间,此配置的值应该要大于 replica.lag.time.max(服务端移除isr的一个超时配置) 的值。
properties.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, 30000);
// 配置控制KafkaProducer.send()和KafkaProducer.partitionsFor()会阻塞多长时间。这些方法可能因为缓冲区已满或元数据不可用而被阻塞。
properties.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, 60000);
// 配置kafka自定义的分区器,我们自己实现的分区器,需要实现 org.apache.kafka.clients.producer.Partitioner 接口
properties.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "com.huan.kafka.api.CustomPartitioner");
// 配置kafka自定义的拦截器,可以配置多个,多个以英文的逗号分割开
properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, "com.huan.kafka.api.CustomProducerInterceptor"); // KafkaProducer 是线程安全的,可以多个线程使用用一个 KafkaProducer
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
for (int i = 0; i < 10; i++) {
ProducerRecord<String, String> record = new ProducerRecord<>("topic-a", "value - (" + i + 1 + ")");
kafkaProducer.send(record, new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if (exception != null) {
System.err.println("发送数据到kafka中,发生了异常.");
exception.printStackTrace();
return;
}
System.out.println("topic: " + metadata.topic() + " offset: " + metadata.offset() + " partition: "
+ metadata.partition());
}
});
} System.out.println("消息发送完成");
kafkaProducer.close();
}
}

3、消息消费者实现

1、自定义消息消费拦截器

import org.apache.kafka.clients.consumer.ConsumerInterceptor;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.TopicPartition; import java.util.Map; /**
* @author huan.fu 2021/1/5 - 下午2:48
*/
public class CustomConsumerInterceptor implements ConsumerInterceptor<String, String> { @Override
public void configure(Map<String, ?> configs) { } @Override
public ConsumerRecords<String, String> onConsume(ConsumerRecords<String, String> records) {
System.out.println("从kafka拉取到了数据,可以在此修改记录数据");
return records;
} @Override
public void onCommit(Map<TopicPartition, OffsetAndMetadata> offsets) {
System.out.println("提交偏移量成功时(即已经提交到了broker上),调用此函数.");
} @Override
public void close() {
System.out.println("close");
}
}

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 java.time.Duration;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.TimeUnit; /**
* 测试kafka消费者
* 1、消息接收的key和value的序列化
* 2、指定消费者组
* 3、自动提交 offset (生产环境可以使用手动提交offset)
* 4、重置消费者的偏移量,此配置生效的条件
* 5、自定义消息消费拦截器
* 6、每次从服务器获取多少数据
*
* @author huan.fu 2021/1/5 - 上午10:29
*/
public class KafkaConsumerDemo {
public static void main(String[] args) throws InterruptedException {
Properties properties = new Properties();
// kafka服务器的地址,端口,可以不用全写,写几个既可
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "127.0.0.1:9092,127.0.0.1:9093,127.0.0.1:9094");
// kafka 消息key的序列化方式
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
// kafka 消息value的序列化方式
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
// 设置消费者组,多个消费者只要组一样,就认为在一个组中,那个topic中的某一个分区,只能被这个组中的某个消费组消费,消费者组和消费者组之间互不影响
properties.put(ConsumerConfig.GROUP_ID_CONFIG, "group-test-001");
// 自动提交 offset
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
// 自动提交 offset 的间隔,即隔多长时间提交offset
properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 100);
// 重置消费者的偏移量,此配置生效的条件:
// 1、当前消费者的偏移量不在kafka服务器上(比如是一个新的消费者组)
// 2、当前消费者的offset在kafka服务器上不存在(比如: 当前消费者消费的偏移量到了10,但是此时消费者宕机了很长一段时间,而服务器上数据默认保存7天,那么此时10之后的某些偏移量可能被删除了)
// earliest: 从最早的偏移量开始消费
// latest: 从最新的偏移量开始消费
// none: 如果没有在消费者组中找到先前的偏移量,则向消费者抛出异常
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
// 配置kafka自定义的拦截器,可以配置多个,多个以英文的逗号分割开
properties.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, "com.huan.kafka.api.CustomConsumerInterceptor");
// 设置两次 poll 方法之间的最大的延时,如果超过了最大的延时,则kafka认为该consumer消费能力弱,会将该分区给别的消费者消费
properties.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 300000);
// 设置一次 pool 最多获取多少条记录
properties.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
// 拉取消息时,每个分区返回的最大的消息的字节数
properties.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG,1048576); KafkaConsumer<String, String> consumer = new KafkaConsumer<>(properties);
// 指定consumer消费的主题
consumer.subscribe(Collections.singletonList("topic-a"));
while (true) {
ConsumerRecords<String, String> consumerRecords = consumer.poll(Duration.ofMillis(500));
for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
System.out.println("接收到了一个数据. partition:" + consumerRecord.partition() + " offset:"
+ consumerRecord.offset() + " 消息的值:" + consumerRecord.value());
TimeUnit.SECONDS.sleep(3);
}
}
}
}

四、完整代码

https://gitee.com/huan1993/rabbitmq/tree/master/kafka-api

kafka生产者和消费者api的简单使用的更多相关文章

  1. kafka生产者和消费者流程

    前言 根据源码分析kafka java客户端的生产者和消费者的流程. 基于zookeeper的旧消费者 kafka消费者从消费数据到关闭经历的流程. 由于3个核心线程 基于zookeeper的连接器监 ...

  2. [Spark][kafka]kafka 生产者,消费者 互动例子

    [Spark][kafka]kafka 生产者,消费者 互动例子 # pwd/usr/local/kafka_2.11-0.10.0.1/bin 创建topic:# ./kafka-topics.sh ...

  3. kafka中生产者和消费者API

    使用idea实现相关API操作,先要再pom.xml重添加Kafka依赖: <dependency> <groupId>org.apache.kafka</groupId ...

  4. Kafka 生产者和消费者入门代码基础

    这篇博文讲解Kafka 的生产者和消费者实例. 基础版本一 生产者 ProducerFastStart.java package com.xingyun.tutorial_1; import org. ...

  5. kafka-python开发kafka生产者和消费者

    1.安装kafka-python 执行命令 pip install kafka-python kafka-python        1.4.6 2.编写python kafka 生产者消费者代码 # ...

  6. kafka生产者与消费者的生产消息与消费消息所遇到的问题

    当我们用API写kafka的时候 生产者生产消息,但是消费者接收不到消息?集群上启动消费者显示生产的消息.我们需要修改一下配置 (1)我们打开在虚拟机中修改kafka集群的配置文件 [root@spa ...

  7. kafka生产者和消费者

    在使用kafka时,有时候为验证应用程序,需要手动读取消息或者手动生成消息.这个时候可以借助kafka-console-consumer.sh和kafka-console-producer.sh 这两 ...

  8. springboot配置kafka生产者和消费者详解

    在原有pom.xml依赖下新添加一下kafka依赖ar包 <!--kafka--> <dependency> <groupId>org.springframewor ...

  9. kafka生产者、消费者java示例

    1. 生产者 import java.util.Properties; import kafka.javaapi.producer.Producer; import kafka.producer.Ke ...

随机推荐

  1. shell脚本之循环语句 for-while-until

    目录: 一.for循环语句 二.while循环语句 三.unti循环语句   一.for循环语句 读取不同的变量值,用来逐个执行同一组命令 举例 批量添加用户◆ 用户名存放在users.txt文件中, ...

  2. 【第一篇】- Git 教程之Spring Cloud直播商城 b2b2c电子商务技术总结

    Git 教程 Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制 ...

  3. POJ3625Building Roads

    Building Roads Description Farmer John had just acquired several new farms! He wants to connect the ...

  4. Java技术开发专题系列之【Guava RateLimiter】针对于限流器的入门到精通(针对于源码分析介绍)

    Guava包中限流实现分析 RateLimiter 之前的文章中已经介绍了常用的限流算法,而google在Java领域中使用Guava包中的限流工具进行服务限流. 回顾使用案例 Google开源工具包 ...

  5. 5ucms的评论列表该怎么写

    查看所有评论 <a href="{sys:plusurl}comment/?id={field:id}">查看所有评论</a> <linkhref=& ...

  6. 创建一个 Orchard Core CMS 站点

    本文通过引用项目模板的方式创建Orchard CMS站点. 创建项目有不同的方式可以为Orchard Core创建站点和模块.你可以在这里了解更多关于它们的信息.在本指南中,我们将使用我们的" ...

  7. Java 知识点 列表

    * Java SE Java开发基础 Java异常处理 Java泛型与反射 Java IO基础 JUnit单元测试 Java多线程开发 Maven基础  https://www.yiibai.com/ ...

  8. 使用亚马逊服务器报错:Signature not yet current: 20190726T070253Z is still later than 20190726T070246Z (20190726T065746Z + 15 min.)时间不同步的解决办法

    1.首先获取亚马逊的时间: $ curl http://s3.amazonaws.com -v 2.更改当前服务器时间,使之与亚马逊时间同步 $ date -s 'xxxx-xx-xx xx:xx:x ...

  9. P4717-[模板]快速莫比乌斯/沃尔什变换(FMT/FWT)

    正题 题目链接:https://www.luogu.com.cn/problem/P4717 题目大意 给出两个长度为\(2^n\)的数列\(A,B\)求 \[C_{n}=\sum_{i\ or\ j ...

  10. unittest基本原理及介绍

    unittest基本原理: unittest是python自带的测试框架,还有一个框架是:pytest,这里简单介绍下unittest模块的简单应用 unittest是python的标准测试库,相比于 ...