文章目录
1. Mq介绍
1.1 为什么要用Mq
Mq全称Message quene, 消息队列. 是一种"先进先出"的数据结构.
其应用场景主要包含以下3个方面
(1) 应用解耦
- 系统的耦合性越高, 容错性就越低. 以电商应用为例, 用户创建订单后, 如果耦合调用库存在系统, 物流系统, 支付系统, 任何一个子系统出了故障或者因为升级等原因暂时不可用, 都会造成下单操作异常, 影响用户使用体验.
- 使用消息队列解耦合, 系统的耦合性就会提高了. 比如物流系统发生了故 障, 需要几分钟才能来修复, 在这段时间内, 物流系统要处理的数据被缓存到消息队列中, 用户的下单操作正常完成. 当物流系统恢复后, 补充处理存在消息队列中的订单消息即可, 终端系统感知不到物流系统发生过几分钟故障.
(2) 流量削峰
- 应用系统如果遇到系统请求流量的瞬间猛增, 有可能会将系统压垮.
- 有了消息队列可以将大量请求缓存起来, 分散到很长一段时间处理, 这样可以大大提高系统的稳定性和用户体验.
(3) 数据分发
- 通过消息队列可以让数据在多个系统之间进行流通. 数据的产生方不需要关心谁来使用数据, 只需要将数据发送到消息队列, 数据使用方直接在消息队列中直接获取数据即可.
1.2 常见的MQ特点对比
常见的Mq产品包括Kafka, ActiveMQ, RabbitMQ, RocketMQ.
综上所述,各种对比之后,我个人倾向于是:
-
一般的业务系统要引入MQ,最早大家都用ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以大家还是算了吧,我个人不推荐用这个了;
-
后来大家开始用RabbitMQ,但是确实erlang语言阻止了大量的java工程师去深入研究和掌控他,对公司而言,几乎处于不可控的状态,但是确实人是开源的,比较稳定的支持,活跃度也高;
不过现在确实越来越多的公司,会去用RocketMQ,确实很不错,但是我提醒一下自己想好社区万一突然黄掉的风险,对自己公司技术实力有绝对自信的,我推荐用RocketMQ,否则回去老老实实用RabbitMQ吧,人是活跃开源社区,绝对不会黄.
-
所以中小型公司,技术实力较为一般,技术挑战不是特别高,用RabbitMQ是不错的选择;大型公司,基础架构研发实力较强,用RocketMQ是很好的选择.
-
如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范.
2. RocketMq
2.1 RocketMq架构
RocketMQ作为一款纯java、分布式、队列模型的开源消息中间件,支持事务消息、顺序消息、批量消息、定时消息、消息回溯等。RocketMQ由阿里巴巴开源.
RocketMq是属于非常高的分布式架构模式, 我们详细介绍下它的各个角色.
如图所示为RocketMq基本的部署结构, 主要分为NameServer集群, Broker集群, Producer集群和Consumer集群四个部分.
- NameServer: 管理Broker集群, 类似于分布式开发中的注册中心.
- Broker: 暂存和传输消息
- Topic、Tag、Queue、GroupName
Topic 与 Tag 都是业务上用来归类的标识,区分在于 Topic 是一级分类,而 Tag 可以理解为是二级分类
- Topic、Tag、Queue、GroupName
- Producer: 消息的发送者
- Consumer: 消息的接受者
大致流程:
- Broker在启动的时候会向NameServere注册并定时发送心跳, 单个Broker节点与所有的NameServer节点保持长连接及心跳, 定时每隔(30秒)注册Topic信息到所有的NameServer中.
- NameServer定时每隔(10s)扫描所有存活Broker的连接, 如果NameServer超过2分钟没有收到心跳, 则NameServer会断开与Broker的连接. 底层的通信和连接都是基于Netty实现的.
- Producer在启动的时候会到NameServer上去拉取Topic所属的Broker具体地址, 然后向具体的Broker发送消息.
- 为了消除单点故障, 增加可靠性或增大吞吐量, 可以在多台机器上部署多个nameServer和broker, 并且为每个broker部署一个或多个slave.
2.2 RocketMq架构角色介绍
(1) NameServer
NameServer的作用是Broker的注册中心.
- 每个NameServer节点互相之间是独立的, 没有任何信息交互, 也就不存在任何的选主或主从切换之类的问题, 因此NameServer是很轻量级的.
- 单个NameServer节点中存储了活跃的Broker列表(包括master和slave), 这里活跃的定义是与NameServer保持有心跳.
(2) Topic、Tag、Queue、GroupName
Topic与Tag都是业务上用来归类的标识, 区分在于Topic是一级分类, 而Tag可以理解为是二级分类.
- Topic
- Topic翻译为话题。我们可以理解为第一级消息类型,比如一个电商系统的消息可以分为:交易消息、物流消息等,一条消息必须有一个Topic
- 是生产者在发送消息和消费者在拉取消息的类别. 一个生产者可以发送不同类型Topic的消息。消费者组可以订阅一个或多个主题.
- Tag
- Tag翻译为标签, 可以理解为第二级消息类型,交易创建消息,交易完成消息… 一条消息可以没有Tag.
- 为用户提供了额外的灵活性。有了标签,方便RocketMQ提供的查询功能
- Queue
- 一个Topic下, 可以设置多个queue(消息队列), 默认是4个队列. 当我们发送消息时, 需要指定该消息的topic. RocketMq会轮询该topic下的所有队列, 将消息发送出去.
- 在 RocketMQ 中,所有消息队列都是持久化,长度无限的数据结构. 所谓长度无限是指队列中的每个存储单元都是定长,访问其中的存储单元使用 Offset 来访问,offset 为 java long 类型,64 位,理论上在 100年内不会溢出,所以认为是长度无限.
- groupName
RocketMQ中也有组的概念。代表具有相同角色的生产者组合或消费者组合,称为生产者组或消费者组.- 作用在集群也就是HA的情况下, 一个生产者宕机了, 本地事务回滚后, 可以继续联系该组中的其他生产者, 保证业务可以继续进行.
- 在消费者组中, 可以实现消息消费的负载均衡和消息容错目标.
- 有了GroupName,在集群下,动态扩展容量很方便。只需要在新加的机器中,配置相同的GroupName。启动后,就立即能加入到所在的群组中,参与消息生产或消费.
(3) Broker-存放消息
-
Broker中存放Topic信息.
- Broker上存放Topic信息, Topic由多个队列组成, 队列会平均分散在多个Broker上.
- 消息发送方发消息会自动轮询所有可以发送的Broker, 尽量平均分布到所有队列中, 最终的效果是所有消息都平均落到每个Broker上.
-
Broker是具体提供业务的服务器, 单个Broker节点与所有的NameServer节点保持长连接及心跳, 定时每隔(30秒)注册Topic信息到所有的NameServer中.
-
NameServer定时每隔(10s)扫描所有存活Broker的连接, 如果NameServer超过2分钟没有收到心跳, 则NameServer会断开与Broker的连接. 底层的通信和连接都是基于Netty实现的的.
(4) Producer-生产者
- 与NameServer的关系
单个Producer和一台NameServer节点(随机选择) 保持长连接, 定时查询 - 与Broker的关系
单个Produce和与其关联的所有broker保持长连接, 并维持心跳. 默认情况下消息发送采用轮询方式, 会均匀发到对应Topic的所有queue中.
(5) Consumer-消费消息
- 与nameserver的关系
单个Consumer和一台NameServer保持长连接,定时查询topic配置信息,如果该NameServer挂掉,消费者会自动连接下一个NameServer,直到有可用连接为止,并能自动重连。与NameServer之间没有心跳。 - 与broker的关系
单个Consumer和与其关联的所有broker保持长连接,并维持心跳,失去心跳后,则关闭连接,并向该消费者分组的所有消费者发出通知,分组内消费者重新分配队列继续消费。
消费者类型
RocketMQ有2种常见的消费模式, 分别是DefaultMQPushConsumer和DefaultMQPullConsumer模式, 这2种模式字面理解一个是推送消息, 一个是拉取消息. 但无论是Push还是Pull, 其本质都是拉取消息, 只是实现机制不一样.
- push consume 推模式
其实并不是Broker主动向Consumer推送消息, 而是consumer向broker发出请求, 保持了一种长链接, broker会每4秒检测一次是否有消息, 如果有消息, 则将消息推送给consumer. 使用push模式实现消息消费, broker会主动记录消息消费的偏移量. - pull consume 拉模式
拉模式是消费方主动去broker拉取数据, 一般会在本地使用定时任务实现, 使用它获得消息状态方便, 负载均衡性能可控, 但消息的及时性差, 而且需要手动记录消息消费的偏移量信息, 所以在工作中多数情况推荐使用Push模式.
消费模式
- 集群模式:在默认情况下,就是集群消费,此时消息发出去后将只有一个消费者能获取消息。
- 广播模式:一条消息被多个Consumer消费。消息会发给Consume Group中的每一个消费者进行消费。