开源, 性能优秀, 稳定性保障
提供可靠的消息投递模式(confirm), 返回模式(return)
SpringAMQP完美整合, API丰富
集群模式丰富, 表达式配置, HA模式, 镜像队列模型
保证数据不丢失的前提做到高可靠性, 可用性
Erlang语言最初用于交换机领域的架构模式, 这样使得RabbitMQ在Broker之间进行数据交互的性能是非常优秀的
Erlang的优点: 有着和原生Socket一样的延迟
Advanced Message Queuing Protocal
高级消息队列协议
具有现代特征的二进制协议. 是一个提供统一消息服务的应用层标准高级消息队列协议, 是应用层协议的一个开放标准, 为面向消息的中间件设计
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: 消息队列, 保存消息并将它们转发给消费者
ConnectionFactory: 获取连接工厂
Connection: 一个连接
Channel: 数据通信信道, 可发送和接收消息
Queue: 具体的消息存储队列
Producer & Consumer 生产者和消费者
Name: 交换机名称
Type: 交换机类型 direct topic fanout headers
Durability: 是否需要持久化, true为持久化
Auto Delete: 当最后一个绑定到Exchange上的队列删除后, 自动删除该Exchange
Internal: 当前Exchange是否用于RabbitMQ内部使用, 默认为False(一般不使用)
Arguments: 扩展参数, 用于扩展AMQP协议定制化使用
所有发送到Direct Exchange的消息被转发到RouteKey中指定的Queue
注意: Direct模式可以使用RabbitMQ自带的Exchange: Default Exchange, 所以不需要将Exchange进行任何绑定操作, 消息传递时, RouteKey必须完全匹配才会被队列接收, 否则该消息会被抛弃
所有发送到Topic Exchange的消息被转发到所有关心RouteKey中指定Topic的Queue上
Exchange将RouteKey和某个Topic进行模糊匹配, 此时队列需要绑定一个Topic
注意: 可以使用通配符进行模糊匹配
符号#匹配一个或者多个词
符号#匹配一个词
不处理路由键, 只需要简单的将队列绑定到交换机上
发送到交换机的消息都会被转发到与该交换机绑定的所有队列上
Fonout交换机转发消息是最快的
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
保障消息的成功发出
保障MQ节点的成功接收
发送端收到MQ节点的确认应答
完善的消息进行补偿机制
大厂解决方案
消息落库, 对消息状态进行打标
缺点: 消息状态落库导致性能下降
消息延迟投递, 做二次确认, 回调检查
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的,更复杂的操作幂等保证是利用唯一交易号(流水号)实现.
唯一ID+指纹码机制, 利用数据库主键去重
SELECT COUNT(1) FROM T_ORDER WHERE ID = 唯一ID+指纹码
好处: 实现简单
坏处: 高并发下有数据库写入的性能瓶颈
解决方案: 根据ID进行分库分表进行算法路由
利用Redis的原子性实现
数据需要落库, 如何保证缓存和数据库原子性操作
数据不需要落库, 如何设置数据同步策略
是指生产者投递消息后, 如果Broker收到消息, 则会给生产者一个应答
生产者进行接收应答, 用来确定这条消息是否正常的发送到Broker, 这种方式也是消息可靠性投递的核心保障
第一步: 在channel上开启确认模式: channel.confirmSelect()
第二步: 在channel上添加监听: addConfirmListener, 监听成功和失败的返回结果, 根据具体的结果对消息进行重新发送或记录日志等处理
用于处理一些不可路由的消息
在某些情况下, 如果我们在发送消息的时候, 当前的Exchange不存在或者指定的RouteKey路由不到, 这个时候如果我们需要监听这种不可达的消息, 就需要使用Return Listener
Mandatory: 如果为true, 则监听器会接收到路由不可达的消息, 然后进行后续处理, 如果为false, 那么Broker会自动删除该消息
消费端的手工ACK和NACK
消费端进行消费的时候, 如果由于业务异常我们可以进行日志的记录, 然后进行补偿
如果由于服务器宕机等严重问题, 那我们就需要手工进行ACK保障消费端消费成功
重回队列
对没有处理成功的消息, 把消息重新回递给Broker
一般实际应用中, 都是关闭重回队列
RabbitMQ服务器有上万条数据, 随便打开一个消费者客户端, 瞬间收到巨量的消息
RabbitMQ提供了一种Qos功能, 在非自动确认消息的前提下, 如果一定数目的消息未被确认前, 不进行新消息的消费
注意: 该功能一定要手动签收
Time To Live
RabbitMQ支持消息过期时间, 在发送消息时可以指定
RabbitMQ支持队列的过期时间, 从消息入队列开始计算, 只要超过了队列的超时时间, 那么消息会自动清除
Dead Letter Exchange
利用DLX, 当消息在一个队列中变成死信之后, 他能被重新publish到另一个Exchange, 这个Exchange就是DLX
变成死信的几种情况
消息被拒绝并且requeue=false(无重回队列)
消息TTL过期
队列达到最大长度
RabbitMQ部署架构采用双中心模式(多中心), 那么在两套(多套)数据中心中各部署一套RabbitMQ集群, 各中心的RabbitMQ服务除了需要为业务提供正常的消息服务外, 中心之间还需要实现部分队列消息共享
Federation插件是一个不需要构建Cluster, 可以在Brokers之间传输消息的高性能插件, Federation插件可以在Brokers或者Cluster之间传输消息, 连接的双方可以使用不同的users和Virtual Hosts, 双方也可以使用版本不同的RabbitMQ和Erlang. Federation插件使用AMQP协议通讯, 可以接受不连续的传输
是一款提供高可用性, 负载均衡以及基于TCP和HTTP应用的代理软件, 支持虚拟主机, 它是免费, 快速并且可靠的一种解决方案. HaProxy适用于负载特别大的web站点, 这些站点通常又需要会话保持或七层处理. HaProxy运行在时下的硬件上, 完全可以支持数以万计的并发连接. 并且它的运行模式使得它可以很简单安全的整合进当前架构中, 同时可以保护web服务器不被暴露到网络上
通过VRRP协议实现高可用功能. VRRP是Virtual Router Redundancy Protocol的缩写, VRRP出现的目的就是为了解决静态路由单点故障问题的, 它能够保证当个别节点宕机时, 整个网络可以不间断地运行, 所以, KeepAlived一方面具有配置管理LVS的功能, 同时还具有对LVS下面节点进行健康检查的功能, 另一方面也可实现系统网络服务的高可用功能
三个重要功能:
消息的延迟推送, 定时任务的执行. 包括一些消息重试策略的配合使用, 以及用于业务削峰限流, 降级的异步延迟消息机制
前提: 两个节点, 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时, 存在跨机房延迟问题
数据库主库单点, 连接数有限, 不能支持应用程序的持续扩展
分布式规模扩大后, 会相应的带来资源扩展, 大集群拆分以及容灾问题
所以出于对业务扩展性以及容灾需求的考虑, 需要一套从底层架构彻底解决问题的方案, 单元化架构方法
业务层面上已经做到了真正的双活, 分别承担部分流量
存储层面比如定时任务, 缓存, 持久层, 数据分析等都是主从架构, 会有跨机房写
一个数据中心故障, 可以手动切换流量, 部分组件可以自动切换
在同城双活的基础上, 在异地部署一套灾备数据中心, 每个中心都具有完备的数据处理能力, 只有当主节点故障需要容灾的时候才会紧急启动备用数据中心
业务: 解决业务遇到的扩展性和容灾等需求, 支撑业务的高速发展
通用性: 架构侧形成统一通用的解决方案, 方便各个业务线接入使用
流量路由:
按照特殊的key(通常为userId)进行路由, 判断某次请求该路由到中心集群还是单元化集群
中心集群:
未进行单元化改造的服务(通常不在核心交易链路, 如供应链系统), 跟当前架构保持一致
单元化集群:
每个单元化集群只负责本单元内的流量处理, 以实现流量拆分以及故障隔离
每个单元化集群前期只存储本单元产生的交易数据, 后续会做双向数据同步, 实现容灾切换需求
中间件:
RPC: 对于SET服务, 调用封闭在SET内; 对于非SET服务, 沿用现有路由逻辑
KV: 支持分SET的数据生产和查询
MQ: 支持分SET的消息生产和消费
数据同步:
全局数据(数据量小且变化不大, 比如商家菜品数据)部署在中心集群, 其他单元化集群, 同步全局数据到本单元内
未来演变为异地多活架构时, 各单元集群数据需要进行双向同步来实现容灾需求
异地容灾:
通过SET化架构的流量调度能力, 将SET分别部署在不同地区的数据中心, 实现跨地区容灾支持
高效本地化服务:
利用前端位置信息采集和域名解析策略, 将流量路由到最近的SET, 提供最高效的本地化服务
集装箱式扩展:
SET的封装性支持更灵活的部署扩展性, 比如SET一键创建/下线, 一键发布
SET化架构原则:
对业务透明原则:
SET化架构的实现对业务代码透明, 业务代码层面不需要关心SET化规则, SET的部署等问题
切分规则:
理论上, 切分规则由业务层面按需订制
实现上, 建议优先选最大的业务维度进行切分
比如海量用户的O2O业务, 按用户位置信息进行切分. 此外, 接入层, 逻辑层和数据层可以有独立的SET切分规则, 有利于实现部署和运维成本的最优化
部署规则:
一个SET并不一定只限制在一个机房, 也可以跨机房或者跨地区部署, 为保证灵活性, 单个SET内机器数不宜过多
支持消息高性能的序列化转换, 异步化发送消息
支持消息生产实例与消费实例的链接池化缓存化, 提升性能
支持可靠性投递消息, 保障消息的100%不丢失
支持消费端的幂等操作, 避免消息端重复消费的问题
支持迅速消息发送模式, 在一些日志收集/统计分析等需求下可以保证高性能, 超高吞吐量
支持延迟消息模式, 消息可以延迟发送, 指定延迟时间, 用于某些延迟检查, 服务限流场景
支持事物消息, 且100%保障可靠性投递, 在金融行业单笔打击呢操作时会有此类需求
支持顺序消息, 保证消息送达消费端的前后顺序, 例如下单等复合操作
支持消息补偿, 重试, 以及快速定位异常/失败消息
支持集群消息负载均衡, 保障消息落到具体SET集群的负载均衡
支持消息路由策略, 指定某些消息路由到指定的SET集群
延迟插件