九.RabbitMQ

RabbitMQ的Broker、Cluster、vhost

  1. Broker:是指一个或多个node的逻辑分组,且node上运行着RbbitMQ应用程序
  2. Cluster:在Broker基础上,增加了node直接共享元数据的约束
  3. vhost:虚拟Broker,其内部均含有独立的queue、exchange和binding,最重要的是其拥有独立的权限系统,可以做到vhost范围的用户控制

元数据

在非Cluster模式下,元数据主要分为:

  1. Queue元数据:queue名字和属性等
  2. Exchange元数据:exchange名字、类型和属性
  3. Binding元数据:存放路由关系的查找表
  4. Vhost元数据:vhot范围内针对前三者的名字空间约束和安全属性设置

channel、exchange和queue是什么

  1. queue具有自己的进程
  2. exchange内部实现为保存binding关系的查找表
  3. channel是实际进行路由工作的实体,即负责按照routing_key将message投递给queue

由AMQP协议可知,channel是真实TCP连接之上的虚拟连接,所有的AMQP命令都是通过channel发送的,切每一个channel有唯一的ID

一个channel只能被单独一个操作系统线程使用,故投递在特定channel上的message是有顺序的,但一个操作系统线程允许使用多个channel

消息时基于什么传输

由于TCP连接的创建和销毁开销交大,且并发数受系统资源限制,会造成瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP链接内的虚拟连接,且每条TCP连接时的信道数量没有限制

单node节点和多node节点构成的Cluster声明queue、exchange,以及binding有什么不同

单node上声明queue时,只要该node上相关的元数据进行更改,就会得到Queue.Declare-ok回应;而cluster上声明,则需全部node都进行元数据更新后才会得到

blackholed问题

blackholed问题是指,向exchange投递了message,而由于各种原因导致该message丢失,但发送者却不知道,可导致blackholed的情况:

  1. 向未绑定queue的exchange发送message
  2. exchange以binding_key key绑定queue,但向exchange发送message使用的routing_key是不同的key

消息怎么路由

消息路由必须有三部分:交换机、路由、绑定

  1. 生产者把消息发布到交换机上
  2. 绑定决定了消息如何从路由机路由到 特定的队列
  3. 消息最终到达队列,被消费者接受

详细来讲:

  1. 消息发布到交换机时,消息将拥有一个路由键,在消息创建时设定
  2. 通过队列路由键,可以把队列绑定到交换机上
  3. 消息到达交换机后,rabbitmq会将消息的路由键与队列的路由键进行匹配(针对不同的交换机有不同的路由规则)。如果能够匹配到队列,则消息会投递到相应队列中;如果不能匹配任何队列,消息将进入黑洞

常见的交换机类型:

  1. direct:路由键完全匹配
  2. fanout:广播到所有绑定队列
  3. topic:可以使用来自不同源头的消息能够到达同一个队列。使用topic交换机时,可以使用通配符

如何保证消息正确的发送至RabbitMQ

发送方确认模式

  1. 发送方确认模式: 将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。一旦消息被投递到目的队列后,或者信息被写入磁盘后,信道会发送一个确认给生产者(包含消息唯一ID)。如果RabbitMQ发送内部错误从而导致消息丢失,会发送一条nack(未确认)消息
  2. 发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者引用陈谷的回调方法就会被触发来处理确认消息

如何保证消息接收方消费了消息

接收方消息确认机制: 消费者接受到每一条消息后都必须进行确认(消息接受和消息确认是两个不同操作)。只有消费者确认了消息,rabbitmq才能安全的把消息从队列中删除

存在的特殊情况:

  1. 如果消费者接受到消息,在确认之前断开了连接或取消订阅,rabbitmq会认为消息没有被分发,然后重新分发给下一个订阅的消费者。此时存在消息重复消费,则需要根据bizid去重
  2. 如果消费者接收到消息却没有确认消息,连接也未断开,则rabbitmq认为该消费者繁忙,将不会给该消费者分发更多的消息

如何避免消息重复投递或重复消费

在消息生成时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列

在消息消费时,要求消息体重必须要有一个bizid作为去重和幂等的依据,避免同一条消息被重复消费

为什么不对所有的message使用持久化机制

写入磁盘比写RAM慢,导致性能下降,吞吐量可能降低10倍

如何保证消息不丢失

消息持久化的前提是:将交换机/队列的durable属性设置为true,表示交换机/队列是持久交换机/队列,在服务器崩溃或重启之后不需要重新创建交换机/队列

如果消息想要从崩溃中恢复,那么消息必须:

  1. 在消息发布前,通过把它的投递模式选项设置为2(持久),来吧消息标记成持久化
  2. 将消息发送到持久交换机
  3. 消息到达持久队列

恢复方式:将它们写入磁盘的一个持久化日志文件:

  1. 当发布一条持久性消息到持久交换机上,rabbitmq会在消息提交到日志文件后才发送响应(如果消息路由到了非持久队列,它会自动从持久化日志中移除)
  2. 一旦消费者从持久队列中消费了一条持久化消息,rabbitmq会在持久化日志中把这条记录标记为等待垃圾收集。如果持久化消息在被消费之前重启,那么rabbitmq会自动重建交换机和队列,并重播持久化日志文件中的消息到合适的队列或者交换机上

死信队列

Dead-Letter-Exchange。当消息在一个队列中变成死信之后,它能被重新publish到另一个Exchange,消息变成死信有几种情况:

  1. 消息被拒绝,并且requeue=false
  2. 消息TTL过期
  3. 队列达到最大长度

用途:延迟消息

Cluster、mirrored queue以及warrens机制分别解决了什么问题?

  1. Cluster:
    1. 解决当cluster中任意node失效后,生产者和消费者均可以通过其他node继续工作,提高了可用性;另外可以通过增加node数量增加cluster的消息吞吐量
    2. 本身不负责message的可靠性问题(需由生产者自行解决);cluster无法解决跨数据中心的问题
    3. 可以通过HAProxy解决node选择问题,业务不需知道cluster中多个node的ip,利用HAProxy做负载

  2. Mirrored queue
    1. 解决使用cluster时创建的queue的完整信息仅存在于单一node上的问题
    2. 若想正确使用:
    消费者需提供consumer cancellation notification机制
    消费者必须能够正确处理重复message

  3. Warrens
    解决cluster中message可能被blackholed的问题,即不能接受生产者不听的republish message,但mq服务无回应的情况:

如何实现个高可用?

单机模式
普通集群模式
镜像集群模式

  1. 单机模式:单台服务器启动的节点
  2. 普通集群模式:多台机器人启动多个mq实例
    1. 创建的queue只会放在一个mq实例上,但每个实例都同步queue元数据
    2. 消费的时候,实际上如果镰刀另一个实例,那么那个实例会从queue所在实例拉数据过来
    3. 缺点:MQ集群内部可能产生大量的数据传输;可用性无保障,如果queue所在节点宕机,数据就丢失了
  3. 镜像集群模式(高可用)
    创建的queue,无论元数据还是queue里的消息都会存在多个实力上,每个mq节点都包含这个queue的全部数据。每次写消息到queue都会自动把消息同步到多个实例的queue上

好处:任何一个几点宕机,可以从其他节点获取数据
坏处:性能开销交大,需同步所有机器;不是分布式,没有扩展性

RabbitMQ丢失数据

三种情况:

  1. 生产者向mq发送消息的过程中丢失了
    解决方案:
    1. 事务:生产者发送数据之前开启事务 channel.txSelect,然后发送消息
    缺点:由于事务机制,吞吐量会降低
    2. confirm功能:生产者开启confirm功能,每次写入消息会分配一个唯一的id;如果写入mq,mq会回传一个ack消息,表示接收到了;如果mq没能处理这个消息会回调一个nack接口,告诉你消息失败了,可以尝试重新发送

  2. 生产者向mq发送消息,mq接收到消息,暂存在内存中还没消费,挂掉了
    解决方案:
    Broker丢失了数据,此时需要开启持久化,设置持久化的两个步骤:
    1. 创建queue的时候将其设置为持久化
    2. 第二个是发送消息的时候将消息的deliveryMode设置为2,就是将消息设置为持久化,此时mq会将消息持久化到磁盘上

  3. mq向消费者发送消息,消费者还未处理,挂掉了
    解决方案:
    关闭mq自动的ack,采用手动的ack形式,可以通过一个api来调用。

RabbitMQ消费消息的顺序性

一个queue里,相同的key交给同一个worker来执行。单条信息ack。前提是一个queue只能对应一个consumer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值