Apache RocketMQ官网翻译(四)

事务例子

什么是事务消息?

可以认为是两阶段提交的消息实现,以确保在分布式系统中的最终一致性。事务消息确保了以原子的方式执行本地事务的执行和消息的发送。

使用限制

(1)事务消息不支持延迟和批量操作。
(2)为了避免单个消息被检查太多次而导致过半的队列消息累积,我们默认限制了检查单个消息15次,但是用户可以通过在broker的配置中修改“transactionCheckMax"参数来改变这个限制。如果一个消息被检查超过了”transactionCheckMax"次,默认broker将会丢弃该消息并同时打印失败日志。用户可以通过重写AbstractTransactionCheckListener类来更改这种操作。
(3)一个事务性的消息会在一个时间后被检查,这个时长是通过在broker的配置文件中transactionTimeout参数设置的。当然用户也可以在发送消息时候设置用户的属性(property)“CHCEK_IMMUNITY_TIME_IN_SECONDS"更改这个限制,这个限制会更优先于“transactionTimeout”参数。
(4)一个事务消息可能会被检查和消费多次。
(5)重新提交消息到目标topic可能会失败。当前这个依靠日志记录。rocketMQ自身的高可用机制确保了消息的高可用性。如果你还是想确保事务消息不会丢失和正确性,推荐使用同步双写的机制。
(6)事务消息的producer ID不能够被其他类型的消息的producer ID共享。与其他类型的消息不同,事务性消息是允许后向查询的。MQ服务是通过producer ID查询连接的客户端。

应用

1、事务状态

事务性消息有三种状态:
(1)TransactionStatus.CommitTransaction:提交事务,意味着允许消费者消费这个消息
(2)TransactionStatus.RollbackTransaction:回滚事务,意味着消息将会被删除且不允许被消费
(3)TransactionStatus.Unknown:中间态,意味着消息需要重新检查来决定状态

2、发送事务消息
(1)创建事务性生产者

使用TransactionMQProducer类创建生产者客户端,并定义一个唯一的生产者组别(producerGroup),设置一个自定义的线程池处理检查型请求。执行完本地事务后,需要将执行结果回复MQ,回复状态在上文有所描述。

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;

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");
        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("TopicTest1234", 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();
    }
}
(2)实现TransactionListener接口

当消息发送成功一半时,"executeLocalTransaction"方法将被执行本地事务,并返回上文提到的三种事务状态中的一种。”checkLocalTransaction"方法检查本地事务状态并响应给MQ检查请求,也是返回上述的三种事务状态中的一种。

   import ...
   
   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) {
           int value = transactionIndex.getAndIncrement();
           int status = value % 3;
           localTrans.put(msg.getTransactionId(), status);
           return LocalTransactionState.UNKNOW;
       }
   
       @Override
       public LocalTransactionState checkLocalTransaction(MessageExt msg) {
           Integer status = localTrans.get(msg.getTransactionId());
           if (null != status) {
               switch (status) {
                   case 0:
                       return LocalTransactionState.UNKNOW;
                   case 1:
                       return LocalTransactionState.COMMIT_MESSAGE;
                   case 2:
                       return LocalTransactionState.ROLLBACK_MESSAGE;
               }
           }
           return LocalTransactionState.COMMIT_MESSAGE;
       }
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值