RabbitMQ实战指南笔记

目录

 

第1章 RabbitMQ简介

1.1 什么是消息中间件

1.2 消息中间件的作用

1.3 RabbitMQ起源

1.4 RabbitMQ的安装及简单实用

第2章 RabbitMQ入门

2.1 概念介绍

2.2 AMQP协议介绍

第3章 客户端开发向导(php-amqplib)

3.1 连接RabbitMQ

3.2 使用交换器和队列

3.3 发送消息

3.4 消费消息

3.5 消费端的确认与拒绝

3.6 关闭连接

第4章 RabbitMQ进阶

4.1 消息何去何从

4.2 过期时间(TTL)

4.3 死信队列

4.4 延迟队列

4.5 优先级队列

4.6 RPC实现

4.7 持久化

4.8 生产者确认

4.9 消费端要点介绍

4.10 消息传输保障

第5章 RabbitMQ管理

5.1 多租户与权限

5.2 用户管理

5.3 Web端管理

5.4 应用与集群管理

5.5 服务端状态

5.6 HTTP API接口管理

第6章 RabbitMQ配置

6.1 环境变量

6.2 配置文件

6.3 参数及策略

第7章 RabbitMQ运维

7.1 集群搭建

7.1.1 多机多节点配置

7.1.2 集群节点类型

7.1.3 剔除单个节点

7.1.4 集群节点升级

7.1.5 单机多节点配置

7.2 查看服务日志

7.3 单节点故障恢复

7.4 集群迁移

7.5 集群监控

第8章 跨越集群的界限

8.1 Federation

8.2 Shovel

第9章 RabbitMQ高阶

9.1 存储机制

9.2 内存及磁盘警告

9.3 流控(Flow Control)

9.4 镜像队列

第10章 网络分区

10.1 网络分区的意义

10.2 网络分区的判定

10.3 网络分区的模拟

10.4 网络分区的影响

10.5 手动处理网络分区

10.6 自动处理网络分区

第11章 RabbitMQ扩展

11.1 消息追踪

11.2 负载均衡


第1章 RabbitMQ简介

1.1 什么是消息中间件

  • 消息(Message)是指在应用间传送的数据。
  • 消息中间件(Message Queue Middleware)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
  • 一般有两种模式:点对点(P2P,Point-to-Point)模式、发布/订阅(Pub/Sub)模式。
  • 适用场景:适用于需要可靠数据传送的分布式系统。

1.2 消息中间件的作用

  • 解耦:处理过程中定义一个隐含的数据接口,两边应用的处理过程都实现这一接口,允许应用独立扩展或修改两边的处理过程,只要确保它们遵循同样的接口约束即可。
  • 冗余(存储):把数据进行持久化,直到它们被成功处理,规避数据丢失风险。
  • 扩展性:解耦了应用的处理过程,如果有需要,只要另外增加处理过程即可,不需要改变代码或调整参数。
  • 削峰:应对突发访问压力,规避访问量剧增情况,防止因为突发的超负荷请求导致系统崩溃。
  • 可恢复性:当子系统或部分组件失效时,不会影响到整个系统。消息仍然可以再系统恢复后继续处理。
  • 顺序保证:保证消息处理的顺序性(FIFO)。
  • 缓冲:控制和优化数据流经过系统的速度。
  • 异步通信:把不需要立即处理的消息,先放入消息中间件中,等需要的时候再慢慢处理。

1.3 RabbitMQ起源

  • 采用Erlang语言实现AMQP(Advanced Message Queuing Protocol,高级消息队列协议)的消息中间件。用于在分布式系统中存储转发消息。
  • Rabbit名称来源,是因为兔子行动非常迅速且繁殖起来非常疯狂。
  • RabbitMQ是由RabbitMQ Technologies Ltd开发并提供商业支持。2010年4月被SpringSource收购,2013年5月并入Pivotal,在RabbitMQ官网Logo旁可以看到“by Pivotal”字样。
  • 官网地址:https://www.rabbitmq.com
  • Github地址:https://github.com/rabbitmq/rabbitmq-server
  • RabbitMQ特点:
    • 可靠性:如持久化、传输确认及发布确认等机制来保证消息可靠性。
    • 灵活的路由:消息入列之前通过交换器来路由消息。已提供了一些内置路由实现。多路由可绑定一起使用,也可以通过插件机制实现自己的路由。
    • 扩展性:支持多个RabbitMQ节点组成集群,动态扩展集群节点。
    • 高可用性:消息队列可再集群机器上设置镜像,使得在部分节点异常时,队列仍然可用。
    • 多协议支持:AMQP、STOMP、MQTT等多种消息中间件协议支持。
    • 多语言客户端:几乎支持所有常用语言,如Java、Python、Go、PHP、JavaScript等。
    • 图形管理界面:用户可视化界面,管理和监控消息、集群节点等功能。
    • 插件机制:RabbitMQ提供许多插件,以实现多方面扩展,也可以编写自己的插件。

1.4 RabbitMQ的安装及简单实用

  1. 安装Erlang语言
    yum安装:
    [root@liuns ~]# yum install erlang -y
    [root@liuns ~]# erl
    Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]
    Eshell V5.10.4  (abort with ^G)
    1>
    
    source安装:
    [root@liuns ~]# wget https://erlang.org/download/otp_src_22.1.tar.gz
    [root@liuns ~]# tar zxvf otp_src_22.1.tar.gz
    [root@liuns ~]# cd otp_src_22.1
    [root@liuns ~]# ./configure --prefix=/opt/erlang
    [root@liuns ~]# make && make install
    [root@liuns ~]# ERLANG_HOME=/opt/erlang
    [root@liuns ~]# export PATH=$PATH:$ERLANG_HOME/bin
    [root@liuns ~]# export ERLANG_HOME
    [root@liuns ~]# erl //验证
    Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]
    Eshell V5.10.4  (abort with ^G)
    1>

     

  2. 安装及启动RabbitMQ
    //直接下载安装包解压到对应的目录即可
    [root@liuns ~]# wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.10/rabbitmq-server-generic-unix-3.6.10.tar.xz
    [root@liuns ~]# xz -d rabbitmq-server-generic-unix-3.6.10.tar.xz
    [root@liuns ~]# tar xvf rabbitmq-server-generic-unix-3.6.10.tar
    [root@liuns ~]# mv rabbitmq_server-3.6.10 /opt/rabbitmq
    [root@liuns ~]# echo RABBITMQ_HOME=/opt/rabbitmq >> ~/.bash_profile
    [root@liuns ~]# echo export PATH=$PATH:$RABBITMQ_HOME/sbin >> ~/.bash_profile
    [root@liuns ~]# echo export RABBITMQ_HOME >> ~/.bash_profile
    [root@liuns ~]# source ~/.bash_profile //环境变量生效
    
    //以守护进程方式启动rabbitmq服务
    [root@liuns ~]# rabbitmq-server -detached
    
    //查看RabbitMQ运行状态
    [root@liuns ~]# rabbitmqctl status
    
    //查看RabbitMQ运行状态
    [root@liuns ~]# rabbitmqctl cluster_status
    
    //停止rabbitmq服务
    [root@liuns ~]# rabbitmqctl stop
    

     

  3. RabbitMQ服务访问用户配置
    //默认访问用户名和密码都是“guest”,只能通过localhost本地网络访问。
    
    //添加新用户,用户名root,密码123456
    [root@liuns ~]# rabbitmqctl add_user root 123456
    Creating user "root"
    
    //为root用户设置所有权限
    [root@liuns ~]# rabbitmqctl set_permissions -p / root ".*" ".*" ".*"
    Setting permissions for user "root" in vhost "/"
    
    //设置root为管理员角色
    [root@liuns ~]# rabbitmqctl set_user_tags root administrator
    Setting tags for user "root" to [administrator]
    [root@liuns ~]# rabbitmqctl list_users
    Listing users
    guest	[administrator]
    root	[administrator]
    
    //设置root为管理员角色
    [root@liuns ~]# rabbitmqctl [Enter]
    
    

     

第2章 RabbitMQ入门

2.1 概念介绍

RabbitMQ实战指南笔记_第1张图片

  • Producer(生产者):创建消息方,然后发布到RabbitMQ中。一般包含两部分,即消息体(Payload)和标签(Label)。
    • 消息体(Payload):一般是一个带有业务逻辑结构的数据,如JSON字符串。
    • 标签(Label):用来表述这条消息,比如一个交换器(Exchange)的名称和一个路由键。RabbitMQ会根据标签把消息发送给对应的消费者(Consumer)。
  • Consumer(消费者):接收消息方,连接到RabbitMQ服务器,并订阅到队列上。
    • 在消息路由的过程中,消息的标签(Label)会被丢弃,所以消费者消费一条消息时,只是消费消息体(Payload),并不知道消息的生产者是谁。
  • Broker(消息中间件服务节点):可以简单看作一个RabbitMQ服务节点或RabbitMQ服务实例,也可以看作一台RabbitMQ服务器。下图是生产者将消息存入Broker,以及消费者从Broker中消费数据的整个流程图。RabbitMQ实战指南笔记_第2张图片
  • Queue(队列):RabbitMQ的内部对象,用于存储消息。
    • 生产者(Producer)生产消息并最终投递到队列(Queue)中,消费者(Consumer)可以从队列中获取消息并消费。
    • 多个消费者(Consumer)可以订阅同一个队列(Queue),消息会被轮询分摊给多个消费者处理,而不是每个消费者都收到所有消息处理。
    • RabbitMQ不支持队列层面的广播消息,如果需要广播消息,需要在其上二次开发,处理逻辑会变得异常复杂,同时也不建议这么做。
  • Exchange(交换器):生产者将消息发送到交换器(Exchange),由交换器将消息路由到一个或多个队列中。
    • Producer -> Exchange -> Queue。
    • 如果路由不到队列,消息会被丢弃或返回给生产者。
    • 交换器四种类型:
      • fanout:把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。
      • direct:把消息路由到那些与RoutingKey和BindingKey完全匹配的队列中。
      • topic:与direct相似,只是RoutingKey和BindingKey匹配规则不同。
        • RoutingKey为一个点号“.”分隔的字符串,被分隔的每一段独立的字符成为单词。如“com.rabbitmq.client”;
        • BindingKey和RoutingKey一样也是点号“.”分隔的字符串,并支持两种特殊通配字符:星号“*”和井号“#”;
          • “*”:用于匹配一个单词。
          • “#”:用于匹配多个单词(可以是零个)。
      • headers:不依赖路由键的匹配规则来路由消息,而是根据消息内容中的headers属性进行匹配。
  • RoutingKey(路由键):生产者将消息发送给交换器时,一般会指定一个RoutingKey,用来指定这个消息的路由规则,而这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才会生效。
  • Binding(绑定):RabbitMQ通过绑定(Binding)将交换器和队列(Queue)关联起来,在绑定的时候回指定一个绑定键(BindingKey)来确定应该将消息路由到那个队列中。

2.2 AMQP协议介绍

  • AMQP(高级消息队列协议):说到底还是一种通信协议,AMQP协议可以看作一系列结构化命令的集合,这里的命令代表一种操作,类似HTTP中的方法(GET、POST、PUT、DELETE等)。
    • low-level层面来看,本身是OSI应用层的通信协议,其填充与TCP协议层的数据部分。
    • high-level层面来看,是通过协议命令进行交互的。
    • AMQP协议本身包括三层:
    1. Module Layer(模型层):位于最高层,主要定义一些供客户端调用的命令,客户端通过命令实现自己的业务逻辑。
    2. Session Layer(会话层):位于中间层,主要负责将客户端的命令发送给服务器,再将服务端的应答返回给客户端,为两者之间的通信提供可靠的同步机制和错误处理。
    3. Transport Layer(传输层):位于最底层,主要传输二进制数据流,提供帧的处理、信道复用、错误检测和数据表示等。
  • RabbitMQ遵从AMQP协议,即RabbitMQ是AMQP协议的Erlang的实现。
  • AMQP模型架构与RabbitMQ一样,都是生产者将消息发送给交换器,交换器和队列绑定。发送消息时通过路由键(RoutingKey)和绑定键(BindingKey)匹配并存入相应队列(Queue)中。
  • 细节参考资料 https://baike.baidu.com/item/AMQP

第3章 客户端开发向导(php-amqplib)

3.1 连接RabbitMQ

  • 用给定的参数(IP地址、端口号、用户名、密码等)连接RabbitMQ服务。
  • 建立连接Connection后,创建Channel用来发送或者接收消息。
    require_once __DIR__ . '/vendor/autoload.php';
    use PhpAmqpLib\Connection\AMQPStreamConnection;
    use PhpAmqpLib\Exchange\AMQPExchangeType;
    use PhpAmqpLib\Message\AMQPMessage;
    
    $connection = new AMQPStreamConnection('localhost', 9876, 'guest', 'guest');
    $channel = $connection->channel();

3.2 使用交换器和队列

  • 使用路由键将队列和交换器绑定起来。
    $exchange = 'router';
    $queue = 'msgs';
    
    //队列声明
    /*
        name: $queue
        passive: false
        durable: true // the queue will survive server restarts
        exclusive: false // the queue can be accessed in other channels
        auto_delete: false //the queue won't be deleted once the channel is closed.
    */
    $channel->queue_declare($queue, false, true, false, false);
    
    //交换器声明
    /*
        name: $exchange
        type: direct
        passive: false
        durable: true // the exchange will survive server restarts
        auto_delete: false //the exchange won't be deleted once the channel is closed.
    */
    $channel->exchange_declare($exchange, AMQPExchangeType::DIRECT, false, true, false);
    
    //交换器和队列绑定
    $channel->queue_bind($queue, $exchange);

3.3 发送消息

  • https://github.com/php-amqplib/php-amqplib/blob/master/demo/amqp_publisher.php

3.4 消费消息

  • https://github.com/php-amqplib/php-amqplib/blob/master/demo/amqp_consumer.php
  • 消费者可以通过推模式或拉模式来获取并消费消息。

3.5 消费端的确认与拒绝

  • https://github.com/php-amqplib/php-amqplib/blob/master/demo/amqp_publisher_with_confirms.php

3.6 关闭连接

  • 在应用程序使用完之后,需要关闭连接,释放资源。
  • 显式的关闭Channel是个好习惯,但这个不是必须的,在Connection关闭的时候,Channel也会自动关闭。

     

客户端支持列表 https://www.rabbitmq.com/devtools.html

客户端使用教程 https://www.rabbitmq.com/getstarted.html

第4章 RabbitMQ进阶

4.1 消息何去何从

  • RabbitMQ提供当消息传递过程中不可达目的地时将消息返回给生产者功能。
  • RabbitMQ提供的备份交换器(Alternate Exchange,AE)可以将未能被交换器路由的消息存储起来,而不用返回给客户端。

4.2 过期时间(TTL)

  • TTL,Time to Live简称,即过期时间。RabbitMQ可以对消息和队列设置过期时间。目前有两种方式可以设置:
    • 第一种,通过队列属性设置,队列中所有消息都有相同的过期时间。一旦消息过期,就会从队列中抹去。
    • 第二种,对消息本身进行单独设置,每条消息的过期时间可以不同。即使消息过期,也不会立即从队列中抹去,因为每条消息是否过期是在即将投递到消费者之前判断的。
  • 如果不设置TTL,则表示此消息永不过期。
  • 如果设置TTL为零,则表示除非此时消息可以直接投递到消费者,否则该消息会被立即丢弃。

4.3 死信队列

  • DLX,全程Dead-Letter-Exchange,称之为死信交换器。也是一个正常的交换器,和一般的交换器并没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性(x-dead-letter-exchange属性)。
  • 当消息在一个队列中变成私信(dead message)之后,它能被重新发送到另一个交换器中,绑定DLX的队列称之为死信队列。
  • 消息变成死信的几种情况:
    • 消息被拒绝,并且设置requeue为false。
    • 消息过期。
    • 队列达到最大长度。

4.4 延迟队列

  • 延迟队列存储的对象就是延迟消息。
  • 延迟消息是指当消息发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
  • RabbitMQ本身没有直接支持延迟队列功能,但是可以通过DLX和TTL模拟出延迟队列功能。
    • 假设一个应用中需要将每条消息都设置为10秒的延迟,生产者通过exchange.normal这个交换器将发送的消息存储在queue.normal这个队列中。消费者订阅的并非是queue.normal这个队列,而是queue.dlx这个死信队列。当消息从queue.normal这个队列过期之后被存入queue.dlx这个死信队列中,消费者就恰巧消费到了延迟10秒的这条消息。

4.5 优先级队列

  • 顾名思义,就是具有高优先级的队列优先执行,优先级高的消息具有优先执行的特权。
  • 队列通过设置x-max-priority属性实现,通过web界面可以看到“Pri”的标识。
  • 消息通过设置priority属性实现,默认最低优先级为零。

4.6 RPC实现

  • .....

4.7 持久化

  • 持久化可以提高RabbitMQ的可靠性,以防在异常情况(重启、关闭、宕机)下的数据丢失。
  • RabbitMQ的持久化分为三个部分:
    1. 交换器的持久化,通过在声明交换器时将durable参数设置为true实现的。如果不设置,那么在RabbitMQ服务重启后,交换器的元数据会丢失,不过消息不会丢失,只是不能将消息发送到这个交换器了。
    2. 队列的持久化,通过声明队列时将durable参数设置为true实现的。如果不设置,那么在RabbitMQ服务重启后,队列的元数据会丢失,此时消息数据也会丢失。
    3. 消息的持久化,通过申明消息的时候设置(具体怎么设置没查...)。
  • 将所有的消息都设置为持久化,会验证影响RabbitMQ的性能。写入磁盘的速度比写入内存的速度慢的不是一点点,对于可靠性不是很高的消息可以不设置持久化。

4.8 生产者确认

  • 生产者确认发送的消息是否真的到达了RabbitMQ服务的交换器中。
  • RabbitMQ提供两种实现机制(两种机制互斥,不可共存):
    • 通过事务机制实现:
      • 相关方法有三个Channel.txSelect()、Channel.txCommit()、Channel.txRollback()。
      • 在一条消息发送后会使发送端阻塞,所以会严重降低RabbitMQ的消息吞吐量,所以引入了轻量级的方式——发送方确认机制。
    • 通过发送方确认(publisher confirm)机制实现:
      • 相关方法Channel.confirmSelect()、Channel.WatForConfirms()或Channel.confirmSelectOk()。
      • 在一条消息发送后,发送端异步等待处理确认信息,不会阻塞发送端,同时继续处理下一条消息。
      • 信道(Channel)设置为confirm模式,所有在该信道上的消息都会被指派一个唯一的ID,一旦消息被投递到所匹配的队列之后,RabbitMQ就会发送一个确认(Ack)给生产者(包含消息的唯一ID),这就使得发送方知晓消息已发送成功。

4.9 消费端要点介绍

  • 消息分发
    • 当同一队列有多个消费者时,消息将以轮询(round-robin)的分发方式发送给消费者。每条消息只会发给订阅列表里的一个消费者。
    • 如果有n个消费者,那么RabbitMQ会将第m条消息分发给第m%n(取余的方式)个消费者。
  • 消息顺序性
    • 指消费者消费到的消息与发送者发布的消息的顺序是一致的。
    • 目前RabbitMQ并不能保证完全保证消息的顺序性。如果要保证消息的顺序性,需要在业务方使用RabbitMQ之后做进一步处理,比如在消息体内添加全局有序标识(类似SequenceID)。

4.10 消息传输保障

  • 消息中间件的消息传输保障分为三个层级:
    • At most once:最多一次。消息可能会丢失,但绝不会重复传输。
    • At least once:最少一次。消息绝不会丢失,但可能会重复传输。
    • Exactly once:恰好一次。每条消息肯定会被传输一次且仅传输一次。
  • RabbitMQ目前支持其中的“最多一次”和“最少一次”。
  • “恰好一次”目前RabbitMQ无法保障,且目前大多数主流的消息中间件都没有消息去重机制。去重机制一般在业务端实现,比如引入GUID(Globally Unique Identifier)概念。

第5章 RabbitMQ管理

5.1 多租户与权限

  • vhost(虚拟主机):每一个RabbitMQ服务器都可以创建虚拟的消息服务器,称之为虚拟主机(virtual host),简称vhost。
    • vhost本质上是一个独立的小型RabbitMQ服务器,拥有自己独立的队列、交换器和绑定关系。
    • 多个vhost之间绝对隔离,无法将vhost1中的交换器与vhost2中的队列进行绑定。
    • RabbitMQ默认创建的vhost是“/”,默认用户名guest和密码guest。
      //新建虚拟机vhost1
      [root@liuns ~]# rabbitmqctl add_vhost vhost1
      Creating vhost "vhost1"
      
      //虚拟机列表
      [root@liuns ~]# rabbitmqctl list_vhosts name tracing
      Listing vhosts
      vhost1	false
      /	false
      
      //删除虚拟机vhost1
      [root@liuns ~]# rabbitmqctl delete_vhost vhost1
      Deleting vhost "vhost1"
  • 权限控制
    • RabbitMQ中权限控制是以vhost为单位的。因此,RabbitMQ中的授予权限是指在vhost级别对用户而言的权限授予。
  • 在创建用户的时候,用户通常会被指定至少一个vhost,且只能访问被指派的vhost内的队列、交换器和绑定关系等。
    //授予用户root可访问虚拟主机vhost1,并在所有资源上都具备可配置、可写,可读权限
    [root@liuns ~]# rabbitmqctl set_permissions -p vhost1 root ".*" ".*" ".*"
    Setting permissions for user "root" in vhost "vhost1"
    
    //列举虚拟机vhost1权限信息
    [root@liuns ~]# rabbitmqctl list_permissions -p vhost1
    Listing permissions in vhost "vhost1"
    root	.*	.*	.*
    
    //列举用户root的权限信息
    [root@liuns ~]# rabbitmqctl list_user_permissions root
    Listing permissions for user "root"
    vhost1	.*	.*	.*
    /	.*	.*	.*
    
    //清除root用户在vhost1上的权限
    [root@liuns ~]# rabbitmqctl clear_permissions -p vhost1 root
    Clearing permissions for user "root" in vhost "vhost1"

     

5.2 用户管理

  • RabbitMQ中,用户是访问控制(Access Control)的基本单元,且单个用户可以跨越多个vhost进行授权。
    //创建一个新用户root,密码123456
    [root@liuns ~]# rabbitmqctl add_user root 123456
    Creating user “root”
    
    //列出所有用户列表
    [root@liuns ~]# rabbitmqctl list_users
    Listing users
    guest	[administrator]
    root	[administrator]
    
    //修改用户密码
    [root@liuns ~]# rabbitmqctl change_password root 654321
    Changing password for user "root"
    
    //清除用户密码
    [root@liuns ~]# rabbitmqctl clear_password root
    Clearing password for user "root"
    
    //验证用户名和密码
    [root@liuns ~]# rabbitmqctl authenticate_user root 123456
    Authenticating user "root"
    Success 或 Error: failed to authenticate user "root"
    
    //删除用户
    [root@liuns ~]# rabbitmqctl delete_user root
    Deleting user "root"
  • 用户角色分为5中类型
  1. none:无任何角色。新用户角色默认为none;
  2. management:可以访问web管理界面;
  3. policymaker:包含management所有权限,并且可以管理策略(Policy)和参数(Parameter);
  4. monitoring:包含policymaker所有权限,并且可以看到所有连接、信道及节点相关信息;
  5. administrator:包含monitoring所有权限,并且可以管理用户、虚拟主机、权限、策略、参数等。代表最高权限。
    //设置用户一个或多个角色
    [root@liuns ~]# rabbitmqctl set_user_tags root policymaker,management
    Setting tags for user "root" to ['policymaker,management']
    [root@liuns ~]# rabbitmqctl list_users
    Listing users
    guest	[administrator]
    root	[policymaker,management]

5.3 Web端管理

  • RabbitMQ management插件可以提供Web管理界面,用来管理虚拟主机、用户、队列、交换器、绑定关系等,还可以监控RabbitMQ服务的状态及一些数据统计类信息,基本上涵盖所有RabbitMQ管理功能。
  • 插件位于RabbitMQ安装目录plugins目录内,其中以.ez扩展名称结尾的文件就是RabbitMQ的插件。
  • 插件启用后重启RabbitMQ服务才能正式生效。
  • 访问地址 http://IP地址:15672 用户名guest、密码guest。
    //启用rabbitmq-management插件
    [root@liuns ~]# rabbitmq-plugins enable rabbitmq_management
    The following plugins have been enabled:
      amqp_client
      cowlib
      cowboy
      rabbitmq_web_dispatch
      rabbitmq_management_agent
      rabbitmq_management
    
    Applying plugin configuration to rabbit@liuns... started 6 plugins.
    
    //查看当前插件使用情况
    //e*为隐士启用
    //E*为显式启用
    [root@liuns ~]# rabbitmq-plugins list
     Configured: E = explicitly enabled; e = implicitly enabled
     | Status:   * = running on rabbit@liuns
     |/
    [e*] amqp_client                       3.6.10
    [e*] cowboy                            1.0.4
    [e*] cowlib                            1.0.2
    [  ] rabbitmq_amqp1_0                  3.6.10
    [  ] rabbitmq_auth_backend_ldap        3.6.10
    [  ] rabbitmq_auth_mechanism_ssl       3.6.10
    [  ] rabbitmq_consistent_hash_exchange 3.6.10
    [  ] rabbitmq_event_exchange           3.6.10
    [  ] rabbitmq_federation               3.6.10
    [  ] rabbitmq_federation_management    3.6.10
    [  ] rabbitmq_jms_topic_exchange       3.6.10
    [E*] rabbitmq_management               3.6.10
    [e*] rabbitmq_management_agent         3.6.10
    [  ] rabbitmq_management_visualiser    3.6.10
    [  ] rabbitmq_mqtt                     3.6.10
    [  ] rabbitmq_recent_history_exchange  3.6.10
    [  ] rabbitmq_sharding                 3.6.10
    [  ] rabbitmq_shovel                   3.6.10
    [  ] rabbitmq_shovel_management        3.6.10
    [  ] rabbitmq_stomp                    3.6.10
    [  ] rabbitmq_top                      3.6.10
    [  ] rabbitmq_tracing                  3.6.10
    [  ] rabbitmq_trust_store              3.6.10
    [e*] rabbitmq_web_dispatch             3.6.10
    [  ] rabbitmq_web_mqtt                 3.6.10
    [  ] rabbitmq_web_mqtt_examples        3.6.10
    [  ] rabbitmq_web_stomp                3.6.10
    [  ] rabbitmq_web_stomp_examples       3.6.10
    [  ] sockjs                            0.3.4

5.4 应用与集群管理

  • 应用管理
    • rabbitmqctl stop [pid_file] 
      • 用于停止运行RabbitMQ的Erlang虚拟机和RabbitMQ服务应用。
    • rabbitmqctl shutdown
      • 与rabbitmqctl stop相似,且不需要pid_file,可以阻塞等待指定进程的关闭。
    • rabbitmqctl stop_app
      • 停止RabbitMQ服务应用,但是Erlang虚拟机还是处于运行状态。
      • 此命令的执行优先于其他管理操作(这些管理操作需要停止RabbitMQ应用),如rabbitmqctl reset。
    • rabbitmqctl start_app
      • 启动RabbitMQ服务应用。
      • 此命令典型用途是在其他管理操作之后,重新启动停止的RabbitMQ应用,如rabbitmqctl reset。
    • rabbitmqctl wait [pid_file]
      • 等待RabbitMQ应用的启动。
    • rabbitmqctl reset
      • 将RabbitMQ节点重置还原到最初状态。
    • rabbitmqctl force_reset
      • 强制将RabbitMQ节点重置还原到最初状态。
    • rabbitmqctl ratate_logs {suffix}
      • 指示RabbitMQ节点轮换或重置日志文件。
    • rabbitmqctl hipe_compile {directory}
      • 将部分RabbitMQ代码用HiPE编译,并将编译后的.beam文件保存到指定的目录中。
  • 集群管理
    • rabbitmqctl join_cluster {cluster_node} [--ram]
      • 将节点加入到集群中。
      • 命令执行前需要先停止RabbitMQ应用并重置节点(rabbitmqctl stop_app && rabbitmqctl reset)。
    • rabbitmqctl cluster_status
      • 显示集群状态
    • rabbitmqctl change_cluster_node_type {disc|ram}
      • 修改集群节点类型。
      • 命令执行前需要停止RabbitMQ应用(rabbitmqctl stop_app)。
    • rabbitmqctl forget_cluster_node [--offline]
      • 将节点从集群中删除,允许离线执行。
    • rabbitmqctl update_cluster_nodes {clusternode}
      • 在集群中的节点应用启动前咨询clusternode节点的最新信息,并更新响应的集群信息。
    • rabbitmqctl force_boot
      • 无条件地启动节点。
    • rabbitmqctl sync_queue [-p vhost] {queue}
      • 指示未同步队列queue的slave镜像可以同步master镜像行的内容。
      • 此条命令执行前提是队列queue已经配置了镜像。
      • 同步期间会阻塞(生产者和消费者),直到同步完成。
    • rabbitmqctl cancel_sync_queue [-p vhost] {queue}
      • 取消队列queue镜像同步操作。
    • rabbitmqctl set_cluster_name {name}
      • 设置集群名称。
      • 集群名称默认是集群中第一个节点的名称。

5.5 服务端状态

  • rabbitmqctl list_queues [-p vhost] [queueinfoitem ...]
    • 返回vhost(默认"/")内队列的详细信息。
    • queueinfoitem用于指定哪些队列的信息项会包含在结果集中。
  • rabbitmqctl list_exchanges [-p vhost] [exchangeinfoitem ...]
    • 返回交换器的详细信息。
  • rabbitmqctl list_connections [connectioninfoitem ...]
    • 返回TCP/IP连接的统计信息。
  • rabbitmqctl list_channels [channelinfoitem ...]
    • 返回当前所有信道的信息。
  • rabbitmqctl list_consumers [-p vhost]
    • 返回所有消费者信息。
  • rabbitmqctl status
    • 显示Broker的状态。
  • rabbitmqctl node_health_check
    • 对RabbitMQ节点进行健康检查,确认应用是否正常运行、list_queues和list_channels是否能够正常返回等。
  • rabbitmqctl environment
    • 显示每个运行程序环境中每个变量的名称和值。
  • rabbitmqctl report
    • 为所有服务器状态生成一个服务器状态报告。
  • rabbitmqctl eval {expr}
    • 执行任意Erlang表达式。

5.6 HTTP API接口管理

  • RabbitMQ Management插件不仅提供web管理界面,还提供了HTTP API接口来方便调用。
  • 细节参考 https://www.rabbitmq.com/management.html#http-api

第6章 RabbitMQ配置

6.1 环境变量

  • RabbitMQ环境变量都是“RABBITMQ_”为前缀,可以再shell中设置,也可以在rabbitmq-env.conf配置文件中设置。
  • 使用优先级顺序:Shell > rabbitmq-env.conf > 默认配置值。
  • rabbimq-env.conf默认在$RABBITMQ_HOME/etc/rabbitmq/目录下。
  • 环境变量默认取值规则可参考$RABBITMA_HOME/sbin/rabbitmq-defaults文件。

6.2 配置文件

  • rabbitmq.conf 默认在$RABBITMQ_HOME/etc/rabbitmq/rabbimq.conf (没有可手动创建)。
  • 配置文件示例参考 https://github.com/rabbitmq/rabbitmq-server/blob/master/docs/rabbitmq.conf.example
  • 配置文件内的敏感配置项可以被加密。
  • 配置文件修改后,重启Broker才能生效。

6.3 参数及策略

  • 大多数配置都可以通过修改配置文件rabbitmq.conf来完成,但是其中有些配置并不适合在配置文件中修改。比如某项配置不需要同步到集群节点中,或者某项配置需要在运行时修改,这种类型的配置在RabbitMQ中称为参数(Parameter)。
  • 参数可以通过rabbitmqctl工具或者RabbitMQ Management插件提供的API接口来设置。
  • RabbitMQ中共有两种类型的参数(Parameter):vhost级别的参数和global级别的参数。
    • vhost级别的参数对应的命令。
      • rabbitmqctl set_parameter [-p vhost] {component_name} {name} {value} 用来设置一个参数。
      • rabbitmqctl list_parameters [-p vhost] 列出指定虚拟机上所有参数(Parameter)。
      • rabbitmqctl clear_parameter [-p vhost] {component_name} {key} 清除指定参数。
    • global级别的参数对应命令。
      • rabbitmqctl set_global_parameter  {name} {value} 用来设置一个参数。
      • rabbitmqctl list_global_parameters 列出指定虚拟机上所有参数(Parameter)。
      • rabbitmqctl clear_global_parameter {name} 清除指定参数。
  • vhost级别参数和global级别的参数所对应的值(value)都是JSON类型的。

第7章 RabbitMQ运维

7.1 集群搭建

7.1.1 多机多节点配置

  • 环境三台物理机环境:
    • 192.168.0.2    node1
    • 192.168.0.3    node2
    • 192.168.0.4    node3
  • 第一步,配置各个节点/etc/hosts文件,是各个节点都能识别对方的存在。
    #/etc/hosts
    192.168.0.2    node1
    192.168.0.3    node2
    192.168.0.4    node3

     

  • 第二步,编辑RabbitMQ的cookie文件,以确保各个节点的cookie文件使用的是同一个值。
    • 可以读取node1节点的cookie值,然后复制到node2和node3节点中。
    • cookie文件默认路径/var/lib/rabbitmq/.erlang.cookie或者$HOME/.erlang.cookie。
    • cookie相当于秘钥令牌,集群中的节点需要通过交换秘钥令牌以获得相互验证。
      //node1服务器
      [root@node1 ~]# cat ~/.erlang.cookie
      ZKPLEQVNHWEWGBSEWUFL
      
      //node2服务器
      [root@node2 ~]# echo ZKPLEQVNHWEWGBSEWUFL > ~/.erlang.cookie
      
      //node3服务器
      [root@node3 ~]# echo ZKPLEQVNHWEWGBSEWUFL > ~/.erlang.cookie

       

  • 第三步,通过rabbitmqctl工具配置集群。
    • 首先,启动node1、node2和node3节点上的RabbitMQ服务。
      [root@node1 ~]# rabbitmq-server -detached
      [root@node2 ~]# rabbitmq-server -detached
      [root@node3 ~]# rabbitmq-server -detached
      
      //三个节点目前都是以独立的节点存在的单个集群。
      //通过rabbitmqctl cluster_status查看各个节点状态。
      [root@node1 ~]# rabbitmqctl cluster_status
      Cluster status of node rabbit@node1
      [{nodes,[{disc,[rabbit@node1]}]},
       {running_nodes,[rabbit@node1]},
       {cluster_name,<<"rabbit@node1">>},
       {partitions,[]},
       {alarms,[{rabbit@node1,[]}]}]
      
      [root@node2 ~]# rabbitmqctl cluster_status
      Cluster status of node rabbit@node1
      [{nodes,[{disc,[rabbit@node2]}]},
       {running_nodes,[rabbit@node2]},
       {cluster_name,<<"rabbit@node2">>},
       {partitions,[]},
       {alarms,[{rabbit@node2,[]}]}]
      
      [root@node2 ~]# rabbitmqctl cluster_status
      Cluster status of node rabbit@node1
      [{nodes,[{disc,[rabbit@node2]}]},
       {running_nodes,[rabbit@node2]},
       {cluster_name,<<"rabbit@node2">>},
       {partitions,[]},
       {alarms,[{rabbit@node2,[]}]}]
    • 接下来将3个节点组成一个集群,需要以node1节点为基准,将node2和node3节点加入到node1节点的集群中。
      //将node2节点加入到node1集群中(node3节点操作一样)
      [root@node2 ~]# rabbitmqctl stop_app
      Stopping rabbit application on node rabbit@node2
      [root@node2 ~]# rabbitmqctl reset
      Resetting node rabbit@node2
      [root@node2 ~]# rabbitmqctl join_cluster rabbit@node1
      Clustering node rabbit@node2 with rabbit@node1
      [root@node2 ~]# rabbitmqctl start_app
      Starting node rabbit@node2
      
      //任意一个节点查看集群状态,便可以看到node1、node2和node3已处于一个集群中。
      [root@node1 ~]# rabbitmqctl cluster_status
      Cluster status of node rabbit@liuns
      [{nodes,[{disc,[rabbit@node1,rabbit@node2,rabbit@node3]}]},
       {running_nodes,[rabbit@node1,rabbit@node2,rabbit@node3]},
       {cluster_name,<<"rabbit@node1">>},
       {partitions,[]},
       {alarms,[{rabbit@node1,[]},{rabbit@node2,[]},{rabbit@node3,[]}]}]

       

  • 至此集群已搭建完成。

  • 其他注意项

    • 如果集群中某个节点关闭了,那么关闭的节点会从集群集running_nodes选项中删除。

      //关闭node2节点
      [root@node2 ~]# rabbitmqctl stop_app
      Stopping rabbit application on node rabbit@node2
      
      //查看集群状态
      [root@liuns ~]# rabbitmqctl cluster_status
      Cluster status of node rabbit@liuns
      [{nodes,[{disc,[rabbit@node1,rabbit@node2,rabbit@node3]}]},
       {running_nodes,[rabbit@node1,rabbit@node3]},
       {cluster_name,<<"rabbit@node1">>},
       {partitions,[]},
       {alarms,[{rabbit@node1,[]},{rabbit@node3,[]}]}]

       

    • 如果关闭了集群中的所有节点,则需要确保最先启动的是最后一个关闭的节点。如果不是,那么当前节点会等待最后一个关闭的节点启动后启动(默认等待时间是30秒/10次),如果没有等到,那么当前节点会启动失败。

      Error: timeout_waiting_for_tables

       

    • 如果最后一个关闭的节点最终由于异常无法启动,则可以通过rabbitmqctl forget_cluster_node命令剔除出当前集群。

      [root@node1 ~]# rabbitmqctl forget_cluster_node node1
      Removing node node1 from cluster

       

    • 如果由于某些非正常原因关闭了所有节点,此时需要调用rabbitmqctl force_boot命令来启动一个节点,之后集群才能正常启动。

      //假设最后关闭的node1节点异常无法启动,强制启动node2节点
      [root@node2 ~]# rabbitmqctl force_boot
      Forcing boot for Mnesia dir /..../rabbit@node2
      [root@node2 ~]# rabbitmq-server -detached

       

7.1.2 集群节点类型

  • 两种节点类型
    • 内存节点类型(ram):所有的队列、交换器、绑定关系、用户、权限和vhost的元数据的定义都存储在内存中。
      • 提供出色的性能。
    • 磁盘节点类型(disc):所有的队列、交换器、绑定关系、用户、权限和vhost的元数据的定义都存储在磁盘中。
      • 保证集群信息的高可靠性。
  • 使用rabbitmqctl cluster_status命令查看节点类型。
    [root@node1 ~]# rabbitmqctl cluster_status
    Cluster status of node rabbit@liuns
    [{nodes,[{disc,[rabbit@node1,rabbit@node2,rabbit@node3]}]},//其中disc标记了节点的类型
     {running_nodes,[rabbit@node1,rabbit@node2,rabbit@node3]},
     {cluster_name,<<"rabbit@node1">>},
     {partitions,[]},
     {alarms,[{rabbit@node1,[]},{rabbit@node2,[]},{rabbit@node3,[]}]}]

     

  • 节点类型设置
    • 节点加入集群的时候设置。
      //--ram参数表示内存节点,不加表示磁盘节点
      [root@node2 ~]# rabbitmqctl join_cluster node2 --ram
    • 修改集群中节点类型。
      //修改集群中节点类型
      [root@node2 ~]# rabbitmqctl stop_app
      [root@node2 ~]# rabbitmqctl change_cluster_node_type disc
      [root@node2 ~]# rabbitmqctl start_app
      [root@node2 ~]# rabbitmqctl cluster_status

       

  • RabbitMQ要求在集群中至少有一个磁盘节点,所以其他节点都可以是内存节点。
  • 内存节点重启后,它们会连接到预先配置的磁盘节点,下载当前集群元数据的副本。

7.1.3 剔除单个节点

  • 第一种方式,适合要剔除的节点没有运行RabbitMQ的情况。
    //假设node2节点异常终止,在node1上从集群中剔除node2
    [root@node1 ~]# rabbitmqctl forget_cluster_node node2

     

  • 第二种方式,RabbitMQ运行正常的节点上直接reset。
    //在node2节点服务器上,剔除node2节点
    [root@node2 ~]# rabbitmqctl stop_app
    [root@node2 ~]# rabbitmqctl reset //清空节点状态,并恢复到空白状态
    [root@node2 ~]# rabbitmqctl start_app
    
    //再查看集群状态时,node2节点已不再集群中
    [root@node2 ~]# rabbitmqctl cluster_status

     

7.1.4 集群节点升级

  1. 关闭所有节点的服务,注意采用rabbitmqctl stop命令关闭。
  2. 保存各个节点的Mnesia数据。
  3. 解压新版本RabbitMQ到指定的目录。
  4. 指定新版的Mnesia路径为步骤2中保存的Mnesia数据路径。
  5. 启动新版本服务,注意先启动原版本中最后关闭的那个节点。

7.1.5 单机多节点配置

  • 单台物理机部署多个RabbitMQ服务节点,需要确保每个节点都有独立的名称、数据存储位置、端口号(包括插件端口号)等。
  • 单机多节点配置主要用于实验性论证,生产环境最好使用多级多节点配置,不仅可以扩容,也能有效地进行容灾。
  • 部署流程:
    1. 为每个RabbitMQ服务配置不同的端口号和名称,如果有插件也要设置不同的端口号。
      //节点1
      [root@liuns rabbitmq]# RABBITMQ_NODE_PORT=5672 RABBITMQ_NODENAME=rabbit1 
      RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15672}]" 
      rabbitmq-server -detached
      
      //节点2
      [root@liuns rabbitmq]# RABBITMQ_NODE_PORT=5673 RABBITMQ_NODENAME=rabbit2 
      RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" 
      rabbitmq-server -detached
      
      //节点3
      [root@liuns rabbitmq]# RABBITMQ_NODE_PORT=5674 RABBITMQ_NODENAME=rabbit3 
      RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15674}]" 
      rabbitmq-server -detached
    2. 服务节点rabbit2、rabbit3加入到节点rabbit1的集群中。

      [root@liuns rabbitmq]# rabbitmqctl -n rabbit2@liuns stop_app
      [root@liuns rabbitmq]# rabbitmqctl -n rabbit2@liuns reset
      [root@liuns rabbitmq]# rabbitmqctl -n rabbit2@liuns join_cluster rabbit1@liuns
      [root@liuns rabbitmq]# rabbitmqctl -n rabbit2@liuns start_app
      [root@liuns rabbitmq]# rabbitmqctl cluster_status
    3. 配置完成。

    4. 1

7.2 查看服务日志

  • 日志文件存在$RABBITMQ_HOME/var/log/rabbitmq/目录下。
    • RABBITMQ_NODENAME-sasl.log记录Erlang相关的日志。
    • RABBITMQ_NODENAME.log记录RabbitMQ服务相关日志。
  • 日志级别(可以通过rabbitmq.conf配置中log_levels参数配置):
    • none 不记录日志
    • error 错误级别
    • warning 警告级别
    • info 通知级别(默认)
    • debug 调试级别
  • 日志切分/轮换 
    • rabbitmqctl rotate_logs {suffix} 命令可以切分/轮换日志文件,生成指定后缀suffix的日志文件备份。
      • 可以使用crontab已日志为后缀定期生成日志文件。
  • 日志查看方式
    • 人工查看日志文件,如cat RABBITMQ_NODENAME.log。
    • 程序化的方式查看。
      • RabbitMQ默认回创建一些交换器,其中amq.rabbitmq.log交换器(topic类型)就是用来收集RabbitMQ日志的,集群中所有日志(error、warning、info、debug)都会发往这个交换器。
      • 可以创建对接级别的队列(如queue.error或使用路由键“#”)绑定amq.rabbitmq.log交换器,消费端处理对应日志。
      • 对应级别的日志队列会收集每个节点的日志,不过这些日志是交错的,不能区分具体是哪个节点的日志。

7.3 单节点故障恢复

  • 单节点故障是指集群中单个节点发证了故障,有可能会引起进群服务不能用、数据丢失等异常。
  • 配置数据节点冗余(镜像队列)可以有效的防止由于单节点故障而降低整个集群的可用性、可靠性。
  • 单节点故障包括(部分):
    • 机器硬件故障,包括机器硬盘、内存、主板等故障造成的死机、无法从软件角度来恢复。
      • 需要在其他节点上执行rabbitmqctl forget_cluster_node {nodename}命令将故障节点剔除。
    • 机器掉电,因为断电导致节点服务器关闭,需要重启机器。
      • 此时RabbitMQ出入stop状态,重启机器后不要盲目启动Rabbitm服务,有可能引起网络分区。
      • 应先在其他节点上使用rabbitmqctl forget_cluster_node {nodename}剔除(同时需要删除Mnesia数据)或使用rabbitmqctl rest重置此节点,最后再将此节点作为一个新节点加入到集群中。
    • 网络异常,网线松动或网卡损坏都会引起网络故障的发生。
      • 建议先关闭故障机RabbitMQ进程,然后对网线或网卡更换或修改操作,之后再考虑是否重启开启RabbitMQ服务。
      • 网络修复之前不建议启动RabbitMQ服务,有可能会引起网络分区。
    • 服务进程异常,RabbitMQ进程非预期终止。
      • 需先思考相关风险是否可控,如果不可控,可以选择抛弃这个节点。
      • 一般重启RabbitMQ服务进程都可以解决。

7.4 集群迁移

  • RabbitMQ集群迁移包括:
    • 元数据重建,是指在新的集群中创建元集群的队列、交换器、绑定关系、vhost、用户、权限和参数等数据信息。
      • 手工重建元数据(耗时耗力,需要对元数据提前整理)。
      • Web管理界面重建元数据(简洁快速)。
        • 流程:Web首页->“Download broker definitions”按钮下载集群元数据信息JSON文件->新集群web页面点击“Upload broker definitions”按钮上传元数据JSON文件->完成。
    • 数据迁移和客户端连接的切换
      • 首先将生产者的客户端与原集群断开,并接入新的集群。
      • 消费端可以等到消费完原集群的队列消息后,在切换接入新的集群。
    • 自动化迁移
      • 可以通过将相应的资源加载到ZooKeeper的相应节点中,然后客户端为对应的资源节点加入watcher来感知变化。RabbitMQ实战指南笔记_第3张图片

7.5 集群监控

  • RabbitMQ Management插件的Web界面提供一定的监控功能,如发送速度、确认速度、消费速度、消息总数、磁盘读写速度、句柄数、Socket连接数、Connection数和Channel数、内存信息等。
  • RabbitMQ Management插件的HTTP API接口自定义自己的监控系统。

第8章 跨越集群的界限

8.1 Federation

  • Federation插件的设计目标是是RabbitMQ在不同的Broker节点之间进行消息传递而无需建立集群。
  • 没细看

8.2 Shovel

  • 与Federation具备的数据转发功能类似,Shovel能够可靠、持续地从一个Broker中的队列拉取数据并转发至另一个Broker中的交换器。
  • 没细看

第9章 RabbitMQ高阶

9.1 存储机制

  • 不管是持久化的消息还是非持久化的消息都可以被写入到磁盘中(在“持久层”中完成)。
    • 持久化的消息在到达队列时就被写入磁盘,并且如果可以也会在内存中保存一份备份,来提高一定的性能,当内存吃紧时会从内存中清除。
    • 非持久化的消息一般是在内存里,在内存吃紧时会被换入到磁盘中,以节省内存空间。
  • 持久层是个逻辑上的概念,实际包括两部分:
    • 队列索引(rabbit_queue_index):负责维护落盘消息的信息,包括消息的存储地点、是否已被交付给消费者、是否已被消费者ack等。
      • 每个队列都有与之对应的一个队列索引。
    • 消息存储(rabbit_msg_store):以键值对的形式存储消息,每个节点中有且只有一个,它被节点上的所有队列共享。技术层面还可以分为:
      • msg_store_persistent(持久消息存储):负责持久化消息的存储,重启后消息不会丢失。
      • msg_store_transient(非持久消息存储):负责非持久消息存储,重启后消息会丢失。
  • 消息(包括消息体、属性和headers)即可存在rabbit_queue_index中,也可以存在rabbit_msg_store中。
    • 存储目录在$RABBITMQ_HOME/var/lib/mnesia/rabbit@$HOSTNAME/下的queus、msg_store_persistent、msg_store_transient文件夹下。
    • 较小的消息存储在rabbit_queue_index中,而较大的消息存储在rabbit_msg_store中。
      • 消息大小的界定通过queue_index_embed_msgs_below来配置,默认值4096B。
      • 消息的大小是指消息体、属性和headers整体的大小。
  • 队列的结构RabbitMQ实战指南笔记_第4张图片
    • 队列主要由两部分组成:
      • rabbit_amqqueue_process:负责协议相关的消息处理,即接收生产者发布的消息、向消费者交付消息、处理消息的确认等。
      • backing_queue:是消息存储的具体形式和引擎,并向rabbit_amqqueue_process提供相关的接口以供调用。其内部通过5个子队列(Q1、Q2、Delta、Q3、Q4)来体现消息的各个状态:
        • Q1、Q4只包含alpha状态的消息。
        • Delta 只包含delta状态的消息。
        • Q2、Q3包含beta和gamma状态的消息。
        • 一般情况下消息按照Q1->Q2->Delta->Q3->Q4的顺序步骤进行流动,但不是每条消息都会经历所有状态,这取决于当前系统的负载状况。
    • RabbitMQ中队列消息的四种状态:
      • alpha:消息内容(包括消息体、属性和headers)和消息索引都存储在内存中。
      • beta:消息内容保存在磁盘中,消息索引保存在内存中。
      • gamma:消息内容保存在磁盘中,消息索引在磁盘和内存中都有(只有持久化的消息才会有的状态)。
      • delta:消息内容和消息索引都存在磁盘中。

         

  • 惰性队列
    • RabbitMQ从3.6.0版本引入惰性队列(Lazy Queue)的概念。
    • 惰性队列会尽可能的将消息写入磁盘中,而在需要的时候才会被载到内存中。
    • 惰性队列的主要目标是支持更长的队列,即支持更多的消息存储。
    • 队列的两种模式:
      • default模式:默认模式。
      • lazy模式,即为惰性队列模式。
    • 在声明队列的时候可以通过“x-queue-mode”参数设置队列模式,取值为default和lazy。
    • 惰性队列和普通队列相比,只有很小的内存开销。

9.2 内存及磁盘警告

  • 当内存使用超过配置的阈值或磁盘空间低于配置的阈值时,RabbitMQ都会暂时阻塞客户端的连接(Connection)并停止接收从客户端发来的消息,直到对应项恢复正常,以此避免服务崩溃。
    • rabbitmqctl list_connections 命令 查看Connection阻塞状态,State状态要么是blocking,要么是blocked。
  • 内存告警
    • RabbitMQ默认内存阈值是0.4,即40%,这并不意味着不能使用超过40%的内存,这仅仅只是显示了RabbitMQ的消息生产者。
    • 内存阈值设置方式:
      • rabbitmq.conf配合文件的vm_memory_high_watermark设置。
      • rabbitmqctl set_vm_memory_high_watermark {fraction} 或 rabbitmqctl set_vm_memory_high_watermark absolute {memory_limit}命令行设置(服务重启会失效)。
    • 正常情况建议内存阈值设置在0.4~0.66之间,不建议超过0.7。
    • 如果内存阈值设置为0,所有生产者都会被停止发送消息。这个功能适用于需要禁止集群中所有消息发布的情况。
    • 内存阈值即可以是百分比,也可以是绝对值(单位是B\KB\MB\GB)。
    • 当节点触及内存并阻塞生产者之前,他会尝试将队列中的消息换页到磁盘以释放内存空间。
      • 默认情况下,在内存达到内存阈值的50%时会进行换页动作,即内存阈值是0.4时,当内存超过0.4x0.5=0.2时会进行换页操作。
      • 触发换页操作的设置方式:
        • 通过rabbitmq.conf配置文件中vm_memory_high_watermark_pagind_ratio项修改,默认值是0.5。
        • 通过rabbitmqctl vm_memory_high_watermark_pagind_ratio {xxx}命令设置(服务重启会失效)。
      • 当vm_memory_high_watermark_pagind_ratio设置为大于1的浮点数时,表示禁用了换页功能。
  • 磁盘告警

    • 当剩余的磁盘空间低于预定的阈值时,同样会阻塞生产者发送消息,这样可以避免非持久化的消息持续换页而耗尽磁盘空间导致服务崩溃。
    • 磁盘阈值设置方式:
      • rabbitmq.conf配置文件的disk_free_limit项配置,默认是50MB。
      • rabbimqctl set_disk_free_limit {disk_limit} 或 rabbimqctl set_disk_free_limit mem_relative {fraction}命令行设置(服务重启会失效)。(mem_relative建议取值范围1.0~2.0之间)。
    • 磁盘阈值的大小相对谨慎的做法是与系统所显示的内存大小一致。

9.3 流控(Flow Control)

  • 流控机制是用来避免消息的发送速率过快而导致服务器难以支撑的情形。
  • 流控机制可以作用于连接(Connection)、信道(Channel)和队列(Queue)。内存和磁盘告警相当于全局流控(Global Flow Control)。
  • RabbitMQ使用一种基于信用证算法(credit-based algorithm)的流控机制来限制发送消息的速率。(什么时候信用证算法?)

9.4 镜像队列

  • 镜像队列(Mirror Queue)机制,是将队列镜像到集群中的其他Broker节点上,如果集群中的一个节点失效了,队列能自动的切换到镜像中其他Broker节点上以保证服务的可用性。
  • 每一个配置镜像的队列都包含一个master节点和若干个slave节点。
  • 如果master节点失效,name“资历最老”的slave节点会被提升为新的master节点,时间最长的slave即为“资历最老”。
  • 生产者会向所有节点发送消息,除发送消息外的所有动作都只会想master发送,然后由master广播给其他slave节点。
  • 如果消费者与slave建立连接并进行订阅消费,其本质上都是从master上获取消息,只不过看似从slave上消费而已。大致流程是:消费者请求->slave1->master->slave1->返回消费者。slave只是转发或代理。
  • 镜像队列配置主要是通过添加响应的Policy来完成。
    //配置镜像队列命令
    //rabbitmqctl set_policy [-p ] [--priority ] [--apply-to ]
       
    definition中需要包含3部分:
    1、ha-mode:指明镜像队列模式,有效值[all|exactly|nodes],默认all。
        all:表示在所有节点上镜像;
        exactly:表示在指定节点数上镜像,节点个数由ha-params指定;
        nodes:表示在指定的节点上镜像,节点名称由ha-params指定、
    2、ha-params:不同的ha-mode配置中需要用到的参数。
    3、ha-sync-mode:队列消息的同步方式,有效值[automatic|manual]。
        automatic时,新加入的slave会默认同步已知的镜像队列。
        manual时,需要手动同步将享队列。
    
    //举例,对队列名称以“queue_”开头的所有队列进行镜像,并在集群的2个节点上完成镜像
    [root@node1 ~]#rabbitmqctl set_policy --prioriry 0 --apply-to queues mirror_queue "^queue_" 
    '{"ha-mode":"all","ha-params":2,"ha-sync-mode":"automatic"}'
    
    //查看哪些slave已经完成同步命令
    //rabbitmqctl list_queues {name} slave_pids synchronised_slave_pids
    [root@node1 ~]#rabbitmqctl list_queues mirror_queue slave_pids synchronised_slave_pids
    
    //手动方式同步slave命令
    //rabbitmqctl sync_queue {name}
    [root@node1 ~]#rabbitmqctl sync_queue mirror_queue
    

     

第10章 网络分区

10.1 网络分区的意义

10.2 网络分区的判定

10.3 网络分区的模拟

10.4 网络分区的影响

  • 未配置镜像
  • 已配置镜像

10.5 手动处理网络分区

10.6 自动处理网络分区

第11章 RabbitMQ扩展

11.1 消息追踪

  • Firehose
  • rabbitmq_tracing插件

11.2 负载均衡

  • 客户端内部实现负载均衡
  • 使用HAProxy实现负载均衡
  • 使用Keeplived实现高可靠负载均衡
  • 使用Keeplived+LVS实现负载均衡

 

 

你可能感兴趣的:(RabbitMQ,RabbitMQ,消息队列,RabbitMQ实战指南)