SpringBoot整合SpringCloudStream3.1+版本的Kafka死信队列

SpringBoot整合SpringCloudStream3.1+版本的Kafka死信队列

上一篇直通车

SpringBoot整合SpringCloudStream3.1+版本Kafka

实现死信队列步骤

  1. 添加死信队列配置文件,添加对应channel
  2. 通道绑定配置对应的channel位置添加重试配置

结果



配置文件

Kafka基本配置(application-mq.yml)

yml 复制代码
server:
  port: 7105
spring:
  application:
	name: betrice-message-queue
  config:
	import:
	- classpath:application-bindings.yml
  cloud:
	stream:
	  kafka:
		binder:
		  brokers: localhost:9092
		  configuration:
			key-serializer: org.apache.kafka.common.serialization.StringSerializer
			value-serializer: org.apache.kafka.common.serialization.StringSerializer
		  consumer-properties:
			enable.auto.commit: false
	  binders:
		betrice-kafka:
		  type: kafka
		  environment:
			spring.kafka:
		  bootstrap-servers: ${spring.cloud.stream.kafka.binder.brokers}

创建死信队列配置文件(application-dql.yml)

yml 复制代码
spring:
  cloud:
	stream:
	  kafka:
		bindings:
		  dqlTransfer-in-0:
			consumer:
			  # When set to true, it enables DLQ behavior for the consumer. By default, messages that result in errors are forwarded to a topic named error.<destination>.<group>.
			  # messages sent to the DLQ topic are enhanced with the following headers: x-original-topic, x-exception-message, and x-exception-stacktrace as byte[].
			  # By default, a failed record is sent to the same partition number in the DLQ topic as the original record.
			  enableDlq: true
			  dlqName: Evad05-message-dlq
			  keySerde: org.apache.kafka.common.serialization.Serdes$StringSerde
#              valueSerde: org.apache.kafka.common.serialization.Serdes$StringSerde
			  valueSerde: com.devilvan.pojo.Evad05MessageSerde
			  autoCommitOnError: true
			  autoCommitOffset: true

注意:这里的valueSerde使用了对象类型,需要搭配application/json使用,consumer接收到消息后会转化为json字符串

通道绑定文件添加配置(application-bindings.yml)

channel对应上方配置文件的dqlTransfer-in-0

yml 复制代码
spring:
  cloud:
	stream:
	  betrice-default-binder: betrice-kafka
	  function:
		# 声明两个channel,transfer接收生产者的消息,处理完后给sink
		definition: transfer;sink;gather;gatherEcho;dqlTransfer;evad05DlqConsumer
	  bindings:
		# 添加生产者bindiing,输出到destination对应的topic
		dqlTransfer-in-0:
		  destination: Evad10
		  binder: ${spring.cloud.stream.betrice-default-binder}
		  group: evad05DlqConsumer # 使用死信队列必须要有group
		  content-type: application/json
		  consumer:
			maxAttempts: 2 # 当消息消费失败时,尝试消费该消息的最大次数(消息消费失败后,发布者会重新投递)。默认3
			backOffInitialInterval: 1000 # 消息消费失败后重试消费消息的初始化间隔时间。默认1s,即第一次重试消费会在1s后进行
			backOffMultiplier: 2 # 相邻两次重试之间的间隔时间的倍数。默认2,即第二次是第一次间隔时间的2倍,第三次是第二次的2倍
			backOffMaxInterval: 10000 # 下一次尝试重试的最大时间间隔,默认为10000ms,即10s。
		dqlTransfer-out-0:
		  destination: Evad10
		  binder: ${spring.cloud.stream.betrice-default-binder}
		  content-type: text/plain
		# 消费死信队列中的消息
		evad05DlqConsumer-in-0:
		  destination: Evad05-message-dlq
		  binder: ${spring.cloud.stream.betrice-default-binder}
		  content-type: text/plain

Controller

发送消息并将消息引入死信队列

java 复制代码
@Slf4j
@RestController
@RequestMapping(value = "betriceMqController")
public class BetriceMqController {
	@Resource(name = "streamBridgeUtils")
	private StreamBridge streamBridge;

	@PostMapping("streamSend")
	public void streamSend(String topic, String message) {
		try {
			streamBridge.send(topic, message);
			log.info("发送消息:" + message);
		} catch (Exception e) {
			log.error("异常消息:" + e);
		}
	}

	@PostMapping("streamSendDql")
	public void streamSendDql(String topic, String message) {
		try {
			streamBridge.send(topic, message);
			log.info("发送消息:" + message);
		} catch (Exception e) {
			log.error("异常消息:" + e);
		}
	}

	@PostMapping("streamSendJsonDql")
	public void streamSendJsonDql(String topic) {
		try {
			Evad05MessageSerde message = new Evad05MessageSerde();
			message.setData("evad05 test dql");
			message.setCount(1);
			streamBridge.send(topic, message);
			log.info("发送消息:" + message);
		} catch (Exception e) {
			log.error("异常消息:" + e);
		}
	}
}

Channel

这里使用了transfer通道,消息从Evad10(topic)传来,经过transfer()方法后抛出异常,随后进入对应的死信队列

java 复制代码
@Configuration
public class BetriceMqSubChannel {
	@Bean
	public Function<String, String> dqlTransfer() {
		return message -> {
			System.out.println("transfer: " + message);
			throw new RuntimeException("死信队列测试!");
		};
	}

	@Bean
	public Consumer<String> evad05DlqConsumer() {
		return message -> {
			System.out.println("Topic: evad05 Dlq Consumer: " + message);
		};
	}
}

将自定义序列化类型转换为JSON消息

步骤

1. 通道绑定文件(application-bindings.yml)的valueSerde属性添加自定义的序列化

2. BetriceMqController中封装该自定义类型的对象,并作为消息发送

java 复制代码
@PostMapping("streamSendJsonDql")
public void streamSendJsonDql(String topic) {
	try {
		Evad05MessageSerde message = new Evad05MessageSerde();
		message.setData("evad05 test dql");
		message.setCount(1);
		streamBridge.send(topic, message);
		log.info("发送消息:" + message);
	} catch (Exception e) {
		log.error("异常消息:" + e);
	}
}

3. channel(BetriceMqSubChannel)接收到该消息并反序列化

java 复制代码
@Bean
public Consumer<String> evad05DlqConsumer() {
	return message -> {
		System.out.println("Topic: evad05 Dlq Consumer: " + JSON.parseObject(message, Evad05MessageSerde.class));
	};
}

4. 结果


参考网址

Kafka 消费端消费重试和死信队列 - Java小强技术博客 (javacui.com)
spring cloud stream kafka rabbit 实现死信队列_spring cloud stream kafka 死信队列_it噩梦的博客-CSDN博客

相关推荐
ladymorgana15 分钟前
【Spring boot】tomcat Jetty Undertow对比,以及应用场景
spring boot·tomcat·jetty
IT_102417 分钟前
Spring Boot项目开发实战销售管理系统——系统设计!
大数据·spring boot·后端
DCTANT1 小时前
【原创】国产化适配-全量迁移MySQL数据到OpenGauss数据库
java·数据库·spring boot·mysql·opengauss
Touper.1 小时前
SpringBoot -- 自动配置原理
java·spring boot·后端
喜欢敲代码的程序员3 小时前
SpringBoot+Mybatis+MySQL+Vue+ElementUI前后端分离版:项目搭建(一)
spring boot·mysql·elementui·vue·mybatis
华子w9089258594 小时前
基于 SpringBoot+Vue.js+ElementUI 的 “花开富贵“ 花园管理系统设计与实现7000字论文
vue.js·spring boot·elementui
小时候的阳光5 小时前
SpringBoot3 spring.factories 自动配置功能不生效?
spring boot·spring·失效·factories·imports
大只鹅6 小时前
Springboot3整合ehcache3缓存--XML配置和编程式配置
spring boot·缓存
执笔诉情殇〆6 小时前
springboot集成达梦数据库,取消MySQL数据库,解决问题和冲突
数据库·spring boot·mysql·达梦
hdsoft_huge7 小时前
Spring Boot 高并发框架实现方案:数字城市的奇妙之旅
java·spring boot·后端