文章目录
RocketMQ提供了灵活的发送模式以适应不同业务场景的需求,主要包括同步发送、异步发送和单向发送三种方式。下面我将详细介绍各种模式的实现方法、适用场景及最佳实践。
一、同步发送模式
1.1 核心特点
- 阻塞等待:发送线程会阻塞直到收到Broker响应
- 强一致性:明确知道消息是否发送成功
- 可靠性高:自动重试机制(默认重试2次)
- 性能中等:TPS约5000-10000(取决于网络和配置)
1.2 代码实现
// 创建生产者实例
DefaultMQProducer producer = new DefaultMQProducer("sync_producer_group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
try {
// 构建消息
Message msg = new Message("OrderTopic",
"PaySuccess",
"order_12345".getBytes());
// 同步发送(关键方法)
SendResult sendResult = producer.send(msg);
System.out.printf("同步发送成功! MsgId:%s, Queue:%s%n",
sendResult.getMsgId(),
sendResult.getMessageQueue().getQueueId());
} catch (Exception e) {
// 处理发送失败(自动重试后仍失败)
System.err.println("消息发送失败: " + e.getMessage());
// 业务补偿逻辑
compensateSendFailure(msg);
} finally {
producer.shutdown();
}
1.3 关键配置参数
// 设置发送超时时间(默认3000ms)
producer.setSendMsgTimeout(5000);
// 设置同步发送失败重试次数(默认2次)
producer.setRetryTimesWhenSendFailed(3);
// 设置Broker不可用时的规避时间(默认1000*10ms)
producer.setSendLatencyFaultEnable(true);
1.4 适用场景
- 金融交易:支付结果通知
- 订单创建:需要确保消息必达
- 重要状态变更:如库存扣减
二、异步发送模式
2.1 核心特点
- 非阻塞:发送后立即返回,通过回调处理结果
- 高性能:TPS可达20000+
- 可靠性保障:失败时有回调通知
- 资源占用:需要维护回调线程池
2.2 代码实现
DefaultMQProducer producer = new DefaultMQProducer("async_producer_group");
producer.setNamesrvAddr("127.0.0.1:9876");
// 设置异步发送失败重试次数(默认2次)
producer.setRetryTimesWhenSendAsyncFailed(2);
producer.start();
// 构建消息
Message msg = new Message("LogTopic",
"UserLogin",
getUserLoginJson().getBytes());
// 异步发送(关键方法)
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 成功处理逻辑
System.out.printf("异步发送成功! MsgId:%s%n", sendResult.getMsgId());
updateSendSuccessMetric();
}
@Override
public void onException(Throwable e) {
// 失败处理逻辑(已自动重试过)
System.err.println("异步发送失败: " + e.getMessage());
recordSendFailure(msg, e);
// 可选择人工介入或持久化后定时重试
asyncRetryQueue.add(msg);
}
});
// 注意:此处立即返回,不要在此后立即shutdown
2.3 回调线程池配置
// 自定义回调线程池(默认使用Netty的EventLoopGroup)
producer.setCallbackExecutor(Executors.newFixedThreadPool(
16,
new ThreadFactory() {
private AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("AsyncSendCallback-" + count.incrementAndGet());
return thread;
}
}
));
2.4 适用场景
- 日志收集:允许短暂延迟
- 通知类消息:如站内信
- 高吞吐场景:秒杀抢购记录
三、单向发送模式(Oneway)
3.1 核心特点
- 只管发送:不等待响应也不回调
- 最高性能:TPS可达50000+
- 可靠性最低:可能丢失消息
- 资源消耗最小:无响应处理开销
3.2 代码实现
DefaultMQProducer producer = new DefaultMQProducer("oneway_producer_group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
try {
Message msg = new Message("MonitorTopic",
"CPU_ALERT",
getHostStats().getBytes());
// 单向发送(关键方法)
producer.sendOneway(msg);
System.out.println("单向发送完成(无结果确认)");
} finally {
producer.shutdown();
}
3.3 适用场景
- 心跳检测:允许丢失部分数据
- 实时性要求低:如用户行为埋点
- 内部监控:集群节点状态上报
四、三种模式对比
特性 | 同步发送 | 异步发送 | 单向发送 |
---|---|---|---|
响应方式 | 阻塞等待响应 | 回调通知结果 | 无响应 |
吞吐量 | 中等(5k-10k TPS) | 高(20k+ TPS) | 极高(50k+ TPS) |
可靠性 | 最高 | 高 | 低 |
实现复杂度 | 简单 | 中等 | 简单 |
资源消耗 | 中等 | 较高(回调线程) | 最低 |
典型场景 | 支付交易 | 日志收集 | 心跳检测 |
五、高级特性与最佳实践
5.1 批量发送优化
// 同步批量发送
List<Message> messages = new ArrayList<>(100);
for(int i=0; i<100; i++) {
messages.add(new Message("BatchTopic",
"TagA",
("Msg"+i).getBytes()));
}
SendResult result = producer.send(messages);
// 异步批量发送
producer.send(messages, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 整批成功
}
@Override
public void onException(Throwable e) {
// 整批失败
}
});
注意事项:
- 单批次建议不超过1MB
- 同一批次消息应有相同Topic
- 不支持延迟消息/事务消息的批量发送
5.2 发送超时管理
// 全局超时设置(作用于所有发送类型)
producer.setSendMsgTimeout(5000);
// 单次发送特殊超时(仅同步发送有效)
long begin = System.currentTimeMillis();
try {
SendResult result = producer.send(msg, 10000); // 单独设置10秒超时
} catch (RemotingTooMuchRequestException e) {
long cost = System.currentTimeMillis() - begin;
System.out.println("实际等待时间: " + cost + "ms");
}
5.3 故障规避机制
// 开启Broker故障延迟规避(默认false)
producer.setSendLatencyFaultEnable(true);
// 自定义规避策略(高级用法)
producer.setLatencyFaultTolerance(new LatencyFaultTolerance() {
@Override
public void updateFaultItem(String brokerName, long currentLatency) {
// 根据延迟动态调整规避时间
}
});
六、生产环境建议
6.1 性能调优参数
# 发送线程池数量(默认CPU核数)
rocketmq.producer.sendMessageThreadPoolNums=16
# 异步发送队列深度(默认5000)
rocketmq.producer.asyncSendThreadPoolQueueCapacity=10000
# 压缩消息阈值(默认4KB)
rocketmq.producer.compressMsgBodyOverHowmuch=4096
6.2 错误处理策略
同步发送失败处理:
try {
sendResult = producer.send(msg);
} catch (MQClientException e) {
// 客户端异常(参数错误等)
log.error("客户端错误:", e);
} catch (RemotingException e) {
// 网络异常
if(retryCount.getAndIncrement() < MAX_RETRY) {
// 自定义重试
return doSendWithRetry(msg);
}
} catch (MQBrokerException e) {
// Broker异常(根据响应码处理)
switch(e.getResponseCode()) {
case ResponseCode.TOPIC_NOT_EXIST:
createTopic(msg.getTopic());
break;
case ResponseCode.SERVICE_NOT_AVAILABLE:
Thread.sleep(1000);
break;
}
}
异步发送失败处理:
// 在SendCallback.onException中实现
public void onException(Throwable e) {
if(e instanceof MQBrokerException) {
// Broker返回的错误
} else if(e instanceof RemotingException) {
// 网络问题
}
// 持久化到本地磁盘
persistToDisk(msg);
// 启动定时任务重试
retryScheduler.schedule(() -> {
producer.send(msg, this); // 使用相同的callback
}, 1, TimeUnit.MINUTES);
}
七、监控与运维
7.1 关键监控指标
指标名称 | 预警阈值 | 监控方式 |
---|---|---|
发送平均耗时 | >500ms | Prometheus+Grafana |
异步发送积压量 | >5000 | RocketMQ控制台 |
发送失败率 | >1% | 日志分析 |
Broker响应时间 | >300ms | 分布式追踪系统 |
7.2 运维命令
# 查看生产者状态
mqadmin producerConnection -n 127.0.0.1:9876 -g producer_group
# 查看发送TPS
mqadmin producerStatus -n 127.0.0.1:9876 -g producer_group
# 重置生产者客户端(强制清理)
mqadmin cleanExpiredProducer -n 127.0.0.1:9876
八、版本兼容性
RocketMQ版本 | 同步发送变化 | 异步发送增强 |
---|---|---|
4.0.x | 基础支持 | 基础回调支持 |
4.3.x | 增加超时精确控制 | 支持批量异步发送 |
4.6.x | 优化重试机制 | 回调线程池可配置化 |
4.9.x | 增强Broker故障检测 | 支持回调结果上下文传递 |
通过合理选择发送模式并配合适当的错误处理和性能调优,可以充分发挥RocketMQ在高并发分布式场景下的优势。建议根据业务场景的可靠性要求、实时性需求和系统资源情况综合评估后选择最合适的发送方式。