RocketMQ在项目中的应用
背景及选取原因
背景:
现有的芊益医生的微信回调为我之前利用JUC定时线程池来解决的,存在代码耦合度高,线程池如果挂了的一些列可能。
所以决定采用RocketMQ进行解耦
利用独有的事务消息特性,进行回调处理,超时取消
同时为以后的业务做扩展,如加入积分业务,扣减库存,等下游服务均可用MQ进行解耦
选取原因:
rabbitMQ底层为elang语言,适合并发量吞吐量比较小的场景,不具备rocketMQ的事务消息机制。
rocketMQ为阿里巴巴开发的一款高可用高吞吐量的消息框架,但是它的开源版是不支持定制延迟级别的,云上版本支持。
当然引入MQ会存在系统架构上的复杂程度增加,
所以暂时只考虑在支付后的回调,以及未支付订单的超时取消场景进行应用
一、2主2从异步刷盘,同步复制
为防止MQ队列崩溃引起的消息丢失等原因,可以采用2主2从同步刷盘的集群部署
采用rocketmq-console-ng进行控制台查看,这样即使有MQ节点挂了,并不影响运行,同时消息会同步刷盘,确保不丢失
二、使用事务消息防止消息的丢失
这个事务消息是RocketMQ提供的一个非常有特色的功能
事务消息只保证消息发送者的本地事务与发消息这两个操作的原子性,因此,事务消息的示例只涉及到消息发送者,对于消息消费者来说,并没有什么特别的。
为了避免单个消息被检查太多次而导致半队列消息累积,我们默认将单个消息的检查次数限制为 15 次,但是用户可以通过 Broker 配置文件的 transactionCheckMax参数来修改此限制。
项目结构如图:
关键代码如下:
/**
* @description: 事务消息监听器
**/
@Slf4j
@Component
@RocketMQTransactionListener(rocketMQTemplateBeanName = "rocketMQTemplate")
public class OrderTransactionImpl implements RocketMQLocalTransactionListener {
private final int CHECK_NUMS=15;
private AtomicInteger wz03Index = new AtomicInteger(1);
private AtomicInteger wz24Index = new AtomicInteger(1);
@Value("${mqUrl.xszfUrl}")
private String xszfUrl;
@Autowired
R01UFDOCIllnessOrderRepo wz03Repo;
@Autowired
GetMsgResultService getMsgResultService;
@Autowired
R01UFRentTxOrderRepo wz24Repo;
private ConcurrentHashMap<Object, Message> localTrans = new ConcurrentHashMap<>();
@Autowired
RedisTemplate redisTemplate;
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Object transId = msg.getHeaders().get(RocketMQHeaders.PREFIX+RocketMQHeaders.TRANSACTION_ID);
String wwz311 = new String((byte[]) msg.getPayload());
localTrans.put