RocketMQ系列(一)——基础篇

前言

 本篇是RocketMQ系列的第一篇,主要针对对RocketMQ感兴趣或想系统学习RocketMQ的同学,内容相对基础,包括各种名称与术语解释、集群架构以及所支持的各种特性与适用场景。想深入了解其原理的请阅读后面的章节。

 RocketMQ系列(二)——应用篇
 RocketMQ系列(三)——原理篇

 RocketMQ是一款分布式消息中间件,由阿里巴巴中间件团队开发并用于生产环境,2016年捐赠给Apache开源基金会,随后成为Apache的顶级项目。

 常见的消息中间件还包括:RabbitMQ、Kafka、ActiveMQ,另外Redis也可以作为消息中间件的一种简单实现。

一、名词解释

Producer

 Producer :消息的生产者,负责产生消息,如:用户完成支付后产生一条交易成功消息。一个producer实例可以往多个topic发送消息。

 Producer Group:一类producer的集合,这类producer通常发送同一种类型的消息,且发送逻辑一致。如:不同应用节点 or 不同渠道的交易订单属于同一类消息。

 一般来说,在同一应用节点(JVM)的同一套配置中(通过unitName划分,系列三原理篇会说明),一个Producer Group只能有一个producer实例。

 如果事务消息出现异常,同一Group中的其它producer节点可以执行(服务端的)提交或回滚操作。

Consumer

 Consumer:消息的消费者,负责消费消息,如:活动服务接收到交易成功消息后向用户发放优惠券。一个consumer实例可以订阅多个topic。

 Consumer Group:一类consumer的集合名称,这类consumer消费同一类消息,且消费逻辑一致。

 与Producer Group类似,在同一应用节点(JVM)的同一套配置中,一个Consumer Group只能有一个consumer实例。

 Push Consumer:consumer的一种,应用程序向consumer对象注册一个Listener接口(MessageListener),一旦收到消息,consumer会回调Listener接口的方法。

 Pull Consumer:consumer的一种,应用程序主动从broker拉取消息,主动权由应用程序控制。

Broker

 消息中转角色,一般也称为Server,负责存储和接受消息拉取请求,producer发送的消息顺序存储在broker的queue中。

 broker的角色分为Master(主节点)和Slave(从节点),区别主要在于消息只能往Master节点写入,从节点被动从Master同步数据。

 一个broker可以存储多个topic的queue,broker与topic是多对多的关系。

NameServer

 轻量级命名服务,producer、consumer和broker的路由控制中心,提供类似于服务注册与发现功能,通常以集群形式部署,彼此之间无通信,局部出问题不影响整个集群,所以稳定性很高。

 每个NameServer维护着集群中所有的broker及topic路由信息。

Topic

 消息主题,一级消息类型,通过 topic 对消息进行分类与业务隔离。如:交易成功消息和用户注册消息可以通过不同topic进行区分。

 topic是一个逻辑概念,一个topic可以划分为多个queue,这些queue存储在不同的broker中,broker与topic是多对多的关系。

 如果消息量比较大的情况下,应该多指定几个队列以便分散broker和consumer的压力。

Tag

 消息标签,二级消息类型,用来进一步区分某个topic下的消息分类,如用success、refund分别表示交易成功和退款的订单消息。

 消费者可以通过订阅不同的tags来对topic下的消息进行选择性的消费。

Message

 消息,发送、存储和消费的载体,一条消息必须指定topic和消息体(body),另外可以选择性指定tags和keys。

Queue

 消息队列,由同一类型的消息按发送顺序组成,broker中划分存储的最小单元,topic与queue的关系为一对多。

 同一类message顺序组成queue,一个或多个queue组成topic,topic按queue维度存放在不同的broker中。

 实际上queue保存的不是真正的消息数据,而是指向commit log的消息索引,commit log才是存储消息的结构。

Broker、Topic与Queue的关系

 创建topic时可以用集群模式创建,每个broker中的queue数量相同;也可以用单个broker模式创建,这样每个broker中的queue数量可能不同。它们之间的具体关系(单个broker模式创建topic)如下图:
在这里插入图片描述

二、集群架构

集群部署结构在这里插入图片描述

 启动顺序:1、NameServer启动 → 2、Broker启动 → 3、Broker创建topic → 4、Producer启动 → 5、Consumer启动

通信方式

 纵轴表示通信发起方,横轴表示被连接方

NameServerBrokerProducerConsumer
NameServer彼此无通信每隔10s扫描所有存活的broker,若2分钟内没有收到心跳包,则断开与broker的连接,并更新topic与queue的关系--
Broker每个broker与所有NameServer保持长连接,每隔30s向所有NameServer发送包含了自身topic配置信息的心跳包;包含信息:地址,brokerName,brokerId,topic,queue等彼此无通信每隔10s扫描所有存活的producer,若2分钟内没有收到心跳数据,则断开与producer的连接每隔10s扫描所有存活的consumer,若2分钟内没有收到心跳数据,则断开与consumer的连接,并向该消费者组所有消费者发出通知,重新分配队列进行消费
Producer每个producer与一台NameServer保持长连接,每隔30s查询topic配置信息;如果连接的NameServer宕机,则会自动连接下一个NameServer每个producer和(topic的queue)关联的所有broker保持长连接,每隔30s发送心跳彼此无通信-
Consumer每个consumer与一台NameServer保持长连接,每隔30s查询topic配置信息;如果连接的NameServer宕机,则会自动连接下一个NameServer每个consumer和(topic的queue)关联的所有broker保持长连接,每隔30s发送心跳-彼此无通信

集群部署模式

 单Master:配置简单,安全性低,一般不用于生产环境
 多Master:性能较高,但无法做到高可用,较少采用
 主从同步双写:主从节点都写入成功后才向客户端返回成功;一致性和安全性高但性能稍差;公司集群采用该方式,2主2从共4个节点
 主从异步复制:Master写入成功立即返回,Slave异步方式复制消息;性能较高但有数据丢失风险

持久化方式

 同步刷盘:刷盘到文件才会返回成功
 异步刷盘:先返回,再刷新到磁盘;公司集群采用该方式

三、支持特性

消息发送方式

 同步发送:发送线程等待发送结果或超时;适用于绝大部分消息较为重要的业务场景
 异步发送:调用发送接口后不等待发送结果,继续执行后续业务逻辑,提供发送回调接口(SendCallback);适用于消息重要但又对发送效率要求较高的场景
 单向发送:只发送,不关心发送结果;适用于并发量大,消息重要性不高的场景

消息获取方式

push模式:(看起来是)broker将消息推送给consumer,最常用模式
 优点:消息处理及时,客户端逻辑简单
 缺点:消息存放在消费者内存中,可能导致消费者的消息积压,处理缓慢
 适用场景:对于数据实时性要求高的场景

pull模式:consumer主动从broker拉取消息
 优点:客户端可以根据自己的消费能力进行消费,不会导致消费者消息积压
 缺点:应用程序逻辑稍复杂,需要记录队列的消费位置及拉取频率等;拉取频率高容易导致服务端压力大,频率低消息得不得及时消费
 适用场景:生产者消息数量大,消费逻辑复杂或消费能力较低的场景

消息过滤

 TAG模式:常用的消息过滤模式,发送阶段在构建消息时指定TAG,consumer订阅时可以订阅多个TAG或模糊匹配
 SQL表达式:通过设置消息的用户属性,过滤时运行SQL过滤表达式进行条件匹配。注意:默认不支持属性过滤,要开启该功能需要在broker的配置文件中添加enablePropertyFilter = true并全部重启后生效
 类过滤模式:自定义消息过滤接口(MessageFilter)实现消息过滤

 其中后两种方式只支持push方式,更多细节请参考:RocketMQ消息过滤
 思考:消息过滤是在客户端还是在服务端?

消息模式

 集群模式:通常同一个queue由consumer group中的固定consumer实例消费,但也有例外,如pull模式下拉取全部队列进行消费;适用于大部分场景。
 广播模式:每个consumer实例都会消费topic中的全部消息;应用场景举例:订单服务中,节点本地内存保存了用户的新老用户状态,当新用户变为老用户时,需要通知所有节点更新本地状态。

事务消息

 支持先发送半消息到broker,此时消息无法被consumer消费,待producer本地事务完成后再通知broker该消息可以被正常发送。
 注意事务消息与分布式事务的区别,前者指发送消息和本地事务的执行结果保持一致(本地事务执行完成则发送成功,本地事务执行失败则回滚发送的消息),后者指不同分布式节点之间的执行结果保持一致。
 应用场景举例:下单成功才向用户推送订单消息。

顺序消息

 指同一类型(topic)中具有先后顺序的消息,可以保证消费时的顺序与发送时保持一致。如:下单→付款→发货。
 顺序消息分为全局有序和局部有序,全局有序需要设置队列数为1才能保证,这会大大降低系统吞吐量,一般应用实现局部有序就能满足要求。

 实现关键:有序发送,有序存储,有序消费,缺一不可
  有序发送:由同一个producer单线程按产生顺序发送
  有序存储:按照一定的规则选取同一个队列发送,如按照订单号取模确定发送的消息队列
  有序消费:一个消费者单线程消费,保证了FIFO

延迟消息

 延迟消息是指发送出去的消息不能马上被消费,而是要等待某些固定的时间后才会投递给真正的队列进行消费。Apache版本支持18种特定时间延迟,阿里收费版支持精确到秒级的延迟。

 实现思想是broker为每种延迟时间的消息建立一个队列,该队列对正常的消费者不可见,然后启动线程轮询这些队列,如果有消息达到延迟时间,就将其转为普通消息存放到真实的topic队列下。

 应用场景举例:用户下单半小时后提醒其支付

 思考:如何实现支持任意时间的延迟?

消息重试与死信队列

 消息因为各种原因消费失败后,会被重新投递到名为%RETRY%+${consumerGroup}的重试队列(注意:该队列以consumerGroup为维度而不是topic),并且每次投递根据重试次数设置延迟级别。

 当重试次数达到一定限制后(默认16次)会成为死信消息(DLM:Dead-Letter Message),死信消息不会被立刻丢弃,而是存放在专门的队列中,存放死信消息的队列就叫死信队列(DLQ:Dead-Letter Queue)。

 进入死信队列的消息需要人工干预,通常有三种处理方式:
  1、直接丢弃
  2、将死信消息重新投递到正常的消息队列中
  3、创建专门处理死信队列的consumer进行消费

 思考:
  为什么要设计重试队列和死信队列?
  延迟消息与消费重试的关系?

【参考资料】

 https://www.jianshu.com/p/570680b32590
 https://my.oschina.net/mingxungu/blog/3083963
 https://www.jianshu.com/p/2c904cc42d95
 https://www.cnblogs.com/hzmark/p/mq-delay-msg.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值