消息中间件-RabbitMQ

448 阅读9分钟

1.消息中间件使用场景

消息中间件使用的场景有很多,但主要的场景是:异步、解耦、消峰填谷。

2.消息中间件的优缺点

异步、解耦、消峰填谷这是消息中间件最大的优点,除了这些消息中间件还可以解决一些我们特殊业务场景的问题。

缺点主要在于系统的可用性、复杂性、一致性问题,引入消息中间件后,需要考虑中间件的可用性,而且复杂性明显提高了,需要考虑消息重复,顺序消费等问题。

3.RabbitMQ是什么

RabbitMQ 是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种 客户端。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性 等方面表现不俗。

4.RabbitMQ特点

  • 可靠性
  • 高可用
  • 多语言客户端
  • 消息集群
  • 多种协议
  • 插件机制
  • 跟踪机制
  • 灵活的路由

5.RabbitMQ安装与运行

去官方文档下载rabbitmq:

www.rabbitmq.com/download.ht…

按照官网的步骤下载文件并进行安装

启动RabbitMQ服务命令: sudo systemctl start rabbitmq-server

查看状态: sudo systemctl status rabbitmq-server

设置为开机启动: sudo systemctl enable rabbitmq-server

6.RabbitMQ角色

administrator

policymaker和monitoring可以做的任何事外加:

  • 创建和删除virtual hosts
  • 查看、创建和删除users
  • 查看创建和删除permissions
  • 关闭其他用户的connections

none

不能访问 management plugin

management

用户可以通过AMQP做的任何事外加:

  • 列出自己可以通过AMQP登入的virtual hosts
  • 查看自己的virtual hosts中的queues, exchanges 和 bindings
  • 查看和关闭自己的channels 和 connections
  • 查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual hosts中的活动

policymaker

management可以做的任何事外加:

  • 查看、创建和删除自己的virtual hosts所属的policies和parameters

monitoring

management可以做的任何事外加:

  • 列出所有virtual hosts,包括他们不能登录的virtual hosts
  • 查看其他用户的connections和channels
  • 查看节点级别的数据如clustering和memory使用情况
  • 查看真正的关于所有virtual hosts的全局的统计信息

7.AMQP协议

AMQP(Advanced Message Queuing Protocol)高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计

8.RabbitMQ核心概念

rabbitmq.png

Producer 生产者,就是投递消息的一方。生产者创建消息,然后发布到RabbitMQ中

消息一般可以包含两个部分:消息体和附加信息。

消息体:在实际应用中,消息体一般是一个带有业务逻辑结构的数据,比如一个JSON字符串。当然可以进 一步对这个消息体进行序列化操作。

附加信息:用来表述这条消息,比如目标交换器的名称、路由键和一些自定义属性 等等

Consumer: 消费者,就是接收消息的一方,消费者连接到RabbitMQ服务器,并订阅到队列上。

Broker:消息中间件的服务节点

对于RabbitMQ来说, 一个RabbitMQ Broker可以简单地看作一个RabbitMQ服务节点,或者 RabbitMQ服务实例, 也可以将一个RabbitMQ Broker看作一台RabbitMQ服务器

Virtual Host: 虚拟主机表示一批交换器、消息队列和相关对象, 虚拟主机是共享相同的身份认证和加密环境的独立服务器域.

每个vhost本质上就是一个mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。

Channel:频道或信道,是建立在Connection连接之上的一种轻量级的连接

大部分的操作是在Channel这个接口中完成的,包括定义队列的声明queueDeclare、交换机的声明 exchangeDeclare、队列的绑定queueBind、发布消息basicPublish、消费消息basicConsume等

RoutingKey:路由键, 生产者将消息发给交换器的时候,一般会指定一个 RoutingKey,用来指定这个消息的路由规则。

在交换器类型和绑定键 (BindingKey) 固定的情况下,生产者可以在发送消息给交换器时,通过 指定 RoutingKey 来决定消息流向哪里。

Exchange:交换器,生产者将消息发送到 Exchange, 由交换器将消息路由到一个或者多个队列中。如果路由不到,或返回给生产者,或直接丢弃。

rabittmq架构.png

Exchange类型 RabbitMQ常用的交换器类型有fanout,direct,topic,headers四种

fanout:扇形交换机,它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中 direct:直连交换机,它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中 topic:主题交换机,与direct类似,但它可以通过通配符进行模糊匹配 headers:头交换机,不依赖路由键的匹配规则来路由信息,而是根据发送的消息内容中的headers属性进行匹配,headers类型交换机性能很差,不推荐使用

Queue:队列,是RabbitMQ的内部对象,用于存储消息

Binding:绑定,RabbitMQ中通过绑定将交换器与队列关联起来,在绑定的时候一般会指定一个绑定键值,这样RabbitMQ就知道如何正确地将消息路由到队列了。

9.RabbitMQ发送消息过程

MQ发送消息的过程.png

生产者发送消息的过程

  1. 生产者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
  2. 生产者声明一个交换器,并设置相关属性,比如交换机类型,是否持久化等
  3. 生产者声明一个队列并设置相关属性,比如是否排他,是否持久化,是否自动删除等
  4. 生产者通过路由键将交换器和队列绑定起来
  5. 生产者发送消息至RabbitMQ Broker,包括路由键和交换器等信息
  6. 相应的交换器根据接收到的路由键查找匹配的队列
  7. 如果找到,则将生产者发送的消息存入队列中
  8. 如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者
  9. 关闭信道,关闭连接

消费者接收消息的过程

  1. 消费者连接到RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
  2. 消费者向RabbitMQ Broker请求相应队列中的消息,可能会设置相应的回调函数
  3. 等待RabbitMQ Broker回应并投递相应队列中的消息,消费者开始接收消息
  4. 消费者确认ACK接收到的消息
  5. RabbitMQ对队列中删除相应已经被确认的消息
  6. 关闭信道,关闭连接

10.RabbitMQ常见的问题

  • 1.如何保证消息不重复消费 通过消费者端做幂等,消费者端通过msgId来做消息去重

  • 2.如何保证消息的顺序性
    一个消费者,一个queue,一个线程去消费一个queue中的消息

  • 3.消息积压怎么解决

    • 先修复consumer的问题,确保其恢复消费速度,然后将现有consumer都停掉
    • 新建一个topic,partition是原来的10倍,临时建立好原来10倍或者20倍的queue数量
    • 写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
    • 接着临时用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
    • 这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据,提高消费者的消费能力
    • 等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
  • 4.订单超时问题 1. 死信队列 2.定时任务做业务补偿

  • 5.可靠性

    • 1.事务
    • 2.开启confirm确认机制
    • 3.开启持久化
    • 4.使用手动ACK

11.如何保证高可用性

RabbitMQ有三种模式: 单机模式,普通集群模式,镜像集群模式

(1)单机模式

单机模式一般在开发或者测试场景,生产上基本不用单机模式,风险很大。

(2)普通集群模式

普通集群模式就是启动多个RabbitMQ实例,在你创建的queue,只会放在一个rabbtimq实例上,但是每个实例都同步queue的元数据。在消费完成以后,如果连接到了另外一个实例,那么那个实例会从queue所在实例上拉取数据过来。

如果存储queue的实例宕机了,会导致其他实例无法从那个之前那个实例拉取,如果你开启了消息持久化,让RabbitMQ落地存储消息的话,消息不一定会丢,等到这个实例恢复了,然后才可以继续从这个queue拉取数据。这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个queue的读写操作

(3)镜像集群模式

镜像集群模式是所谓的RabbitMQ的高可用模式,跟普通集群模式不一样的是,你创建的queue,无论元数据还是queue里的消息都会存在于多个实例上,然后每次你写消息到queue的时候,都会自动把消息到多个实例的queue里进行消息同步。

优点在于你任何一个实例宕机了,其他实例都可以用。

缺点在于性能开销太大和扩展性很低,同步所有实例,这会导致网络带宽和压力很大,而且扩展性很低,每增加一个实例都会去包含已有的queue的所有数据,并没有办法线性扩展queue。

开启镜像集群模式可以去RabbitMQ的管理控制台去增加一个策略,指定要求数据同步到所有节点的,也可以要求就同步到指定数量的节点,然后你再次创建queue的时候,应用这个策略,就会自动将数据同步到其他的节点上去了。