RocketMQ学习之二-----RocketMQ的事务消息机制

RocketMQ的事务消息机制


前言

对于复杂的分布式事务,RocketMQ提供的事务消息也是目前业内最佳的降级方案。


场景

在这里插入图片描述
在下单后,删除购物车的场景
订单下单成功后,加用户的积分

所以总结起来就是:

  1. 没有资源竞争,
  2. 实时性会滞后一点

来理解一下:

订单系统下订单,等待支付,支付完成之后要推送给下游服务,进行营销,例如:给客户发红包,下物流的单子。

  1. 首先,订单系统先发个half消息,如果订单系统不发half消息,首先本地mysql下单,通知rocketMQ,假设下完单,rocketMQ挂了。那事务的一致性就消失了,下单成功了,下游服务的全都没有了。half消息更大的作用是检查RocketMQ有没有挂。

     half消息特点是:下游服务不可见
    
  2. 假设mysql下单,数据库挂掉了,这时候已经通知了MQ,可以给一次反悔的机会,图4返回本地事务状态,rollback状态事务丢弃。保证了本地事务执行失败,下游服务也执行失败。这样就保证了事务的一致性。

  3. 会什么要来进行回查?例如下单过了5分钟没支付,给mq返回个unknow,mq就进行状态回查,检查本地事务状态

保证的是本地事务和MQ的事务一致性。执行本地事务的每一步都有反悔的机会。
只是保证了分布式事务的一半。

代码示例

代码如下(示例):

public class TransactionProducer {
    public static void main(String[] args) throws MQClientException, InterruptedException {
        TransactionListener transactionListener = new TransactionListenerImpl();
        TransactionMQProducer producer = new TransactionMQProducer("please_rename_unique_group_name");
        producer.setNamesrvAddr("39.107.103.223:9876");
        ExecutorService executorService = new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("client-transaction-msg-check-thread");
                return thread;
            }
        });

        producer.setExecutorService(executorService);
        producer.setTransactionListener(transactionListener);
        producer.start();

        String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
        for (int i = 0; i < 10; i++) {
            try {
                Message msg =
                    new Message("TopicTest", tags[i % tags.length], "KEY" + i,
                        ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
                SendResult sendResult = producer.sendMessageInTransaction(msg, null);
                System.out.printf("%s%n", sendResult);

                Thread.sleep(10);
            } catch (MQClientException | UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        for (int i = 0; i < 100000; i++) {
            Thread.sleep(1000);
        }
        producer.shutdown();
    }
}

消费者监听器:

public class TransactionListenerImpl implements TransactionListener {
    private AtomicInteger transactionIndex = new AtomicInteger(0);

    private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();

    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {

        String tags = msg.getTags();
        if(StringUtils.contains(tags,"TagA")){
            return LocalTransactionState.COMMIT_MESSAGE;
        }else if(StringUtils.contains(tags,"TagB")){
            return LocalTransactionState.ROLLBACK_MESSAGE;
        }else{
            return LocalTransactionState.UNKNOW;
        }
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        String tags = msg.getTags();
        if(StringUtils.contains(tags,"TagC")){
            return LocalTransactionState.COMMIT_MESSAGE;
        }else if(StringUtils.contains(tags,"TagD")){
            return LocalTransactionState.ROLLBACK_MESSAGE;
        }else{
            return LocalTransactionState.UNKNOW;
        }
    }
}

在这里插入图片描述
先收到了tagA吗,过一会收到了tagc
在这里插入图片描述
消息回查时间通过配置文件的transactionTimeOut=6000可以设置,默认是60秒,也可以

 msg.putUserProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS,"20000");//时间单位毫秒

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值