大厂五剑客之RocketMQ---9--分布式事务---二周目

19 篇文章 0 订阅

每个消息有唯一的messageID和自己的id。

分布式事务。

不同的微服务和不同的数据库。

------------------------------------------------01------------------------------

默认是储存的是3天的消息。

走一遍流程:

第一步:produce投递消息到broker

第二步:broker回传消息投递成功的信息

第三步:执行本地的事务

第四步:再给broker发信息如果事务成功,则给broker发送消息为可被消费走第五步,如果是Rollback删除半消息,三天之后删除,如果是网络不好的话就回查走第六步。

第五步:给consumer发消息订阅

第六步:服务端主动发个请求确认事务状态

第七步:本地事务检查,commit还是rollback

第八步:rollback的话不投递消息储存三天后删除

consumer重试消息失败的话就把失败的消息存到数据库里面去。

------------------------------------------------02-----------------------------

讲义所讲:

------------------------------------------------------------------------------------------

实战。

第一步:

consumer是不变的。

第二步:

//  本地的事物的
class TransactionListenerImpl implements  TransactionListener{

    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        return null;
    }

    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        return null;
    }
}

第三步:new事务的监听器。

//事务监听器
    private TransactionListener transactionListener = new TransactionListenerImpl();

第四步: 


Decapitator 2020/2/13 23:13:49
    public TransactionProducer(){

        producer = new TransactionMQProducer(producerGroup);

        producer.setNamesrvAddr(JmsConfig.NAME_SERVER);

       
        // 生产者设置事务监听器
        producer.setTransactionListener(transactionListener);

        producer.setExecutorService(executorService);

        //指定NameServer地址,多个地址以 ; 隔开

        start();
    }

第五步:设置线程池,直接拷贝官方文档的代码 我们要开线程去回查的。

  //一般自定义线程池的时候,需要给线程加个名称

    private 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;
        }
    });

第六步:写controller

@Autowired
    private TransactionProducer transactionMQProducer;


    @RequestMapping("/api/v1/pay_cb")
    public Object callback( String tag, String otherParam ) throws Exception {

            Message message = new Message(JmsConfig.TOPIC, tag, tag+"_key",tag.getBytes());



            SendResult sendResult =  transactionMQProducer.getProducer().
                    sendMessageInTransaction(message, otherParam);


            System.out.printf("发送结果=%s, sendResult=%s \n", sendResult.getSendStatus(), sendResult.toString());

            return new HashMap<>();
    }

----------------------------------------03----------------------------

第一步:我们启动下我们的代码

第一次为半消息,不能被消费。

第二步:

第一个:半消息投递成功,方法会被调用执行本地的事务

第二个:没有半消息相应的时候,回查事务的状态

我们注意到一点:otherParam会被传递到作为红框的参数。

第三步:我们写监听器本地事务的。

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

        System.out.println("====executeLocalTransaction=======");
        String body = new String(msg.getBody());
        String key = msg.getKeys();
        String transactionId = msg.getTransactionId();
        System.out.println("transactionId="+transactionId+", key="+key+", body="+body);
        // 执行本地事务begin TODO

        // 执行本地事务end TODO

        int status = Integer.parseInt(arg.toString());

        //二次确认消息,然后消费者可以消费
        if(status == 1){
            return LocalTransactionState.COMMIT_MESSAGE;
        }

        //回滚消息,broker端会删除半消息
        if(status == 2){
            return LocalTransactionState.ROLLBACK_MESSAGE;
        }

        //broker端会进行回查消息,再或者什么都不响应
        if(status == 3){
            return LocalTransactionState.UNKNOW;
        }

        return null;
    }

第四步:回查:根据上一步的返回值进行回查。提交消息。

@Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {

        System.out.println("====checkLocalTransaction=======");
        String body = new String(msg.getBody());
        String key = msg.getKeys();
        String transactionId = msg.getTransactionId();
        System.out.println("transactionId="+transactionId+", key="+key+", body="+body);

        //要么commit 要么rollback

        //可以根据key去检查本地事务消息是否完成


        return LocalTransactionState.COMMIT_MESSAGE;
    }

 

第五步:我们实际的演练下

我们演示消息成功的情况。参数是1。

我们输入网址测试:

http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=1

消费了。

第六步:我们如何回查消息

http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=3

过一会就回去会查了:

第七步:我们模拟rollback的message。

http://localhost:8081/api/v1/pay_cb?tag=order_pay&otherParams=2

这次我们不会进入到回查的函数的,是因为再broker删除了。

总结:

1.可被消费2.broker端把消息进行删除3.回查

-------------------------

回查:知识点:

我们会通过这个key作为校验的。

----

注意点:

这个必须是唯一的,不能和普通的一样,会冲突。

---------------

回顾:

第一步:produce首先会发送半消息到broker端。

相当于第一步,第二步。

第二步:执行本地事务操作对应的代码

第三步:

提交给broker信息。

是不是可以消费,可以消费consumer进行打印。

第四步:

返回的是rollback则直接删除broker里面的消息不进行回查的。

第五步:

或者什么都不相应。

回查消息。

一般拿到key就是唯一的标识,比如订单号。

---------------------04------------------

源码剖析:

第一步,源码的查看。

这部分源码的查看。

在这一步把消息变成一个半消息。

sendmsg:就是发送简单的消息。

再往下:

设置默认是为UNKNOW。

再往下:

这里点进去就是检查本地的事务。

再往下:

点进去:

传进来两个值。

第一步是事务的id,第二步是告诉broker找对应的消息。

判断。发送给broker。

注意L:

事务的id和msgId是一致的。

--------------------------------------------------------------------------05--------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值