RocketMQ

RocketMQ特性
脑图
组成
  生产者和消费者
  broker
  nameserver
  topic

RocketMQ事务消息
  事务消息的三个接口
  生产者和监听器代码
  基于事务消息设计可靠消息

其他类型的消息
  延迟消息和批量消息
  有序消息

RocketMQ特性

  • Java开发的MQ,虽然源码中中文注释不多但是也能看。
  • 和rabbitMQ相比,RocketMQ整体结构比较简单
  • 使用topic区分消息
  • broker上topic的queue中存放的是消息的索引,topic多了并不影响性能
  • 很容易就能实现顺序消息、延迟消息、事务消息(可靠消息)

脑图

在这里插入图片描述

组成

在这里插入图片描述

生产者和消费者

broker

存放消息的,有多台是主从结构。
生产者把消息发送给broker后,broker会把消息写到文件中。broker根据消息的topic区分消息并把消息的地址放到对应的queue中。
默认情况下一个topic分四个queue,每个queue可以连接一个消费者

nameserver

nameserver保存的是broker,topic,生产者,消费者的信息。
nameserver可以有多台,不是主从结构互不通信,每一台nameserver保存的都是全量信息,可以独立对外提供服务

topic

topic是一个很重要的概念,topic既是消息类的一个属性,也是broker的一个逻辑上的组件。


RocketMQ事务消息

事务消息:事务消息发送到broker(消息服务器)后不能马上被消费者消费,需要broker调用生产者的接口并拿到COMMIT_MESSAGE的结果后才能被消费者消费。

事务消息的三个接口
  • sendMessageInTransaction:生产者发送半事务消息
  • executeLocalTransactionTransactionListener接口中的方法,由生产者实现。消息已经成功发送到了服务器,消息服务器会回调用这个接口。生产者需要返回COMMIT_MESSAGE、 ROLLBACK_MESSAGE、 UNKNOW、或不返回(生产者异常,网络异常等)
  • checkLocalTransactionTransactionListener接口中的方法,由生产者实现。executeLocalTransaction方法没有给消息服务器返回COMMIT_MESSAGEROLLBACK_MESSAGE状态时(也可能是网络问题导致消息服务器没有收到),消息服务器会调用这个接口。生产者仍需要返回消息状态(同上)

消息发送到broker:半消息(消息不能被消费)
executeLocalTransaction:返回COMMIT_MESSAGE消息可以被消费,返回ROLLBACK_MESSAGE消息被删除,返回UNKNOW不确定需要调用checkLocalTransaction去确认
checkLocalTransaction:直到返回COMMIT_MESSSAGEROLLBACK_MESSAGE,时间太长没有拿到commit或rollback消息也会被删除

代码
生产者
/**
 * 使用 TransactionMQProducer类创建生产者,并指定唯一的 ProducerGroup,就可以设置自定义线程池来处理这些检查请求。
 * 执行本地事务后、需要根据执行结果对消息队列进行回复。回传的事务状态在请参考前一节。
 */
public class Producer {

    public static void main(String[] args) throws MQClientException, InterruptedException, IOException {
        TransactionListener transactionListener = new TransactionListenerImpl();
        TransactionMQProducer producer = new TransactionMQProducer(RocketConst.producer_group);
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        producer.setExecutorService(executorService);
        producer.setTransactionListener(transactionListener);
        producer.start();
        try {
            // topic, tag, body
            Message message = new Message(RocketConst.topic, RocketConst.tag,
                    ("json消息可以反序列化为一个实体类").getBytes(RemotingHelper.DEFAULT_CHARSET));
            message.setKeys("全局唯一和业务相关");
            message.setTransactionId("");  // 这里设置没有用,消息服务器会重新设置的
            SendResult sendResult = producer.sendMessageInTransaction(message, null);
            System.out.printf("%s%n", sendResult);
        } catch (MQClientException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 等待消息服务器回调 transactionListener
        System.in.read();
    }
}
transactionListener回调监听器
public class TransactionListenerImpl implements TransactionListener {
    private final AtomicInteger transactionIndex = new AtomicInteger(0);
    private final ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();

    /**
     * 消息发送到了服务器回调这个方法(此时消息并不能被消费)
     * 此方法返回: LocalTransactionState.COMMIT_MESSAGE 消息可以被消费
     * 此方法返回: LocalTransactionState.ROLLBACK_MESSAGE 消息需要被作废(本地事务失败)
     * 此方法返回: LocalTransactionState.UNKNOW 现在结果不明,待会在确认
     * (本地处理时间较长可以返回UNKNOW,一段时间后服务器会调用checkLocalTransaction方法 再次确认)
     */
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        // 获取事务id(businessId),本地业务处理决定事务是否提交
        String msgKeys = msg.getKeys();
        if("全局唯一".equals(msgKeys)) {
            throw new RuntimeException("抛异常,让服务器调用确认方法");
        }
        // (commit)确定半消息,消息状态变为TransactionStatus.CommitTransaction,可以被消费
        // 如果本地事务需要的时间较长,这里可以先返回UNKNOW
        return LocalTransactionState.UNKNOW;
    }

    /**
     * 上一个方法(executeLocalTransaction)没有返回任何信息
     * 或返回的状态不是(COMMIT_MESSAGE或ROLLBACK_MESSAGE),broker会调用这个方法确认
     */
    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        System.out.println(msg.getTransactionId());
        return LocalTransactionState.COMMIT_MESSAGE;
    }
}    
基于事务消息的可靠消息

可靠消息:本地事务落库,消息成功发送到服务器并且能够被消费者消费。

  • 1、sendMessageInTransaction发送消息
  • 2、executeLocalTransaction提交本地事务,即保存transactionId、keys、消息体。落库成功返回COMMIT_MESSAGE,长事务不能马上拿到结果则返回UNKNOW, 落库失败返回ROLLBACK_MESSAGE, 网络异常也没关系
  • 3、checkLocalTransaction如果executeLocalTransaction没有返回或返回了UNKNOW,消息服务器会调用这个方法。重新查询事务结果(根据transactionId)并返回结果(同上)

他类型的消息

延迟消息和批量消息

https://rocketmq.apache.org/docs/%E7%94%9F%E4%BA%A7%E8%80%85/07message3
https://rocketmq.apache.org/docs/%E7%94%9F%E4%BA%A7%E8%80%85/08message4

  • 延迟消息设置消息属性指定延迟等级就行了message.setDelayTimeLevel(6);;
  • 批量消息SendResult send(Collection<Message> msgs),多个message放到集合就行了(topic相同)
顺序消息

RocketMQ是一个queue连接一个消费者,如果想让消息有序消费则需要把几条消息先后发送到同一个queue中,
这样就能保证这几条消息按照发送的先后顺序进行消费了。
把几个有序的消息发送到同一个queue,指定发送到那个queue

生产者代码

int queueIndex = 1;  // 要把消息发送到那个queue
SendResult sendResult1 = producer.send(message1, new ProducerQueueSelector(), queueIndex);
SendResult sendResult2 = producer.send(message2, new ProducerQueueSelector(), queueIndex);
SendResult sendResult3 = producer.send(message3, new ProducerQueueSelector(), queueIndex);

MessageQueueSelector代码

public class ProducerQueueSelector implements MessageQueueSelector {
    /**
     * mqs: topic下所有的队列
     * msg: 消息
     * arg: 生产者传递的消息
     * 返回一个queue,msg会被发送到这个queue
     */
    @Override
    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
        // 这里的arg就是生产者传递过来的queueIndex
        return mqs.get((int) arg);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值