RabbitMQ(幂等性/顺序性/可靠性)
2021-02-06 15:46:51 61 举报
AI智能生成
RabbitMQ
作者其他创作
大纲/内容
RabbitMQ是一款开源的,使用Erlang语言编写的,基于AMQP协议的消息中间件
基本概念
特点
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、 安全
AMQP协议对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次
常用组件
Connection
连接,应用程序与Server的网络连接,TCP连接
Channel
信道,消息读写等操作在信道中进行
Message
消息,应用程序和服务器之间传送的数据
Virtual Host
虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange和Queue
Exchange
交换器,接收消息,按照路由规则将消息路由到一个或者多个队列
Binding
绑定,交换器和消息队列之间的虚拟连接,绑定中可以包含一个或者多个RoutingKey
RoutingKey
路由键,生产者将消息发送给交换器时会发一个RoutingKey,用来指定路由规则
Queue
消息队列,用来保存消息,供消费者消费
Broker
标识消息队列服务器实体
交换器类型
Direct Exchange
完全匹配,消息中的路由键(routing key)和Binding中的binding key一致
Topic Exchange
模糊匹配,两个通配符:"#"和"*",#匹配0个或多个单词,*只匹配一个单词
Fanout Exchange
广播模式,不处理路由键,把所有发送到交换器的消息路由到所有绑定的队列中
Headers Exchange
忽略路由规则,根据消息中的headers属性来匹配,性能较低(不常用)
MQ使用场
景及优缺点
景及优缺点
优点
解耦(最终一致性)
异步(提升效率)
削峰(量力而行)
限流
RabbitMQ提供了一种qos(服务质量保证)功能。即在非自动确认消息
的前提下,如果一定数目的消息未被确认前,不进行消费新的消息
的前提下,如果一定数目的消息未被确认前,不进行消费新的消息
缺点
系统的可用性降低
引入外部依赖越多,系统越容易挂掉MQ挂了,
也会导致整个系统不可用
也会导致整个系统不可用
系统的复杂性提高
如何保证消息没有重复消费?
幂等性
如何保证消息传递的顺序?
顺序性
如何保证消息不丢失?
可靠性
数据一致性的问题
A系统发送完消息直接返回成功,但是BCD系统之
中若有系统写库失败,则会产生数据不一致的问题
中若有系统写库失败,则会产生数据不一致的问题
幂等性
使用全局唯一ID+指纹码(全局唯一ID:雪花算法生成的业务表的主键。指纹码:时间戳、UUID、订单号)
并发量不高的情况下可以在数据库维护一张消费记录表,并发量很高可将全局ID写入redis,利用其原子操作setnx
接收到消息后执行setnx,如果执行成功则表示没有处理过,可以消费,相反如果执行失败就表示该消息已经被消费了
顺序性
在 MQ 里面创建多个queue,使用hash算法将需要排序的数据有顺序的放入同一个queue,每个queue对应一个consumer
或者就一个queue,对应一个consumer,这个consumer内部用内存队列排队,然后分发给不同的worker来处理
可靠性
消息丢失场景
生产者发送消息到MQ
网络原因
代码/配置
MQ中存储的消息丢失
消息未完全持久化
消费者从MQ拉取消息
消费端接收到相关消息之后,消费端还没
来得及处理消息,消费端机器就宕机了
来得及处理消息,消费端机器就宕机了
如何避免
消息丢失
消息丢失
生产者丢消息
事务机制(基于AMQP协议)
吞吐量下降(同步),不推荐
confirm机制(生产者确认机制)
异步回调,效率高
MQ丢消息
开启RabbitMQ持久化
创建queue时设置持久化
发送消息时设置持久化
使用镜像集群
模式保证高可用
模式保证高可用
rabbitmq有很好的管理控制台,在后台新增一个镜像集群模式的策略
指定同步节点的时候要求数据同步到所有节点(性能受极大影响)
镜像策略:指定最多同步N台机器、只同步到符合指定名称的机器
镜像策略:指定最多同步N台机器、只同步到符合指定名称的机器
再次创建queue的时候应用这个策略就会自动将数据同步到其他的节点上
消费者丢消息
关闭消费者的自动ack机制,采用手动ack形式
消费者处理完消息后手动ack通知MQ删除消息
常见问题
死信队列(DLX)
消息变成死信的原因
消息被拒绝(basic.reject/ basic.nack)并且不再重新投递 requeue=false
TTL(time-to-live) 消息超时未消费
队列达到最大长度
死信队列的设置
提前设置好死信队列的 exchange 和 queue,然后进行绑定
在普通队列上加一个参数: argument.put("x-dead-letter-exchange", "dlx.exchange");
这样消息在过期或者队列达到最大长度时,消息就会直接路由到死信队列
延时队列怎么实现?
不推荐
使用定时任务
非常浪费服务器性能,不建议
使用Java自带的delayQueue
这种实现方式是数据保存在内存中,可能面临数据丢失的情况
无法支持分布式系统,不能做集群化处理且不易维护
推荐
使用rabbitmq的消息过期时间(TTL)和死信队列(DLX)来模拟出延时队列
还可以用RabbitMQ的插件 rabbitmq-delayed-message-exchange 插件来实现延时队列
达到可投递时间时并将其通过 x-delayed-type 类型标记的交换机类型投递至目标队列
达到可投递时间时并将其通过 x-delayed-type 类型标记的交换机类型投递至目标队列
重复排队怎么解决?
利用redis的原子递增来实现,使用用户名作为key,每次递增1,返回值大于1则抛异常
0 条评论
下一页