RabbitMQ:从入门到搞定面试官

安装

使用docker安装,注意要安装tag后缀为management的镜像(包含web管理插件),我这里使用的是rabbitmq:3.8-management

1、 拉取镜像

docker pull rabbitmq:3.8-management

2、 启动容器

docker run --name rabbitmq --hostname rabbitmq -d -p 15672:15672 -p 5672:5672 rabbitmq:3.8-management

3、 访问web管理页面

http://127.0.0.1:15672/

概念介绍

组件概念

  • Broker:简单来说就是消息队列服务器实体。
  • Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
  • Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
  • Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
  • Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
  • vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
  • producer:消息生产者,就是投递消息的程序。
  • consumer:消息消费者,就是接受消息的程序。
  • channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

6种消息模式和4种交换机

消息模式:

  • Simple Work Queue (简单工作队列):也就是常说的点对点模式,一条消息由一个消费者进行消费。(当有多个消费者时,默认使用轮训机制把消息分配给消费者)。
  • Work Queues (工作队列):也叫公平队列,能者多劳的消息队列模型。队列必须接收到来自消费者的手动ack才可以继续往消费者发送消息。
  • Publish/Subscribe (发布订阅模式):一条消息被多个消费者消费。
  • Routing(路由模式):有选择的接收消息。
  • Topics (主题模式):通过一定的规则来选择性的接收消息
  • RPC 模式:发布者发布消息,并且通过 RPC 方式等待结果。目前这个应该场景少,而且代码也较为复杂,本章不做细讲。

交换机类型:

  • direct(直连交换机):将队列绑定到交换机,消息的 routeKey 需要与队列绑定的 routeKey 相同。
  • fanout (扇形交换机):不处理 routeKey ,直接把消息转发到与其绑定的所有队列中。
  • topic(主题交换机):根据一定的规则,根据 routeKey 把消息转发到符合规则的队列中,其中#用于匹配符合一个或者多个词(范围更广), * 用于匹配一个词。
  • headers (头部交换机):根据消息的 headers 转发消息而不是根据 routeKey 来转发消息, 其中 header 是一个 Map,也就意味着不仅可以匹配字符串类型,也可以匹配其他类型数据。规则可以分为所有键值对匹配或者单一键值对匹配。

消息模式和交换机的对应关系如下:

2021-10-20-11-17-31
2021-10-20-11-17-31

消费模式

消费模式分为推模式(Basic Consume)和拉模式(channel basicGet)

代码demo

了解完上述概念后,还是要用代码实践一下,以加深自己的理解。幸运的是rabbitmq官方提供了完整的代码demo,并且包含多种语言版本。
所以可以直接下载官方示例学习:

https://github.com/rabbitmq/rabbitmq-tutorials

比如下面是python代码中的hello world例子

20211025142123
20211025142123

进阶

备份交换器

生产者在发送消息的时候如果不设置 mandatory 参数 那么消息在未被路由的情况下将会丢失,如果设置了 mandatory 参数,那么需要添加 ReturnListener 的编程逻辑,生产者的代码将变得复杂。如果既不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备份交换器,这样可以将未被路由的消息存储在 RabbitMQ 中,再在需要的时候去处理这些消息。

消息过期时间

目前有两种方式设置消息的过期时间,一是通过队列属性设置,二是通过消息单独设置。如果两种方式同时使用,以最小值为准。

队列过期时间

通过 channel queueDeclare 方法中的 expires 参数可以控制队列被自动删除前处于未使用状态的时间。未使用的意思是队列上没有任何的消费者,队列也没有被重新声明,并
且在过期时间段内也未调用过Basic Get命令。

死信队列(DLX)

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

消息变成死信一般由于以下几种情况:

  • 消息被拒绝
  • 消息过期
  • 队列达到最大长度

DLX 是一个正常的交换器,和一般的交换器没有区别,它能在任何的队列上被指定际上就是设置某个队列的属性。当这个队列中存在死信时 RabbitMQ 就会自动地将这个消息新发布到设置的 DLX ,进而被路由到另一个队列,即死信队列。可以监听这个队列中的消息、以进行相应的处理。

延时队列

在rabbitmq中可通过过期时间(TTL)和死信队列(DLX)实现延时队列

优先级队列

可设置队列支持的最大优先级,然后发送消息时设置消息的优先级。但是要注意这种情况只在消费者能力小于生产者,有消息堆积时有效。

持久化

RabbitMQ的持久化分为3个部分:交换器的持久化、队列的持久化和消息的持久化。但是如果将所有消息持久化,将会严重影响rabbitmq的性能。

即使将交换器、队列和消息都设置了持久化,也不能保证消息100%不丢失。

  1. 从消费者端,防止消费者收到消息还没来得及处理就宕机的情况,需要将autoAck设置为false
  2. 从生产者断,防止发送到rabbitmq后还没来的及落盘rabbitmq就宕机的情况,可以在生产者端引入事务机制或者发送方确认机制来保证消息己经正确地发送并存储RabbitMQ 中(前提还要保证在调用 channel.basicPublish 方法的时候交换器能够将消息正确路由到相应的队列之中)或者引入镜像队列来保证高可用

消息的有序性

很多资料上说rabbitmq可以保证消息的有序,其实是不严谨的。在不使用任何 RabbitM 高级特性 ,也没有消息丢失、网络故障之类异常的情况发生,并且只有一个消费者的情况下,最好也只有一个生产者的情况下可以保证消息的顺序性。如果有多个生产者同时发送消息,无法确定消息到达 Broker 的前后顺序,也就无法验证消息的顺序性。

如果要保证消息的顺序性,需要业务方使用 RabbitMQ 之后做进一步的处理,比如在消息体内添加全局有序标识(类似SequenceID) 来实现。

惰性队列

RabbitMQ 3.6.0 版本开始引入了惰性队列 lazy Queue 的概念。惰性队列会尽可能地将消息存入磁盘中,而在消费者消费到相应的消息时才会被加载到内存中,它的一个重要的设计目标是能够支持更长的队列即支持更多的消息存储。当消费者由于各种各样的原因(比如消费者下线、宕机或者由于维护而关闭等〉致使长时间内不能消费消息而造成堆积时惰性队列就很有必要了。

面试资料和电子书

上面进阶的内容可能只是零散的知识点,如果想比较成体系的深入了解的话,还是建议读本关于rabbitmq的书,个人比较推荐《RabbitMQ实战指南。
看完后如果还想查漏补缺,或者应对面试,可以看一下网上的知识点总结或者最新的面试题汇总。


学习的最好方法就是实践,建议大家像上面写的那样在自己机器上安装学习一下,不要只停留在纸面上。

最后因为电子书和面试题都是PDF,所以我都上传到了网盘,如果大家需要,可以回复:rabbitmq,获取一些资料。

20211025154244
20211025154244
posted @ 2021-10-25 15:51  码匠赵铁柱  阅读(267)  评论(0编辑  收藏  举报