SpringCloud之RocketMQ2

4. 消息的种类

4.1 按照发送的特点分

4.1.1 同步消息

(1)属于可靠同步发送

是指消息发送方发出数据后,会阻塞直到MQ服务方发回响应消息。

(2)应用场景:

如重要通知邮件、报名短信通知、营销短信系统等。

(3)流程图

SpringCloud之RocketMQ2_第1张图片

(4)代码

SendResult sendResult = producer.send(msg);

4.1.2 异步消息

(1)属于可靠异步发送

  • 是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式
  • 需要用户实现异步发送回调接口(SendCallback),在执行消息的异步发送时,应用不需要等待服务器响应即可直接返回,
  • 通过回调接口接收服务器响应,并对服务器的响应结果进行处理。

(2)应用场景:

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

(3)流程图

SpringCloud之RocketMQ2_第2张图片

(4)代码

producer.sendAsync(msg, new SendCallback() {//...});

4.1.3 单向消息

(1)one-way

  • 发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。
  • 发送消息的过程耗时非常短,一般在微秒级别。

(2)应用场景:

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

(3)流程图

SpringCloud之RocketMQ2_第3张图片

(4)代码

producer.sendOneway(msg);

以上三种消息特点及区别:

SpringCloud之RocketMQ2_第4张图片

4.2 按照使用功能特点分

4.2.1 普通消息

(1)无特性的消息,区别于有特性的定时、延时、顺序和事务消息。
(2)包括上面的同步、异步、单向消息

4.2.2 顺序消息

消息队列 RocketMQ 提供的一种按照顺序进行发布和消费的消息类型,分为全局顺序消息和分区顺序消息

(1)全局顺序消息

  • 概念:

对于指定的一个 Topic,所有消息按照严格的先入先出(FIFO)的顺序进行发布和消费。

  • 流程图:
    SpringCloud之RocketMQ2_第5张图片
  • 示例:

在证券处理中,以人民币兑换美元为 Topic,在价格相同的情况下,先出价者优先处理,则可以通过全局顺序的方式按照 FIFO 的方式进行发布和消费。

(2)分区顺序消息

  • 概念:

对于指定的一个 Topic,所有消息根据 Sharding Key 进行区块分区。同一个分区内的消息按照严格的 FIFO 顺序进行发布和消费。

  • 注意:

Sharding Key是顺序消息中用来区分不同分区的关键字段,和普通消息的 Message Key是完全不同的概念。

  • 流程图:

SpringCloud之RocketMQ2_第6张图片

  • 示例:

例一:用户注册需要发送发验证码,以用户 ID 作为 sharding key, 那么同一个用户发送的消息都会按照先后顺序来发布和消费。

例二:电商的订单创建,以订单 ID 作为 sharding key,那么同一个订单相关的创建订单消息、订单支付消息、订单退款消息、订单物流消息都会按照先后顺序来发布和消费。

(4)发送顺序消息-MessageQueueSelector()

String orderId = "Order_0000001";

//msg-key: "PAY_201907151223001" 标识此条消息业务id
//msg-key: 以方便您在无法正常收到消息情况下,可通过控制台查询消息并补发。
String payId = "PAY_201907151223001";
Message msg = new Message("pay", "TAG1", "PAY_201907151223001" ,
		("支付消息,内容为:xxxxx " ).getBytes(RemotingHelper.DEFAULT_CHARSET));

 // 分区顺序消息中区分不同分区的关键字段,sharding key 于普通消息的 key 是完全不同的概念。
// 全局顺序消息,该字段可以设置为任意非空一个字符串常量即可。
String shardingKey = orderId;
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
	@Override
	public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
		//arg为后续传递的shardingKey,可以根据hash算法or其他方法来计算出id;
		//可参考hashmap的hash算法;
		int id = hash(arg);
		int index = id % mqs.size();
		return mqs.get(index);
	}
}, shardingKey);

(5)接收顺序消息-MessageListenerOrderly()

consumer.registerMessageListener(new MessageListenerOrderly() {

       @Override
       public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs,
                                                  ConsumeOrderlyContext context) {
          //处理消息...
          return ConsumeOrderlyStatus.SUCCESS;

       }
    });

4.2.3 延时、定时消息

(1)延时消息

Producer 将消息发送到消息队列 RocketMQ 服务端,但并不期望这条消息立马投递,而是延迟一定时间后才投递到 Consumer 进行消费

(2)定时消息

Producer 将消息发送到消息队列 RocketMQ 服务端,但并不期望这条消息立马投递,而是推迟到在当前时间点之后的某一个时间投递到 Consumer 进行消费

(3)代码

// 延时消息,单位毫秒(ms),在指定延迟时间(当前时间之后)进行投递,例如消息在 3 秒后投递
long delayTime = System.currentTimeMillis() + 3000;
// 设置消息需要被投递的时间
msg.setStartDeliverTime(delayTime);


// 定时消息,单位毫秒(ms),在指定时间戳(当前时间之后)进行投递,例如 2019-08-01 16:21:00 投递。如果被设置成当前时间戳之前的某个时刻,消息将立刻投递给消费者。
long timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2019-08-01 16:21:00").getTime();
msg.setStartDeliverTime(timeStamp);

4.2.4 事务消息

(1)概念

消息队列 RocketMQ 提供类似 X/Open XA 的分布事务功能,通过消息队列 RocketMQ 的事务消息能达到分布式事务的最终一致.

(2)流程图

SpringCloud之RocketMQ2_第7张图片

(3)以上流程图步骤

  1. 发送方向消息队列 RocketMQ 服务端发送消息。
  2. 服务端将消息持久化成功之后,向发送方 ACK 确认消息已经发送成功,此时消息为半消息。
  3. 发送方开始执行本地事务逻辑。
  4. 发送方根据本地事务执行结果向服务端提交二次确认(Commit 或是 Rollback),服务端收到 Commit 状态则将半消息标记为可投递,订阅方最终将收到该消息;服务端收到 Rollback 状态则删除半消息,订阅方将不会接受该消息。
  5. 在断网或者是应用重启的特殊情况下,上述步骤 4 提交的二次确认最终未到达服务端,经过固定时间后服务端将对该消息发起消息回查。
  6. 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
  7. 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤 4 对半消息进行操作。

说明:事务消息发送对应步骤 1、2、3、4,事务消息回查对应步骤 5、6、7。

(4)代码

  • producer:
TransactionListener transactionListener = new DeducationTransactionListenerImpl();
//`producer`需要绑定transactionListener
producer.setTransactionListener(transactionListener);

//`producer`需要sendMessageInTransaction方法发送消息
SendResult sendResult = producer.sendMessageInTransaction(msg, null);

  • TransactionListener:
public class DeducationTransactionListenerImpl implements TransactionListener {

	//当发送prepare(half)消息成功后,会执行此逻辑
	@Override
	public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
		LocalTransactionState state ;
		//todo 执行业务方法,并根据执行结果,返回state 
		return state;
	}

	/**
	 * 当没有回应prepare(half)消息时,brokder会检查此条消息的状态
	 * @param msg
	 * @return
	 */
	@Override
	public LocalTransactionState checkLocalTransaction(MessageExt msg) {
		LocalTransactionState state ;
		//todo 查看订单bizNo的状态,并返回state 
		return  state;
	}
}
  • TransactionStatus:
TransactionStatus.CommitTransaction 提交事务,允许订阅方消费该消息。
TransactionStatus.RollbackTransaction 回滚事务,消息将被丢弃不允许消费。
TransactionStatus.Unknow 暂时无法判断状态,期待固定时间以后消息队列 RocketMQ 服务端向发送方进行消息回查。
  • Message设置消息回查时间:
/**
 * 	在消息属性中添加第一次消息回查的最快时间,单位秒。
 * 	例如,以下设置实际第一次回查时间为 120 秒 ~ 125 秒之间
 *
 * 	以上方式只确定事务消息的第一次回查的最快时间,实际回查时间向后浮动0~5秒;
 * 	如第一次回查后事务仍未提交,后续每隔5秒回查一次。
	 */
msg.putUserProperty(MessageConst.PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS,"120");

4.2.5 其他消息

广播消息、 批量消息

4.2.6 附录

  • 消息类型对比:
    SpringCloud之RocketMQ2_第8张图片

  • 发送方式对比:
    SpringCloud之RocketMQ2_第9张图片

5. 发布订阅

5.1 收发模型

SpringCloud之RocketMQ2_第10张图片

5.2 producer端消息发布原理图

SpringCloud之RocketMQ2_第11张图片

5.3 consumer端两种消息获取模式

(1)push模式

MQServer主动向消费端推送

(2)pull模式

消费端在需要时,主动到MQServer拉取

5.4 consumer端有两种消息消费模式

5.4.1 集群消费

(1)集群:

使用相同 Group ID 的订阅者属于同一个集群。
同一个集群下的订阅者消费逻辑必须完全一致(包括 Tag 的使用),这些订阅者在逻辑上可以认为是一个消费节点。

(2)集群消费:

任意一条消息只需要被集群内的任意一个消费者处理即可。

(3)注意事项

  • 消费端集群化部署,每条消息只需要被处理一次。
  • 由于消费进度在服务端维护,可靠性更高。
  • 集群消费模式下,每一条消息都只会被分发到一台机器上处理。
  • 集群消费模式下,不保证每一次失败重投的消息路由到同一台机器上,因此处理消息时不应该做任何确定性假设。

(4)流程图

SpringCloud之RocketMQ2_第12张图片

5.4.2 广播消费

(1)RocketMQ 会将每条消息推送给集群内所有注册过的客户端,保证消息至少被每台机器消费一次。

(2)广播消费模式下不支持顺序消息。

  • 不支持重置消费位点。
  • 每条消息都需要被相同逻辑的多台机器处理。
  • 消费进度在客户端维护,出现重复的概率稍大于集群模式。
  • 消息队列 RocketMQ 保证每条消息至少被每台客户端消费一次,但是并不会对消费失败的消息进行失败重投,因此业务方需要关注消费失败的情况。
  • 客户端每一次重启都会从最新消息消费。客户端在被停止期间发送至服务端的消息将会被自动跳过,请谨慎选择。
  • 每条消息都会被大量的客户端重复处理,因此推荐尽可能使用集群模式。
  • 目前仅 Java 客户端支持广播模式。
  • 服务端不维护消费进度,所以控制台不支持消息堆积查询、消息堆积报警和订阅关系查询功能。

(3)流程图

SpringCloud之RocketMQ2_第13张图片


上一篇跳转—SpringCloud之RocketMQ1                 下一篇跳转—SpringCloud之RocketMQ3


官方文档

参考链接1

参考链接2

参考链接3

参考链接4

参考链接5


随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,收藏及转发,一起学习、交流!

你可能感兴趣的:(微服务SpringCloud,后端Java,开发学习拓展,spring,cloud,java,消息中间件,RocketMQ,微服务)