前言
- spring cloud提供的stream模块,本人不太推崇。 首先,虽然其目的是屏蔽底层不同mq实现细节,但引入了新的抽象,增大了开发者的理解门槛和难度,以及问题排查难度。
其次,当未来需要替换消息中间件时,也无法达到低成本(少改或不改代码)切换的目的。对于线上运行系统,替换消息中间件难度和工作量都极大,如消息迁移、发布期间两套mq并行和兼容、producer和consumer两端的兼容、大量微服务应用配合改造等等,远远不止是业务开发端的改造。何况业务开发端也有工作量,即便不修改代码,也要修改依赖、修改配置项、测试验证发布上线等。
因此,基于实用角度考虑,对于中小型团队,个人还是建议直接使用rocketmq-spring-boot-starter。
- 对于初学者来说,github.com/apache/rock… 下的rocketmq-spring-boot-samples,是最好的代码示例。这也是笔者的选择。
生产者
主要是通过RocketMQTemplate提供api给开发者调用。 绝大部分业务场景下,默认使用一个name server,对应一个RocketMQTemplate实例即可。但是官方还是支持多name server的,参见org.apache.rocketmq.samples.springboot.ExtRocketMQTemplate。 RocketMQTemplate提供的功能汇总如下:
syncSend/syncSendOrderly系列重载函数
同步发送mq,即发送成功才返回。
| 参数 | 功能描述 |
|---|---|
| 消息参数 | 支持传org.springframework.messaging.Message或其他任何类型的payload |
| timeout | 等待超时的时间(单位:毫秒) |
| Collection messages | 批量发送消息 |
| delayLevel | 支持发送延时消息 |
| hashKey | 支持顺序消息,保证相同hashKey的消息发送到同一个队列中。参看www.iocoder.cn/RocketMQ/me… |
| / | 支持事务性消息。具体下方备注 |
备注:早期的LocalTransactionExecuter虽然使用起来最简单,但可靠性不足,已Deprecated,将于5.0.0版本删除。官方提供了TransactionListener接口供开发者自行实现事务性消息,可靠性交由开发者保证。官方示例org.apache.rocketmq.samples.springboot.ProducerApplication.TransactionListenerImpl仅供参考,不可直接用于分布式生产环境,改造中的几个参考点:
- transaction id的生成,可以使用id生成器中间件或数据库自增;
- transaction id和transaction status映射关系的保存,可以选择各种持久化方案,如db、redis等;
- 参数Object arg可以是DML代码片段(如Runnable),在executeLocalTransaction中执行。成功,则保存上述映射关系,返回COMMIT;失败,则直接返回ROLLBACK;
- 对于可靠性要求高的场景,回查方法checkLocalTransaction一定要规范实现。
sendOneWay系列重载函数
如函数注释所言,调用性能很高(不等待ack到达即return),但只能用于可靠性要求不高的场景,如日志搜集。
/**
* Similar to <a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol">UDP</a>, this method won't wait for
* acknowledgement from broker before return. Obviously, it has maximums throughput yet potentials of message loss.
* <p>
* One-way transmission is used for cases requiring moderate reliability, such as log collection.
*
* @param destination formats: `topicName:tags`
* @param message {@link org.springframework.messaging.Message}
*/
public void sendOneWay(String destination, Message<?> message) {
}
asyncSend/asyncSendOrderly系列重载函数
支持异步发送,监听回调SendCallback。
sendAndReceive系列重载函数
同步发送并等待接收consumer的返回消息。如DefaultMQProducer的函数注释所言,
/**
* Send request message in synchronous mode. This method returns only when the consumer consume the request message and reply a message. </p>
*
* <strong>Warn:</strong> this method has internal retry-mechanism, that is, internal implementation will retry
* {@link #retryTimesWhenSendFailed} times before claiming failure. As a result, multiple messages may potentially
* delivered to broker(s). It's up to the application developers to resolve potential duplication issue.
*
@return reply message
*/
@Override
public Message request(final Message msg, final long timeout) throws RequestTimeoutException, MQClientException,
RemotingException, MQBrokerException, InterruptedException {
}
返回类型支持泛型:
ProductWithPayload<String> replyGenericObject = rocketMQTemplate.sendAndReceive(
genericRequestTopic,
"request generic",
new TypeReference<ProductWithPayload<String>>() {}.getType(),
30000,
2
);
异步发送,监听回调RocketMQLocalRequestCallback。
/**
* Send request message in asynchronous mode. </p> This method returns immediately. On receiving reply message,
* <code>rocketMQLocalRequestCallback</code> will be executed. </p>
*
* @param destination formats: `topicName:tags`
* @param message {@link org.springframework.messaging.Message} the message to be sent.
* @param rocketMQLocalRequestCallback callback that will invoked when reply message received.
* @param hashKey needed when sending message orderly
* @param timeout send timeout in millis
* @param delayLevel message delay level(0 means no delay)
* @return
*/
public void sendAndReceive(String destination, Message<?> message,
RocketMQLocalRequestCallback rocketMQLocalRequestCallback, String hashKey, long timeout, int delayLevel) {
消费者
consumer接口有2个:RocketMQListener和RocketMQReplyListener,接口函数onMessage的参数类型可以是MessageExt/Message/payload的类型。 注解ocketMQMessageListener,支持按tag过滤或sql过滤,支持指定name server,ConsumeMode,MessageModel等。 MessageExtConsumer L42只消费启动以来的新增消息。