RabbitMQ详解

一、主流消息中间件介绍

ActiveMQ

Kafka

RocketMQ

RabbitMQ

二、RabbitMQ核心概念及AMQP协议

互联网大厂为什么选择RabbitMQ

开源, 性能优秀, 稳定性保障
提供可靠的消息投递模式(confirm), 返回模式(return)
SpringAMQP完美整合, API丰富
集群模式丰富, 表达式配置, HA模式, 镜像队列模型
保证数据不丢失的前提做到高可靠性, 可用性

RabbitMQ的高性能是如何做到的

Erlang语言最初用于交换机领域的架构模式, 这样使得RabbitMQ在Broker之间进行数据交互的性能是非常优秀的
Erlang的优点: 有着和原生Socket一样的延迟

什么是AMQP高级协议

Advanced Message Queuing Protocal
高级消息队列协议
具有现代特征的二进制协议. 是一个提供统一消息服务的应用层标准高级消息队列协议, 是应用层协议的一个开放标准, 为面向消息的中间件设计

AMQP协议模型

RabbitMQ详解_第1张图片

AMQP核心概念是什么

Server: 又称Broker, 接受客户端的连接, 实现AMQP实体服务
Connection: 连接, 应用程序与Broker的网络连接
Channel: 网络信道, 几乎所有的操作都在Channel中进行, Channel是进行消息读写的通道. 客户端可以建立多个Channel, 没一个Channel代表一个会话任务
Message: 消息, 服务器和应用程序之间传送的数据, 由Properties和Body组成. Properties可以对消息进行修饰, 比如消息的优先级, 延迟等高级特性; Body就是消息体内容
Virtual host: 虚拟地址, 用于进行逻辑隔离, 最上层的消息路由. 一个Virtual host里面可以有若干个Exchange和Queue, 同一个Virtual host里面不能有相同名称的Exchange和Queue
Exchange: 交换机, 接收消息, 根据路由键转发消息到绑定的队列
Binding: Exchange和Queue之间的虚拟连接, binding中可以包含routing key
Routing key: 一个路由规则, 虚拟机可用它来确定如果路由一个特定消息
Queue: 消息队列, 保存消息并将它们转发给消费者

RabbitMQ整体架构模型是什么样子的

RabbitMQ详解_第2张图片

RabbitMQ消息是如何流转的

RabbitMQ详解_第3张图片

RabbitMQ消息生产与消费

ConnectionFactory: 获取连接工厂
Connection: 一个连接
Channel: 数据通信信道, 可发送和接收消息
Queue: 具体的消息存储队列
Producer & Consumer 生产者和消费者

RabbitMQ交换机详解

交换机属性:

Name: 交换机名称
Type: 交换机类型 direct topic fanout headers
Durability: 是否需要持久化, true为持久化
Auto Delete: 当最后一个绑定到Exchange上的队列删除后, 自动删除该Exchange
Internal: 当前Exchange是否用于RabbitMQ内部使用, 默认为False(一般不使用)
Arguments: 扩展参数, 用于扩展AMQP协议定制化使用

Direct Exchange

所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue
注意: Direct模式可以使用RabbitMQ自带的Exchange: Default Exchange, 所以不需要将Exchange进行任何绑定操作, 消息传递时, RouteKey必须完全匹配才会被队列接收, 否则该消息会被抛弃
RabbitMQ详解_第4张图片

Topic Exchange

所有发送到Topic Exchange的消息被转发到所有关心RouteKey中指定Topic的Queue上
Exchange将RouteKey和某个Topic进行模糊匹配, 此时队列需要绑定一个Topic
注意: 可以使用通配符进行模糊匹配
符号#匹配一个或者多个词
符号#匹配一个词
RabbitMQ详解_第5张图片

Fonout Exchange

不处理路由键, 只需要简单的将队列绑定到交换机上
发送到交换机的消息都会被转发到与该交换机绑定的所有队列上
Fonout交换机转发消息是最快的
RabbitMQ详解_第6张图片

RabbitMQ队列、绑定、虚拟主机、消息

绑定

Exchange和Exchange, Queue之间的连接关系
Binding中可以包含RoutingKey或者参数

消息队列

实际存储消息数据
Durability: 是否持久化, Durable: 是, Transient: 否
Auto Delete: yes时, 代表当最后一个监听被移除后, 该Queue会自动被删除

消息

服务器和应用程序之间传送的数据
本质上就是一段数据, 由Properties和(Payload)Body组成
常用属性:
delivery mode(可以做持久化或者内存级别的非持久化)
headers(自定义属性)
其他属性:
content_type
content_encoding
priority(0-9, 分布式环境并不能保证顺序消费)
correlation_id(消息唯一id, ack, 消息路由, 幂等会用到)
reply_to(重回队列使用)
expiration(消息过期时间)
message_id

虚拟主机

虚拟地址, 用于进行逻辑隔离, 最上层的消息路由
一个Virtual host里面可以有若干个Exchange和Queue
同一个Virtual host里面不能有相同名称的Exchange和Queue

三、RabbitMQ高级特性

消息如何保障100%的投递成功

生产端的可靠性投递

保障消息的成功发出
保障MQ节点的成功接收
发送端收到MQ节点的确认应答
完善的消息进行补偿机制

大厂解决方案
消息落库, 对消息状态进行打标
缺点: 消息状态落库导致性能下降
RabbitMQ详解_第7张图片
消息延迟投递, 做二次确认, 回调检查
RabbitMQ详解_第8张图片

幂等性概念详解

在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的,更复杂的操作幂等保证是利用唯一交易号(流水号)实现.

在海量订单产生的业务高峰期, 如何避免消息的重复消费问题

消费端-幂等性保障

唯一ID+指纹码机制, 利用数据库主键去重
SELECT COUNT(1) FROM T_ORDER WHERE ID = 唯一ID+指纹码
好处: 实现简单
坏处: 高并发下有数据库写入的性能瓶颈
解决方案: 根据ID进行分库分表进行算法路由

利用Redis的原子性实现
数据需要落库, 如何保证缓存和数据库原子性操作
数据不需要落库, 如何设置数据同步策略

Confirm确认消息, Return返回消息

Confirm确认消息

是指生产者投递消息后, 如果Broker收到消息, 则会给生产者一个应答
生产者进行接收应答, 用来确定这条消息是否正常的发送到Broker, 这种方式也是消息可靠性投递的核心保障
第一步: 在channel上开启确认模式: channel.confirmSelect()
第二步: 在channel上添加监听: addConfirmListener, 监听成功和失败的返回结果, 根据具体的结果对消息进行重新发送或记录日志等处理
RabbitMQ详解_第9张图片

Return返回消息

用于处理一些不可路由的消息
在某些情况下, 如果我们在发送消息的时候, 当前的Exchange不存在或者指定的RouteKey路由不到, 这个时候如果我们需要监听这种不可达的消息, 就需要使用Return Listener
Mandatory: 如果为true, 则监听器会接收到路由不可达的消息, 然后进行后续处理, 如果为false, 那么Broker会自动删除该消息
RabbitMQ详解_第10张图片

消息的ACK与重回队列

消费端的手工ACK和NACK
消费端进行消费的时候, 如果由于业务异常我们可以进行日志的记录, 然后进行补偿
如果由于服务器宕机等严重问题, 那我们就需要手工进行ACK保障消费端消费成功
重回队列
对没有处理成功的消息, 把消息重新回递给Broker
一般实际应用中, 都是关闭重回队列

消息的限流

RabbitMQ服务器有上万条数据, 随便打开一个消费者客户端, 瞬间收到巨量的消息
RabbitMQ提供了一种Qos功能, 在非自动确认消息的前提下, 如果一定数目的消息未被确认前, 不进行新消息的消费
注意: 该功能一定要手动签收

TTL消息

Time To Live
RabbitMQ支持消息过期时间, 在发送消息时可以指定
RabbitMQ支持队列的过期时间, 从消息入队列开始计算, 只要超过了队列的超时时间, 那么消息会自动清除

死信队列

Dead Letter Exchange
利用DLX, 当消息在一个队列中变成死信之后, 他能被重新publish到另一个Exchange, 这个Exchange就是DLX
变成死信的几种情况
消息被拒绝并且requeue=false(无重回队列)
消息TTL过期
队列达到最大长度

四、RabbitMQ集群架构

架构模式

主备模式: 实现RabbitMQ的高可用集群, 一般在并发和数据量不高的情况下, 这种模型非常的好用且简单. 也叫Warren模式

主节点挂了, 备份节点提供服务, 备份节点不参与读写
RabbitMQ详解_第11张图片

远程模式: 远程模式可以实现双活的一种模式, 简称Shovel模式, 所谓Shovel就是我们可以把消息进行不同数据中心的复制工作, 我们可以跨地域的让两个MQ集群互联

该模型需要插件
RabbitMQ详解_第12张图片
RabbitMQ详解_第13张图片

镜像模式: 集群模式非常经典的就是Mirror镜像模式, 保证100%数据不丢失, 在实际工作中也是用的最多的. 并且实现集群非常简单, 一般互联网大厂都会构建这种镜像集群模式

RabbitMQ详解_第14张图片

多活模式: 这种模式也是实现异地数据复制的主流模式, 因为Shovel模式配置比较复杂, 所以一般来说实现异地集群都是使用这种双活或者多活模型来实现的. 这种模型需要依赖RabbitMQ的federation插件, 可以实现持续的可靠的AMQP数据通信, 多活模式在实际配置与应用中非常简单

RabbitMQ部署架构采用双中心模式(多中心), 那么在两套(多套)数据中心中各部署一套RabbitMQ集群, 各中心的RabbitMQ服务除了需要为业务提供正常的消息服务外, 中心之间还需要实现部分队列消息共享
RabbitMQ详解_第15张图片
Federation插件是一个不需要构建Cluster, 可以在Brokers之间传输消息的高性能插件, Federation插件可以在Brokers或者Cluster之间传输消息, 连接的双方可以使用不同的users和Virtual Hosts, 双方也可以使用版本不同的RabbitMQ和Erlang. Federation插件使用AMQP协议通讯, 可以接受不连续的传输
RabbitMQ详解_第16张图片

高级插件的使用

HaProxy

是一款提供高可用性, 负载均衡以及基于TCP和HTTP应用的代理软件, 支持虚拟主机, 它是免费, 快速并且可靠的一种解决方案. HaProxy适用于负载特别大的web站点, 这些站点通常又需要会话保持或七层处理. HaProxy运行在时下的硬件上, 完全可以支持数以万计的并发连接. 并且它的运行模式使得它可以很简单安全的整合进当前架构中, 同时可以保护web服务器不被暴露到网络上

  1. 单进程, 事件驱动模型显著降低了上下文切换的开销及内存占用
  2. 在任何可用的情况下, 单缓冲机制能以不复制任何数据的方式完成读写操作, 这会节约大量的CPU时钟周期及内存带宽
  3. 借助于Linux2.6(>=2.6.27.19)上的splice()系统调用, HaProxy可以实现零复制转发, 在Linux3.5及以上的OS中还可以实现零复制启动
  4. 内存分配器在固定大小的内存池中可实现即时内存分配, 这能够显著减少创建一个会话的时长
  5. 树形存储: 侧重于使用作者多年前开发的弹性二叉树, 实现了以O(log(N))的低开销来保持计时器命令, 保持运行队列命令及管理轮训及最少连接队列

KeepAlived

通过VRRP协议实现高可用功能. VRRP是Virtual Router Redundancy Protocol的缩写, VRRP出现的目的就是为了解决静态路由单点故障问题的, 它能够保证当个别节点宕机时, 整个网络可以不间断地运行, 所以, KeepAlived一方面具有配置管理LVS的功能, 同时还具有对LVS下面节点进行健康检查的功能, 另一方面也可实现系统网络服务的高可用功能
三个重要功能:

  1. 管理LVS负载均衡软件
  2. 实现LVS集群节点的健康检查
  3. 作为系统网络服务的高可用性(failover)
    RabbitMQ详解_第17张图片

延迟插件

消息的延迟推送, 定时任务的执行. 包括一些消息重试策略的配合使用, 以及用于业务削峰限流, 降级的异步延迟消息机制

集群故障, 失败转移讲解

前提: 两个节点, A和B组成一个镜像队列
场景1: A先停, B后停
方案: B是master, 只要先启动B, 再启动A即可. 或者先启动A, 过30秒再启动B即可

场景2: AB同时停机
方案: 在30秒之内连续启动A和B即可恢复

场景3: A先停, B后停, 且A没有办法恢复
方案: B启动之后, 在B节点上解除与A的Cluster关系, 再将新的Slave节点加入到B即可恢复

场景4: A先停, B后停, 且B没有办法恢复
方案: 在3.4.2以后的版本, 支持线下忘记B节点, 再将新的Slave节点加入到A即可恢复

场景5: A先停, B后停, 且AB无法恢复, 但是能得到A或B的磁盘文件
方案: 替换数据库文件, 如果替换的是A文件, 后续按照场景4处理, 如果替换的是B文件, 后续按照场景3处理

五、单元化架构

单元化架构的衍变

容灾问题

核心服务(订单)挂掉, 会影响全网所有用户, 导致整个业务不可用
数据库主库集中在一个IDC, 主机房挂掉, 会影响全网所有用户, 整个业务无法快速切换和恢复

资源扩展问题

单IDC的资源已经没法满足, 扩展IDC时, 存在跨机房延迟问题
数据库主库单点, 连接数有限, 不能支持应用程序的持续扩展

大集群拆分问题

分布式规模扩大后, 会相应的带来资源扩展, 大集群拆分以及容灾问题
所以出于对业务扩展性以及容灾需求的考虑, 需要一套从底层架构彻底解决问题的方案, 单元化架构方法

大厂是如何进行单元化的

同城双活

业务层面上已经做到了真正的双活, 分别承担部分流量
存储层面比如定时任务, 缓存, 持久层, 数据分析等都是主从架构, 会有跨机房写
一个数据中心故障, 可以手动切换流量, 部分组件可以自动切换

两地三中心

在同城双活的基础上, 在异地部署一套灾备数据中心, 每个中心都具有完备的数据处理能力, 只有当主节点故障需要容灾的时候才会紧急启动备用数据中心
RabbitMQ详解_第18张图片

SET化架构

业务: 解决业务遇到的扩展性和容灾等需求, 支撑业务的高速发展
通用性: 架构侧形成统一通用的解决方案, 方便各个业务线接入使用
RabbitMQ详解_第19张图片
流量路由:
按照特殊的key(通常为userId)进行路由, 判断某次请求该路由到中心集群还是单元化集群
中心集群:
未进行单元化改造的服务(通常不在核心交易链路, 如供应链系统), 跟当前架构保持一致
单元化集群:
每个单元化集群只负责本单元内的流量处理, 以实现流量拆分以及故障隔离
每个单元化集群前期只存储本单元产生的交易数据, 后续会做双向数据同步, 实现容灾切换需求
中间件:
RPC: 对于SET服务, 调用封闭在SET内; 对于非SET服务, 沿用现有路由逻辑
KV: 支持分SET的数据生产和查询
MQ: 支持分SET的消息生产和消费
数据同步:
全局数据(数据量小且变化不大, 比如商家菜品数据)部署在中心集群, 其他单元化集群, 同步全局数据到本单元内
未来演变为异地多活架构时, 各单元集群数据需要进行双向同步来实现容灾需求

SET化路由策略及其能力:

异地容灾:
通过SET化架构的流量调度能力, 将SET分别部署在不同地区的数据中心, 实现跨地区容灾支持
高效本地化服务:
利用前端位置信息采集和域名解析策略, 将流量路由到最近的SET, 提供最高效的本地化服务
集装箱式扩展:
SET的封装性支持更灵活的部署扩展性, 比如SET一键创建/下线, 一键发布
RabbitMQ详解_第20张图片
RabbitMQ详解_第21张图片

SET化架构的设计与解决方案

SET化架构原则:
对业务透明原则:
SET化架构的实现对业务代码透明, 业务代码层面不需要关心SET化规则, SET的部署等问题
切分规则:
理论上, 切分规则由业务层面按需订制
实现上, 建议优先选最大的业务维度进行切分
比如海量用户的O2O业务, 按用户位置信息进行切分. 此外, 接入层, 逻辑层和数据层可以有独立的SET切分规则, 有利于实现部署和运维成本的最优化
部署规则:
一个SET并不一定只限制在一个机房, 也可以跨机房或者跨地区部署, 为保证灵活性, 单个SET内机器数不宜过多

六、基础组件设计

大厂MQ组件实现思路和架构设计方案

RabbitMQ详解_第22张图片

实现功能点一

支持消息高性能的序列化转换, 异步化发送消息
支持消息生产实例与消费实例的链接池化缓存化, 提升性能
支持可靠性投递消息, 保障消息的100%不丢失
支持消费端的幂等操作, 避免消息端重复消费的问题

实现功能点二

支持迅速消息发送模式, 在一些日志收集/统计分析等需求下可以保证高性能, 超高吞吐量
支持延迟消息模式, 消息可以延迟发送, 指定延迟时间, 用于某些延迟检查, 服务限流场景
支持事物消息, 且100%保障可靠性投递, 在金融行业单笔打击呢操作时会有此类需求

实现功能点三

支持顺序消息, 保证消息送达消费端的前后顺序, 例如下单等复合操作
支持消息补偿, 重试, 以及快速定位异常/失败消息
支持集群消息负载均衡, 保障消息落到具体SET集群的负载均衡
支持消息路由策略, 指定某些消息路由到指定的SET集群

迅速消息发送

RabbitMQ详解_第23张图片

确认消息发送

RabbitMQ详解_第24张图片

批量消息发送

RabbitMQ详解_第25张图片

延迟消息发送

延迟插件

顺序消息发送

RabbitMQ详解_第26张图片

事物消息发送

RabbitMQ详解_第27张图片

消息幂等性保障-消息路由规则架构设计

RabbitMQ详解_第28张图片

你可能感兴趣的:(Java)