目录

普通消息

可靠同步发送

可靠异步发送

单向发送

三种发送方式的对比

顺序消息

事物消息

 两个概念

 事务消息发送步骤

事务消息回查步骤

消息消费要注意的细节

RocketMQ支持两种消息模式:


普通消息

RocketMQ提供三种方式来发送普通消息:可靠同步发送、可靠异步发送和单向发送。

可靠同步发送

同步发送是指消息发送放发出数据后,会在收到接收方 响应之后才发下一个数据包的通讯方式。

这种方式应用场景非常广泛,列如重要通知邮件、报名短信通知、营销短信系统等。

//同步消息
   @Test
   public void testSyncSend() {
//参数一: topic, 如果想添加tag 可以使用"topic:tag"的写法
//参数二: 消息内容
      SendResult sendResult =
              rocketMQTemplate.syncSend("test-topic-1", "这是一条同步消息");                         
      System.out.println(sendResult);
   }

可靠异步发送

异步发送是指发送放  发出数据后,不等接收方 发回响应,接着发送下一个数据包的通讯方式。发送方 通过回调接口接收服务器响应,并对响应结果进行处理。

异步发送一般用于 链路耗时较长,对RT响应时间较为敏感的业务场景,列如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。

//异步消息
   @Test
   public void testAsyncSend() throws InterruptedException { 
        public void testSyncSendMsg() {
//参数一: topic, 如果想添加tag 可以使用"topic:tag"的写法
//参数二: 消息内容
//参数三: 回调函数, 处理返回结果
          rocketMQTemplate.asyncSend(
                "test-topic-1", 
                "这是一条异步消息",
          new SendCallback() {
             @Override
             public void onSuccess(SendResult sendResult) {             
                 System.out.println(sendResult);
              }
              @Override
              public void onException(Throwable throwable) {             
                 System.out.println(throwable);
              }
        });
//让线程不要终止
       Thread.sleep(30000000);
   }

单向发送

单向发送是指发送方 只负责发送消息,不等待服务器回应 没有 回调函数触发,只发送请求不等待应答。

适合用于某些耗时非常短,但对可靠性要求并不高的场景,不如说日志收集。

//单向消息
      @Test
      public void testOneWay() {
         rocketMQTemplate.sendOneWay("test-topic-1", "这是一条单向消息");
      }

三种发送方式的对比

rocketMQTemplate 设置 消息 key rocketmq发送消息的类型_rocketmq

 

顺序消息

rocketMQTemplate 设置 消息 key rocketmq发送消息的类型_java_02

//同步顺序消息[异步顺序 单向顺序写法类似]
        public void testSyncSendOrderly() {
//第三个参数用于队列的选择
            rocketMQTemplate.syncSendOrderly(
                "test-topic-1", 
                "这是一条异步顺序消息",
                "xxxx");
        }

事物消息

 RocketMQ提供了事务消息,通过事务消息就能达到分布式事务的最终一致。

rocketMQTemplate 设置 消息 key rocketmq发送消息的类型_发送方和接收方_03

 两个概念

        半事务消息:暂不能投递的消息,发送方已经成功地将消息发送到 RocketMQ服务,但是服务端 未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的消息 为半事务消息。

         消息回查:由于网络闪断、生产者应用重启等原因,导致的某条事务消息的二次确认丢失,

 RocketMQ服务端通过扫描发现某条消息长期处于“半事务消息”时,需要主动向消息生产者询问该消息的最终状态(Commit 或者 Rollback),该询问过程 消息回查。

 事务消息发送步骤

   1.发送方 将半事务消息发送至PocketMQ服务端。

    2.RocketMQ服务端将消息持久化之后,向发送方返回Ack确认消息已经发送成功,此时消息为半事务消息。

    3.发送方开始执行本地事务逻辑

    4.发送方根据本地事务执行结果向服务端提交二次确认(Commit 或者 Rollback),服务端收到Commit 状态则将半事务消息标记为可投递,订阅方最终将收到该消息。服务端说到R0llback状态则删除半事务消息,订阅方将不会接受该消息。

事务消息回查步骤

     1.在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达服务端,经过固定时间后服务端将对该数据发起消息回查

     2.发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。

     3.发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍然按照步骤4对半事务消息  进行操作。

//事物日志
 @Entity(name = "shop_txlog")@Data
 public class TxLog {        @Id
         private String txLogId;        private String content;
        private Date date;
 }
 @Service
 public class OrderServiceImpl4 {
     @Autowired    private OrderDao orderDao;
     @Autowired
     private TxLogDao txLogDao;     @Autowired
     private RocketMQTemplate rocketMQTemplate;     public void createOrderBefore(Order order) {
         String txId =  UUID.randomUUID().toString();
        //发送半事务消息
        rocketMQTemplate.sendMessageInTransaction(
                                         "tx_producer_group",                                        "tx_topic",
                                         MessageBuilder.withPayload(order).setHeader(                                                                        "txId",
                                                                         txId).build(),                                        order
                                         );
     }      //本地事物
@Transactional
public void createOrder(String txId, Order order) {
         //本地事物代码        orderDao.save(order);
        //记录日志到数据库,回查使用
        TxLog txLog = new TxLog();
         txLog.setTxLogId(txId);        txLog.setContent("事物测试");
        txLog.setDate(new Date());
         txLogDao.save(txLog);
     }
 }
@RocketMQTransactionListener(txProducerGroup = "tx_producer_group")
public class OrderServiceImpl4Listener implements RocketMQLocalTransactionListener {
        @Autowired
          private TxLogDao txLogDao;         @Autowired
         private OrderServiceImpl4 orderServiceImpl4;         //执行本地事物
    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(
        Message msg, Object arg) {
         try {
         //本地事物
             orderServiceImpl4.createOrder((String) msg.getHeaders().get("txId"), (Order) arg);
                        return RocketMQLocalTransactionState.COMMIT;
         } catch (Exception e) {
             return RocketMQLocalTransactionState.ROLLBACK;
         }
     }     //消息回查
    @Override
     public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
         //查询日志记录
         TxLog txLog = txLogDao.findById((String) msg.getHeaders().get("txId")).get();        if (txLog == null) {
             return RocketMQLocalTransactionState.COMMIT;
         } else {
             return RocketMQLocalTransactionState.ROLLBACK;
         }
     }


}

消息消费要注意的细节

@RocketMQMessageListener(
         consumerGroup = "shop",//消费者分组        topic = "order-topic",//要消费的主题
         consumeMode = ConsumeMode.CONCURRENTLY, //消费模式:无序和有序                messageModel = MessageModel.CLUSTERING, //消息模式:广播和集群,默认是集群
 )
 public class SmsService implements RocketMQListener<Order> {
}

RocketMQ支持两种消息模式:

  • 广播消费: 每个消费者实例都会收到消息,也就是一条消息可以被每个消费者实例处理;
  • 集群消费: 一条消息只能被一个消费者实例消费