0%

RabbitMQ学习记录

https://cloud.tencent.com/developer/article/2113802

什么是消息队列

消息队列是在消息传输过程中保存消息的容器。 通常有生产者和消费者两个角色:

  • 生产者只负责发送数据到消息队列,谁消费他不管
  • 消费者只负责从消息队列中取数据处理,谁发送数据他不管

常见消息队列中间件

  • Kafka 高吞吐量实时日志采集
  • RabbitMQ Erlang语言, 灵活性和易用性,中小规模应用
  • RocketMQ 阿里出品, Java开发, 国内市场有很高知名度和应用案例

为什么使用消息队列

  1. 服务解耦: 通过消息队列, 生产者和消费者之间可以不依赖对方进行通信。 即使某个组件失败,也不影响其他组件,提升可靠性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    +------------------+          +------------------+         +------------------+
    | Producer 1 | | Producer 2 | | Producer N |
    +--------+---------+ +--------+---------+ +--------+---------+
    | | |
    v v v
    +------------------------------------------------------------------------------+
    | (Message Queue) |
    +------------------------------------------------------------------------------+
    | | |
    v v v
    +--------+---------+ +--------+---------+ +------------------+
    | Consumer 1 | | Consumer 2 | | Consumer M |
    +------------------+ +------------------+ +------------------+
  2. 异步处理: 生产者将请求发送到队列,无需等待请求处理(例如:用户注册发送短信验证码)。 减少响应时间,提升性能和用户体验。

    1
    2
    3
    4
    5
    6
                                                                         /----------------> System B(200ms)
    Request /
    client -------------------> System A(30ms) --------> Message Queue ------------------> System C(300ms)
    <------------------- \
    Response \----------------> System D(250ms)

  3. 流量削峰: 面对高并发请求,通过消息队列缓冲请求,避免系统过载。 确保系统在高峰期稳定运行

    1
    2
    3
            10k requests/s                       consume 2k requests/s
    User --------------------> Message Queue --------------------------> System A --------------------> MySQL

消息队列的劣势

  • 系统可用性降低,如果MQ挂了,整个系统就崩了
  • 系统复杂性增加, 需要考虑消息队列自身的可用性问题,例如:
    • 如何保证消息不被重复消费
    • 如何保证消息可靠传输
    • 如何保证数据一致性
    • 如何解决消息积压导致的故障

不适用消息队列的场景

  • 对于简单的,快速执行的任务,直接调用API更为直接高效
  • 需要立即确认结果的交互

RabbitMQ简介

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件。RabbitMQ服务器是用Erlang语言编写的

AMQP是什么

Module Layer: 协议最高层,主要定义了一些客户端调用的命令,客户端可以用这些命令实现自己的业务逻辑。
Session Layer: 中间层,主要负责客户端命令发送给服务器,再将服务端应答返回客户端,提供可靠性同步机制和错误处理。
TransportLayer: 最底层,主要传输二进制数据流,提供帧的处理、信道服用、错误检测和数据表示等。

RabbitMQ的几个概念

  • Broker, RabbitMQ的服务节点,一个broker可以看做一个RabbitMQ服务器
  • Exchange(交换机), 生产者把消息发送到交换机, 交换机负责把消息路由到队列中
  • Queue(队列), 用于存储消息。 多个消费者可以订阅同一个队列,此时队列消息会平摊(Round-Robin)给多个消费者处理

RoutingKey的概念

生产者将消息发送给交换机时,需要指定一个RoutingKey, 用于指定消息的路由规则。

Binding

通过绑定将交换机和队列关联起来

RabbitMQ交换机的概念,为什么设计

RabbitMQ中的消息不是直接发送到队列,而是发送到交换机,由交换机发送到队列

RabbitMQ交换机的几种类型

  • fanout 把消息路由到所有与交换机绑定的队列中
  • direct 消息路由到BindingKey和RoutingKey完全匹配的队列中
  • topic
    • RoutingKey为一个点号分隔的字符串
    • BindingKey也是一个点号分隔的字符串, 可以使用*和#作模糊匹配, *匹配一个单词, #匹配0个或多个
  • headers 不常用

生产者发送消息流程

  • 生产者连接到Broker, 建立连接, 开启一个信道(channel)
  • 声明一个交换机
  • 声明一些队列
  • 通过路由键将交换机和队列绑定起来
  • 生产者发送消息到Broker, 其中包含路由键(Routing Key), 交换机等信息
  • 交换机根据路由键查找匹配队列,将消息存入响应队列
  • RabbitMQ收到确认,从队列中删除已确认的消息
  • 关闭信道和连接

消费者接受消息

  • 消费者连接到Broker,建立连接,开启一个信道(channel)
  • 向Broker请求消费队列中的消息, 设置回调函数
  • 等待Broker回应,接收信息, 确认收到的消息
  • RabbitMQ收到确认,从队列中删除已确认的消息
  • 关闭信道和连接

交换机无法找到队列时,怎么处理

  • mandatory: true, 返回消息给生产者
  • mandatory: false, 直接丢弃

死信队列是什么

[TODO] 为什么设计?

  • 当消息在一个队列中变成dead message之后,可以被重新发送到另一个交换机中,这个交换机就是DLX(Dead-Letter-Exchange)
  • 绑定DLX的队列就称为死信队列

导致dead message的原因

  • 消息被拒
  • 消息TTL过期
  • 队列满了,无法添加

延迟队列

TODO: 为什么设计
当消息发送之后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费

优先级队列

优先级高的先消费,通过x-max-priority实现,当消费速度比较快,没有消息堆积情况下,这个优先级队列意义不大。

事物机制

RabbitMQ客户端中与事务机制相关方法:

  • channel.txSelect 用于将当前信道设置为事务模式
  • channel.txCommit 提交事务
  • channel.txRollback 事务回滚,如果事务提交执行前抛出异常,通过txRollback回滚

发送确认机制

生产者把信道设置为confirm模式后,所有在此channel发布消息会被指定一个唯一ID,
一旦消息被投递到所有匹配队列之后,RabbitMQ就会发送一个确认给生产者,这样生产者就知道消息到达对应的目的地了

消息传输保证的层级

  • At most once 最多一次,消息可能会丢失,但不会重复传输
  • At least once 最少一次,信息不会丢失,但可能重复传输
  • Exactly once 恰好一次,消息仅传输一次

Virtual Host概念

每个RabbitMQ服务器都能创建虚拟的服务器,也叫虚拟主机(vhost)

集群中的节点类型

  • 内存节点: ram, 将变更写入内存
  • 磁盘节点: disc, 磁盘写入操作
    RabbitMQ要求最少有一个磁盘节点

生产者如何将消息可靠投递到MQ

  • Client发送消息给MQ
  • MQ将消息持久化后, 发送Ack消息给Client, 如果说因为网络问题导致Ack无法发送到Client, Client在等待超时后会重传消息
  • Client收到ACK后,可以认为消息投递成功

MQ如何把消息可靠投递到消费者

  • 消费者收到消息执行业务逻辑
  • 发送Ack消息给MQ,通知MQ删除该消息, 此处可能因为网络问题导致ACK失败,导致重复消费,引出消费幂等问题
  • MQ将已消费消息删除

RabbitMQ的高可用

  • 单机模式 —— demo, 玩具, 生产环境很少用单机
  • 普通集群模式 —— 多台机器启动多个RabbitMQ示例
  • 镜像集群模式 —— 高可用模式, 创建的Queue,消息会存在与多个实例上,每次写消息到Queue时,自动把消息到多个实例的Queue进行消息同步

如何保证消息的顺序性

  • 拆分多个Queue, 每个Queue对应一个Consumer

如何保证消息的可靠性

  • 生产者到RabbitMQ: Confirm机制
  • RabbitMQ自身: 持久化(交换机和队列), 集群, 普通模式, 镜像模式 (TODO)
  • RabbitMQ到消费者: basicAck机制, 死信队列, 消息补偿机制

https://cloud.tencent.com/developer/article/2093640