RabbitMQ进阶基础2
AMQP?
RabbitMQ是基于AMQP协议的Erlang的实现的,那么什么是AMQP协议。
AMQP协议的三层:
- Module Layer:协议最高层,主要定义了一些客户端调用的命令,客户端可以用这些命令实现自己的业务逻辑
- Session Layer:中间层,主要负责客户端命令发送给服务器,再将服务端应答返回客户端,提供可靠性同步机制和错误处理。
- TransportLayer:最底层,主要传输二进制数据流,提供帧的处理、信道复用、错误检测和数据表示等。
AMQP模型的三大组件:
- 交换器(Exchange):消息代理服务器中用于把消息路由到队列的组件。
- 队列(Queue):用来存储消息的数据结构,位于硬盘或内存中。
- 绑定(Binding):一套规则,告知交换器消息应该将消息传递给哪个队列。
生产者Producer和消费者Consumer?
生产者
- 消息生产者,就是投递消息的一方
- 消息一般包含两个部分:消息体(payload)和标签(Label)
消费者
- 消费消息,也就是接受消息的一方
- 消费者连接到RabbitMQ服务器,并订阅到队列上。消费消息时只消费消息体,丢弃标签。
Broker服务节点、Queue队列、Exchange交换器?
- Broker:可以看做RabbitMQ的服务节点。一般情况下一个Broker可以看做一个RabbitMQ服务器。
- Queue:RabbitMQ的内部对象,用于存储消息。多个消费者可以订阅同一队列,这时队列中的消息会被平摊(轮询)给多个消费者进行处理。
- Exchange: 生产者将消息发送到交换器,由交换器将消息路由到一个或者多个队列中。当路由不到时,或返回给生产者或直接丢弃。
什么是死信队列?如何导致的?
DLX,全称Dead-Letter-Exchange, 死信交换器。当消息在一个队列中变成死信之后,它能被重新被发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就被称之为死信队列。
导致死信的几种原因:
- 消息被拒(Bacis.Reject /Basic.Nack) 且 requeue=false。
- 消息TTL过期
- 队列满了,无法再添加
什么是延迟队列?RabbitMQ怎么实现延迟队列?
延迟队列指的是存储对应的延迟消息,消息被发送以后,并不想消费者立刻拿到消息,而是等待特定的消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
RabbitMQ本身是没有延迟队列的,要实现延迟消息,一般有两种方式:
- 通过RabbitMQ本身队列的特性来实现,需要使用RabbitMQ的死信交换机(Exchange)和消息的存活时间TTL(Time To Live)。
- 在RabbitMQ 3.5.7 及以上的版本提供了一个插件(rabbitmq-delayed-message-exchange) 来实现延迟队列功能。同时,插件依赖Erlang/OPT 18.0及以上。
什么是优先级队列?
RabbitMQ自V3.5.0 有优先级队列实现,优先级高的队列会先被消费。
可通过x-max-priority参数来实现优先级队列。
RabbitMQ有哪些工作模式?
- 简单模式
- work工作模式
- pub/sub发布订阅模式
- Routing路由模式
- Topic主题模式
RabbitMQ消息怎么传输?
由于TCP链接的创建和销毁开销较大,且并发数受系统资源限制,存在性能瓶颈,所以RabbitMQ使用信道的方式来传输数据。信道(Channel)是生产者、消费者与RabbitMQ通信的渠道,信道是建议再TCP链接上的虚拟链接,且每条TCP链接上的信道数量没有限制。就是说RabbitMQ在一条TCPL链接上简历成百上千个信道来得到多个线程处理,这个TCP被多个线程共享,每个信道在RabbitMQ都有唯一的ID,保证了信道私有性,每个信道对应一个线程使用。
如何保证消息的可靠性?
消息到MQ的过程中搞丢,MQ自己搞丢,MQ到消费过程中搞丢。
- 生产者到RabbitMQ:事务机制和Confirm机制,注意:事务机制和Confirm机制是互斥的,两者不能共存,会导致RabbitMQ报错。
- RabbitMQ自身:持久化、集群、普通模式、镜像模式。
- RabbitMQ到消费者:basicAck机制、死信队列、消息补偿机制。
如何保证RabbitMQ消息的顺序性?
- 拆分多个Queue(消息队列),每个Queue(消息队列)一个consumer(消费者),就是多一些Queue(消息队列)而已,确实是麻烦点
- 就一个Queue(消息队列),但是对应一个consumer(消费者),然后这个consumer(消费者)内部用内存队列做排队,然后分发给底层不同的worker来处理。
RabbitMQ 是比较有代表性的,因为是基于主从(非分布式)做高可用性的,我们就以 RabbitMQ 为例子讲解第一种 MQ 的高可用性怎么实现。RabbitMQ 有三种模式:单机模式、普通集群模式、镜像集群模式。
单机模式
Demo 级别的,一般就是你本地启动了玩玩儿的?,没人生产用单机模式。
普通集群模式
意思就是在多台机器上启动多个 RabbitMQ 实例,每个机器启动一个。你创建的 queue,只会放在一个 RabbitMQ 实例上,但是每个实例都同步 queue 的元数据(元数据可以认为是 queue 的一些配置信息,通过元数据,可以找到 queue 所在实例)。
你消费的时候,实际上如果连接到了另外一个实例,那么那个实例会从 queue 所在实例上拉取数据过来。这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。
镜像集群模式
这种模式,才是所谓的 RabbitMQ 的高可用模式。跟普通集群模式不一样的是,在镜像集群模式下,你创建的 queue,无论元数据还是 queue 里的消息都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。RabbitMQ 有很好的管理控制台,就是在后台新增一个策略,这个策略是镜像集群模式的策略,指定的时候是可以要求数据同步到所有节点的,也可以要求同步到指定数量的节点,再次创建 queue 的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。
这样的好处在于,你任何一个机器宕机了,没事儿,其它机器(节点)还包含了这个 queue 的完整数据,别的 consumer 都可以到其它节点上去消费数据。坏处在于,第一,这个性能开销也太大了吧,消息需要同步到所有机器上,导致网络带宽压力和消耗很重!RabbitMQ 一个 queue 的数据都是放在一个节点里的,镜像集群下,也是每个节点都放这个 queue 的完整数据。
RabbtiMQ 是可以设置过期时间的,也就是 TTL。如果消息在 queue 中积压超过一定的时间就会被 RabbitMQ 给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在 mq 里,而是大量的数据会直接搞丢。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上 12 点以后,用户都睡觉了。这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入 mq 里面去,把白天丢的数据给他补回来。也只能是这样了。假设 1 万个订单积压在 mq 里面,没有处理,其中 1000 个订单都丢了,你只能手动写程序把那 1000 个订单给查出来,手动发到 mq 里去再补一次。
// todo 需要多看几遍
- 点赞
- 收藏
- 关注作者
评论(0)