目录

前言

一、死信队列

概念

产生原因

死信队列的架构图

二、延迟队列

概念

使用场景

三、优先级队列

四、惰性队列

使用场景

两种模式

性能对比

RabbitMQ集群

使用集群的原因

搭建集群步骤

镜像队列

创建镜像队列

联邦交换机 Federation Exchange

步骤

联邦队列Federation Queue

总结


前言

继上一篇章了解完了消息队列的基本概念与使用场景,另外还讲解了RabbitMQ的几种工作模式,这一篇章我们来对RabbitMQ的死信队列,延迟队列,以及RabbitMQ的集群搭建等内容进行学习。

一、死信队列

概念

先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理 解,一般来说,生产者 将消息投递到 交换机或者直接到 队列里里了,消费者从队列取出消息 进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有 后续的处理,就变成了死信,有死信自然就有了死信队列。

应用场景:为了保证订单业务的消息数据不丢失,需要使用到 RabbitMQ 的死信队列机制,当消息 消费发生异常时,将消息投入死信队列中.还有比如说: 用户在商城下单成功并点击去支付后在指定时 间未支付时自动失效。

产生原因

消息 TTL 过期

队列达到最大长度(队列满了,无法再添加数据到 mq 中)

消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false

死信队列的架构图

开始按照正常步骤,生产者将消息传送给交换机,交换机通过zhangsan 这个key与队列normal绑定,然而这个时候,如果传输的消息由于被拒绝,或者TTL时间过期,队列已满的原因会进入到另一个交换机dead中,然后传输到死信队列dead中,交给c2消费者进行消费。如果没有出现问题,消息会按照正常情况由c1消费者进行消费。

二、延迟队列

概念

顾名思义 延迟队列的概念即我们队列中的消息不会立刻由消费者取出并进行消费,而是延迟到我们设定的时间后再进行消费。

使用场景

1.订单在十分钟之内未支付则自动取消

2.新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。

3.用户注册成功后,如果三天内没有登陆则进行短信提醒。

4.用户发起退款,如果三天内没有得到处理则通知相关运营人员。

5.预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议

这些场景都有一个特点,需要在某个事件发生之后或者之前的指定时间点完成某一项任务,如: 发生订单生成事件,在十分钟之后检查该订单支付状态,然后将未支付的订单进行关闭;看起来似乎 使用定时任务,一直轮询数据,每秒查一次,取出需要被处理的数据,然后处理不就完事了吗?如果 数据量比较少,确实可以这样做,比如:对于“如果账单一周内未支付则进行自动结算”这样的需求, 如果对于时间不是严格限制,而是宽松意义上的一周,那么每天晚上跑个定时任务检查一下所有未支 付的账单,确实也是一个可行的方案。但对于数据量比较大,并且时效性较强的场景,如:“订单十 分钟内未支付则关闭“,短期内未支付的订单数据可能会有很多,活动期间甚至会达到百万甚至千万 级别,对这么庞大的数据量仍旧使用轮询的方式显然是不可取的,很可能在一秒内无法完成所有订单 的检查,同时会给数据库带来很大压力,无法满足业务要求而且性能低下。

在讲延迟队列的时候,我们首先要了解一个概念 “TTL属性”。

  TTL 是什么呢?TTL 是 RabbitMQ 中一个消息或者队列的属性,表明一条消息或者该队列中的所有消息的最大存活时间,单位是毫秒。换句话说,如果一条消息设置了 TTL 属性或者进入了设置 TTL 属性的队列,那么这 条消息如果在 TTL 设置的时间内没有被消费,则会成为"死信"。如果同时配置了队列的 TTL 和消息的 TTL,那么较小的那个值将会被使用。
  有两种方式设置 TTL。
  一种是在声明队列的时候设置,另一种是对消息设置。

三、优先级队列

在我们创建队列的时候可以勾选让之成为优先级队列,然后在创建消息的时候对其设置优先级,这样消费者在队列中有多个消息的时候会优先取优先级最高的消息进行消费。

四、惰性队列

使用场景

  RabbitMQ 从 3.6.0 版本开始引入了惰性队列的概念。惰性队列会尽可能的将消息存入磁盘中,而在消 费者消费到相应的消息时才会被加载到内存中,它的一个重要的设计目标是能够支持更长的队列,即支持 更多的消息存储。当消费者由于各种各样的原因(比如消费者下线、宕机亦或者是由于维护而关闭等)而致 使长时间内不能消费消息造成堆积时,惰性队列就很有必要了。
  默认情况下,当生产者将消息发送到 RabbitMQ 的时候,队列中的消息会尽可能的存储在内存之中,
  这样可以更加快速的将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留 一份备份。当 RabbitMQ 需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的 时间,也会阻塞队列的操作,进而无法接收新的消息。虽然 RabbitMQ 的开发者们一直在升级相关的算法, 但是效果始终不太理想,尤其是在消息量特别大的时候。

两种模式

  队列具备两种模式:default 和 lazy。默认的为 default 模式,在 3.6.0 之前的版本无需做任何变更。lazy 模式即为惰性队列的模式,可以通过调用 channel.queueDeclare 方法的时候在参数中设置,也可以通过 Policy 的方式设置,如果一个队列同时使用这两种方式设置的话,那么 Policy 的方式具备更高的优先级。
如果要通过声明的方式改变已有队列的模式的话,那么只能先删除队列,然后再重新声明一个新的。 在队列声明的时候可以通过“x-queue-mode”参数来设置队列的模式,取值为“default”和“lazy”。下面示 例中演示了一个惰性队列的声明细节:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-queue-mode", "lazy");
channel.queueDeclare("myqueue", false, false, false, args);

性能对比

在发送 1 百万条消息,每条消息大概占 1KB 的情况下,普通队列占用内存是 1.2GB,而惰性队列仅仅占用 1.5MB。

RabbitMQ集群

使用集群的原因

  最开始我们一直介绍的都是基于单机版运行 RabbitMQ 服务,然而如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等情况,该怎么办?单台 RabbitMQ 服务器可以满足每秒 1000 条消息的吞吐量,那么如果应用需要 RabbitMQ 服务满足每秒 10 万条消息的吞吐量呢?购买昂贵的服务器来增强单机 RabbitMQ 务的性能显得捉襟见肘,搭建一个 RabbitMQ 集群才是 解决实际问题的关键。

搭建集群步骤

1.修改 3 台机器的主机名称
vim /etc/hostname
2.配置各个节点的 hosts 文件,让各个节点都能互相识别对方
vim /etc/hosts
10.211.55.74 node1
10.211.55.75 node2
10.211.55.76 node3
3.以确保各个节点的 cookie 文件使用的是同一个值
在 node1 上执行远程操作命令
scp /var/lib/rabbitmq/.erlang.cookie root@node2:/var/lib/rabbitmq/.erlang.cookie
scp /var/lib/rabbitmq/.erlang.cookie root@node3:/var/lib/rabbitmq/.erlang.cookie
4.启动 RabbitMQ 服务,顺带启动 Erlang 虚拟机和 RbbitMQ 应用服务(在三台节点上分别执行以
下命令)
rabbitmq-server -detached
5.在节点 2 执行
rabbitmqctl stop_app
(rabbitmqctl stop 会将 Erlang 虚拟机关闭,rabbitmqctl stop_app 只关闭 RabbitMQ 服务)
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node1
rabbitmqctl start_app(只启动应用服务)
6.在节点 3 执行rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node2
rabbitmqctl start_app
7.查看集群状态
rabbitmqctl cluster_status
8.需要重新设置用户
创建账号
rabbitmqctl add_user admin 123
设置用户角色
rabbitmqctl set_user_tags admin administrator
设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
9.解除集群节点(node2 和 node3 机器分别执行)
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
rabbitmqctl cluster_status
rabbitmqctl forget_cluster_node rabbit@node2(node1 机器上执行)

镜像队列

  如果 RabbitMQ 集群中只有一个 Broker 节点,那么该节点的失效将导致整体服务的临时性不可用,并 且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true, 但是这样仍然无法避免由于缓存导致的问题:因为消息在发送之后和被写入磁盘井执行刷盘动作之间存在 一个短暂却会产生问题的时间窗。通过publisherconfirm 机制能够确保客户端知道哪些消息己经存入磁盘,
  尽管如此,一般不希望遇到因单点故障导致的服务不可用。引入镜像队列(Mirror Queue)的机制,可以将队列镜像到集群中的其他 Broker 节点之上,如果集群中的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。

创建镜像队列

1.启动三台集群节点
2.随便找一个节点添加 policy
3.在 node1 上创建一个队列发送一条消息,队列存在镜像队列
4.停掉 node1 之后发现 node2 成为镜像队列
5.就算整个集群只剩下一台机器了 依然能消费队列里面的消息
说明队列里面的消息被镜像队列传递到相应机器里面了

联邦交换机 Federation Exchange

  (broker 北京),(broker 深圳)彼此之间相距甚远,网络延迟是一个不得不面对的问题。有一个在北京的业务(Client 北京) 需要连接(broker 北京),向其中的交换器 exchangeA 发送消息,此时的网络延迟很小, (Client 北京)可以迅速将消息发送至 exchangeA 中,就算在开启了 publisherconfirm 机制或者事务机制的情况下,也可以迅速收到确认信息。此时又有个在深圳的业务(Client 深圳)需要向 exchangeA 发送消息,那么(Client 深圳) (broker 北京)之间有很大的网络延迟,(Client 深圳) 将发送消息至 exchangeA 会经历一定的延迟,尤其是在开启了 publisherconfirm 机制或者事务机制的情况下,(Client 深圳) 会等待很长的延迟时间来接收(broker 北京)的确认信息,进而必然造成这条发送线程的性能降低,甚至造成一定程度上的阻塞。
  将业务(Client 深圳)部署到北京的机房可以解决这个问题,但是如果(Client 深圳)调用的另些服务都部署在深圳,那么又会引发新的时延问题,总不见得将所有业务全部部署在一个机房,那么容灾又何以实现?
  这里使用 Federation 插件就可以很好地解决这个问题.
1.需要保证每台节点单独运行
2.在每台机器上开启 federation 相关插件
rabbitmq-plugins enable rabbitmq_federation
rabbitmq-plugins enable rabbitmq_federation_management
 
3.原理图(先运行 consumer 在 node2 创建 fed_exchange)
4.在 downstream(node2)配置 upstream(node1)
5.添加 policy
6.成功的前提

步骤

联邦队列Federation Queue

  联邦队列可以在多个 Broker 节点(或者集群)之间为单个队列提供均衡负载的功能。一个联邦队列可以 连接一个或者多个上游队列(upstream queue),并从这些上游队列中获取消息以满足本地消费者消费消息的需求。
  原理图
2.添加 upstream(同上)
3.添加 policy

总结

消息队列作为开发中常用的中间件,是当下热门的技术之一,除了RabbitMQ以外,还有.ActiveMQ,Kafka,RocketMQ等等,消息队列在多种场景都可以使用。

学习纪录片:三、消息队列下—RbbitMQ相关推荐

  1. Redis学习笔记~实现消息队列比MSMQ更方便

    回到目录 什么是队列:简单的说就是数据存储到一个空间里(可以是内存,也可以是物理文件),先存储的数据对象,先被取出来,这与堆栈正好相反,消息队列也是这样,将可能出现高并发的数据进行队列存储,并按着入队 ...

  2. 进程通信学习笔记(Posix消息队列)

    在某个进程往一个队列写入消息之前,并不需要另外有个进程在该队列上等待消息的到达,这跟管道和FIFO是相反的,对于后两者来说,除非读出者已存在,否则先有写入者是没有意义的 1.mq_open.mq_cl ...

  3. exit函数_Linux进程间通信详解(三) 消息队列及函数

    消息队列的概念 消息队列就是一个消息的链表,每个消息队列都有一个队列头,用结构struct msg_queue来描述.队列头中包含了该队列的大量信息,包括消息队列的键值.用户ID.组ID.消息数目.读 ...

  4. Linux进程间通信详解(三) —— 消息队列及函数

    消息队列的概念 消息队列就是一个消息的链表,每个消息队列都有一个队列头,用结构struct msg_queue来描述.队列头中包含了该队列的大量信息,包括消息队列的键值.用户ID.组ID.消息数目.读 ...

  5. JAVA03_21学习总结(RabbitMQ消息队列)

    今日内容 1. RabbitMQ 消息队列 Rabbitmq 消息队列基于AMQP协议的消息队列就是将本来一次性完成的,耗时的,需要等待的操作分离出来-形成一个单独的模块,就是消息队列-例子:普通方式 ...

  6. linux 进程uhxuhao,linux 进程间通信三 消息队列以及实例

    转自 http://blog.csdn.net/liang890319/article/details/8280934 代码来自:嵌入式Linux应用开发标准教程 消息可以理解为写信给某个人,这里在应 ...

  7. RabbitMQ入门学习系列(三).消息发送接收

    快速阅读 用Rabitmq的队列管理,以及如何保证消息在队列中不丢失.通过ack的消息确认和持久化进行操作.以及Rabbit中如何用Web面板进行管理队列.消费者如何处理耗时的任务 生产者代码创建链接 ...

  8. 【Python学习系列三】Windows下Python第三方常用库安装

    Python有丰富的第三方库,提供丰富的爬虫.数据分析等功能. 方法一:下载完整包,含编译器和常见库,https://www.continuum.io/downloads/          针对操作 ...

  9. Rplidar学习(三)—— ROS下进行rplidar调试

    一.建立工作空间.编译包 mkdir -p ~/catkin_rplidar/src #创建目录 cd ~/catkin_rplidar/src #打开目录#下载rplidar_ros数据包,进行移动 ...

最新文章

  1. 海量数据处理:从并发编程到分布式系统
  2. Numpy核心语法和代码整理汇总!
  3. sersync + rsync 实现文件的实时同步
  4. WebDriverAgent安装到iphone真机
  5. tidb mysql5.7_MYSQL5.7实时同步数据到TiDB
  6. Shell 编程进阶笔记
  7. SQL数据分析实战:好用的窗口函数
  8. Luogu2114 [NOI2014]起床困难综合症 【位运算】
  9. 设计模式(7) 续原型模式
  10. python的浮点数_Python的浮点数损失精度问题
  11. 技术人 | 如何做一个明白状况的研发主管?
  12. 布朗大学计算机专业怎么样,Offer捷报 | 恭喜Z同学收获布朗大学计算机科学专业Offer!...
  13. 百度新营销:不只是关键词了
  14. 海湾汉字编码表全部_汉字编码对照表
  15. 大华监控相机RTSP视频流
  16. 微信分享wx.config配置时遇到invalid signature错误的解决办法
  17. 【马克思主义基本原理】--第一章--【世界的物质性及发展规律】
  18. 曾经爱过就是彼此的慈悲
  19. Kotlin学习系列之:协程的取消和超时
  20. 【报错】VMware Workstation 与 Device/Credential Guard 不兼容.在禁用 Device/Credenti

热门文章

  1. 驱动程序开发:LCD屏显示驱动
  2. PCL 基于惯性矩与偏心率的描述子进行包围盒提取
  3. php导出excel格式文件,PHP导入与导出Excel文件的方法
  4. RocketMQ的拉(Pull)模式详解
  5. Alcohol 120%刻录教程:软件介绍
  6. vue+vite+element-plus修改全局主题颜色
  7. 外部用户触达方式有哪些?应用场景是什么?
  8. 关于 4G/5G 智能手机天线调谐的 4 点须知
  9. n!阶乘末尾有多少个零0
  10. 那些年解的疑难性能问题 --- ext4_fsync优化