目录
一、简介
RocketMQ 的消息同步发送我们也演示过了,本文主要是简单的讲解异步发送。
1.1、概念
异步发送指的是生产者在发送消息后,直接返回,不需要等待Broker的响应。消息发送的结果通过指定的回调接口进行异步通知。异步发送的优缺点如下:
优点:
- 无需等待Broker响应,减少了发送延迟
- 吞吐量相对较高,适合于发送端吞吐量高的场景
缺点:
- 发送可靠性相对同步发送模式略低,无法立即感知发送结果
- 需要通过回调接口获取发送结果,增加了一些代码复杂性
1.2、场景
异步发送对消息可靠性传输要求不是特别高的场景,允许存在少量消息丢失情况,发送端吞吐量很高,需要尽量减少发送延迟的场景,如日志收集等
二、Maven依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>rocketmq</artifactId>
<groupId>com.alian</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>02-send-async-message</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alian</groupId>
<artifactId>common-rocketmq-dto</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
父工程已经在我上一篇文章里,通用公共包也在我上一篇文章里有说明,包括消费者。具体参考:RocketMQ笔记(一)SpringBoot整合RocketMQ发送同步消息
三、application配置
application.properties
server.port=8002
# rocketmq地址
rocketmq.name-server=192.168.0.234:9876
# 默认的生产者组
rocketmq.producer.group=async_group
# 发送同步消息超时时间
rocketmq.producer.send-message-timeout=3000
# 用于设置在消息发送失败后,生产者是否尝试切换到下一个服务器。设置为 true 表示启用,在发送失败时尝试切换到下一个服务器
rocketmq.producer.retry-next-server=true
# 用于指定消息发送失败时的重试次数
rocketmq.producer.retry-times-when-send-failed=3
# 设置消息压缩的阈值,为0表示禁用消息体的压缩
rocketmq.producer.compress-message-body-threshold=0
四、生产者
上一篇文章中,我们演示了不同类型的消息发送,实际中还是以json形式发送的居多,所以本文异步发送就主要说异步发送json消息。
4.1、普通消息
在 RocketMQ 中,RocketMQTemplate的asyncSend方法。它允许你发送消息而不必等待发送结果,而是在发送完毕后执行一个回调函数以处理发送结果。这个回调函数是通过 SendCallback 接口来定义的,通常包含两个方法:
- onSuccess(SendResult sendResult):当消息发送成功时调用这个方法,sendResult 参数包含了发送消息的结果信息,如消息 ID 等。
- onException(Throwable throwable):当消息发送失败时调用这个方法,throwable 参数包含了发送失败的异常信息。
SendJsonMessageTest1.java
@Slf4j
@SpringBootTest
public class SendJsonMessageTest1 {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Test
public void asyncSendJsonMessage() {
String topic = "json_message_topic";
JSONObject json = new JSONObject();
json.put("name", "Alian");
json.put("age", "28");
json.put("hobby", "java");
rocketMQTemplate.asyncSend(topic, json, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 异步发送成功的回调逻辑
log.info("异步消息发送json信息成功: " + sendResult);
}
@Override
public void onException(Throwable e) {
// 异步发送失败的回调逻辑
log.info("异步消息发送json信息失败: " + e.getMessage());
}
});
}
@AfterEach
public void waiting() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.2、构建发送
SendJsonMessageTest2.java
@Slf4j
@SpringBootTest
public class SendJsonMessageTest2 {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Test
public void asyncSendJsonMessageWithBuilder() {
String topic = "json_message_topic";
JSONObject json = new JSONObject();
json.put("name", "Alian");
json.put("age", "28");
json.put("hobby", "java");
Message<JSONObject> msg = MessageBuilder.withPayload(json)
// 设置消息类型
.setHeader(MessageHeaders.CONTENT_TYPE, "application/json")
.build();
rocketMQTemplate.asyncSend(topic, msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 异步发送成功的回调逻辑
log.info("异步消息发送json信息成功: " + sendResult);
}
@Override
public void onException(Throwable e) {
// 异步发送失败的回调逻辑
log.info("异步消息发送json信息失败: " + e.getMessage());
}
});
}
@AfterEach
public void waiting() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.3、自定义回调
看到前面写代码结构比较繁琐,我们可以简化下回调方法,只需要实现接口SendCallback
package org.apache.rocketmq.client.producer;
public interface SendCallback {
void onSuccess(SendResult var1);
void onException(Throwable var1);
}
然后实现成功和失败的方法即可,具体如下:
JsonSendCallback.java
package com.alian.async;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
@Slf4j
public class JsonSendCallback implements SendCallback {
@Override
public void onSuccess(SendResult sendResult) {
// 异步发送成功的回调逻辑
log.info("异步消息发送JSON消息成功: " + sendResult);
}
@Override
public void onException(Throwable e) {
// 异步发送失败的回调逻辑
log.info("异步消息发送JSON消息失败: " + e.getMessage());
}
}
此时我们调用的方法就可以改造如下:
SendJsonMessageTest3.java
@Slf4j
@SpringBootTest
public class SendJsonMessageTest3 {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Test
public void asyncSendJsonMessageWithBuilderMyCallback() {
String topic = "json_message_topic";
JSONObject json = new JSONObject();
json.put("name", "Alian");
json.put("age", "28");
json.put("hobby", "java");
Message<JSONObject> msg = MessageBuilder.withPayload(json)
// 设置消息类型
.setHeader(MessageHeaders.CONTENT_TYPE, "application/json")
.build();
// 3秒发送超时,延迟级别为3(也就是要10秒后才能被消费者消费)
rocketMQTemplate.asyncSend(topic, msg, new JsonSendCallback());
}
@AfterEach
public void waiting() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.4、异步延迟发送
SendJsonMessageTest4
@Slf4j
@SpringBootTest
public class SendJsonMessageTest4 {
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Test
public void asyncSendJsonMessageWithBuilderMyCallback() {
String topic = "json_message_topic";
JSONObject json = new JSONObject();
json.put("name", "Alian");
json.put("age", "28");
json.put("hobby", "java");
Message<JSONObject> msg = MessageBuilder.withPayload(json)
// 设置消息类型
.setHeader(MessageHeaders.CONTENT_TYPE, "application/json")
.build();
// 3秒发送超时,延迟级别为3(也就是要10秒后才能被消费者消费)
rocketMQTemplate.asyncSend(topic, msg, new JsonSendCallback(),3000,3);
}
@AfterEach
public void waiting() {
try {
Thread.sleep(20000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3秒发送超时,延迟级别为3(也就是要10秒后才能被消费者消费),看到这里了相信大家都看到一段代码了
@AfterEach
public void waiting() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这个是测试生命周期的注解,我这里休眠了3秒,因为是单元测试,异步发送时,调用完发送程序就结束了,就没法收到异步回调了,所有这里采用了休眠的方式,具体休眠时间大家可以自行调整。
关于消费者不用做任何改变和我上文中一样。
五、运行结果
5.1、普通消息
json消费者接收到的消息: {"name":"Alian","age":"28","hobby":"java"}
异步消息发送json信息成功: SendResult [sendStatus=SEND_OK, msgId=7F000001373818B4AAC235FD45C70000, offsetMsgId=C0A800EA00002A9F00000000000003CD, messageQueue=MessageQueue [topic=json_message_topic, brokerName=broker-a, queueId=1], queueOffset=1]
5.2、构建对象再发送
json消费者接收到的消息: {"name":"Alian","age":"28","hobby":"java"}
异步消息发送json信息成功: SendResult [sendStatus=SEND_OK, msgId=7F000001402818B4AAC235FE628C0000, offsetMsgId=C0A800EA00002A9F00000000000004F7, messageQueue=MessageQueue [topic=json_message_topic, brokerName=broker-a, queueId=0], queueOffset=0]
5.3、自定义回调
json消费者接收到的消息: {"name":"Alian","age":"28","hobby":"java"}
异步消息发送JSON消息成功: SendResult [sendStatus=SEND_OK, msgId=7F00000113C818B4AAC235FEEB900000, offsetMsgId=C0A800EA00002A9F0000000000000621, messageQueue=MessageQueue [topic=json_message_topic, brokerName=broker-a, queueId=0], queueOffset=1]
5.4、异步延迟
2024-03-11 11:43:15.289 INFO 15224 --- [ublicExecutor_1] com.alian.async.JsonSendCallback : 异步消息发送JSON消息成功: SendResult [sendStatus=SEND_OK, msgId=7F0000013B7818B4AAC2360371360000, offsetMsgId=C0A800EA00002A9F000000000000074B, messageQueue=MessageQueue [topic=json_message_topic, brokerName=broker-a, queueId=1], queueOffset=0]
2024-03-11 11:43:25.297 INFO 9232 --- [NT_GROUP_JSON_4] c.alian.concurrent.JsonMessageConsumer : json消费者接收到的消息: {"name":"Alian","age":"28","hobby":"java"}
从上面时间可以看到消费者等发送完到消费中间有10秒的延迟。
一般来说,同步发送模式用于可靠性要求较高的场合,异步发送模式则更多用于对吞吐量和延迟有较高要求的场合。在实际应用中,可以根据具体的业务场景来选择合适的发送方式。如果对消息可靠性要求不是非常高,且发送端吞吐量较大,建议采用异步发送模式,以提高消息发送的性能和系统的吞吐能力。