RabbitMQ指南(二)

2020-11-17  本文已影响0人  纳样流年

一、多租户与权限

每一个RabbitMQ服务器都能创建虚拟的服务器主机(vhost)。每个vhost都有用自己独立的队列,交换机,绑定关系,权限等等。客户端在连接的时候必须指定一个vhost,默认的vHost是/
rabbitmqctl命令标准格式

rabbitmqctl [-n node] [-t timeout] [-q] {command} [command options] //[] 表示可选参数,{}表示必选参数
租户与权限相关的命令
rabbitmqctl add_vhost {vhost}
rabbitmqctl list_vhosts {vhostinfoitem...}
rabbitmqctl delete_vhost {vhost}
rabbitmqctl set_permissions {-p vhost} {username} {conf} {write} {read}
rabbitmqctl clear_permissions {-p vhost} {username}
rabbitmqctl list_permissions {-p vhost}
rabbitmqctl list_user_permissions {username}

二、用户管理

在RabbitMQ中,用户是访问控制的基本单元,且单个用户可以跨越多个vhost授权。针对一至多个vhost,用户可以被授权不同的访问权限。

用户相关指令
rabbitmqctl add_user {username} {password}
rabbitmqctl change_password {username} {password}
rabbitmqctl clear_password {username} {password}
rabbitmqctl authenticate_user{username} {password} 
rabbitmqctl list_users
rabbitmqctl delete_user {username}

用户角色分为5类:

三、应用管理

四、集群管理

RabbitMQ集群允许消费者和生产者在RabbitMQ单点崩溃的情况下继续运行,也可以通过添加更多的节点来线性的扩展消息通信的吞吐量。当失去一个RabbitMQ节点时,客户端能过重新连接到集群中的任何一个其他的节点,并继续生产或消费。

RabbitMQ集群对延迟非常敏感的,应当只用于局域网。广域网应该使用Federation或者Shovel来代替。

RabbitMQ集群不能保证消息的万无一失。当集群中的一个RabbitMQ节点崩溃时,该节点上的所有消息也会丢失。RabbitMQ集群中的所有节点都会备份所有的元数据信息,元数据包括如下内容

RabbitMQ在集群中创建队列,集群只会在单个节点而不是所有节点上创建该队列的进程,只有该节点包含完整的队列信息(元数据,状态,内容)。这样只有队列的宿主(队列的所有者)知道队列的所有信息,其他的节点只知道队列的元数据和指向该队列的指针。因此,当集群中某个节点崩溃的时候,该节点上的队列进程和关联的绑定都会消失。该队列上的所有的订阅都会失效,并且任何匹配该队列的新消息也会丢失。那么为何RabbitMQ集群仅采用元数据同步的方式?

  1. 存储空间:如果每个集群节点都拥有所有Queue的完全数据拷贝,那么每个节点的存储空间会非常大,集群的消息积压能力会非常弱(无法通过集群节点的扩容提高消息积压能力);
  2. 性能:消息的发布者需要将消息复制到每一个集群节点,对于持久化消息,网络和磁盘同步复制的开销都会明显增加。

集群发送/订阅消息的基本原理

RabbitMQ集群的工作原理图如下:


RabbitMQ集群工作原理
一、客户端直接连接队列所在节点
二、客户端连接的是非队列数据所在节点

集群命令

集群节点类型

集群中的节点有两种类型:

单个集群中必须至少有一个磁盘类型的节点,否则RabbitMQ重启之后,所有的系统配置信息都会丢失。节点类型涉及如下指令:

rabbitmqctl join_cluster name --{ram,disc}
rabbitmqctl change_cluster_node_type {ram,disc}

在集群中创建队列,交换机或绑定关系时候,这些操作直到所有集群节点都成功提交元数据后才会返回。

RabbitMQ只要求在集群中至少有一个磁盘节点。如果集群中的所有磁盘节点均崩溃了,那么集群可以继续发送或者接收消息,但是不再可以执行创建队列,交换机,绑定关系,用户等操作
在内存节点重启后,它们会连接到预先配置的磁盘节点,下载当前集群元数据的副本。只要内存节点在集群中可以找到一个磁盘节点,那么就可以加入到集群中。

剔出集群中的单个节点

方法一
  1. 在节点上执行rabbitmqctl stop_apprabbitmqctl stop关闭RabbitMQ服务。
  2. 在集群中其他的节点上执行rabbitmqctl forget_cluster_node nodexxx
  3. 如果集群中其他的节点处于未运行的状态,那么需要使用rabbitmqctl forget_cluster_node nodexxx --offline,添加offline参数让起可以在非运行状态下提出节点
方法二
  1. 在节点上执行rabbitmqctl stop_app
  2. 在节点上执行rabbitmqctl reset

reset命令将情况节点的状态,让其恢复到空白状态(该指令会清除节点上的包括消息在内的全部数据),并通知集群中其他的节点该节点正在离开集群。

集群节点升级

如果集群中多个节点升级,可以参考单个节点的升级的方式。

  1. 使用rabbitmqctl stop关闭所有节点的的RabbitMQ服务
  2. 保存各个节点的Mnesia数据
  3. 解压新版本的RabbitMQ到指定目录
  4. 指定新版本的Mnesia数据路径为旧版本备份路径(步骤2)
  5. 启动新版本服务。(最先启动最后关闭的那个节点)

集群注意事项

  1. 如果关闭了集群中的所有节点,那么在启动的时候,需要确保最后关闭的那台节点是要最先启动的,因为这个节点知道最多的事情。如果第一个启动的不是最后关闭的节点,那么这个节点也会等待(30秒,重试10次)最后关闭的那个节点启动。在重试失败之后,当前节点也会因为失败而关闭自身的应用,报错信息如下(例子):
BOOT FAILED
===========
Timeout contacting cluster nodes: [rabbit@node3,rabbit@node2].

BACKGROUND
==========

This cluster node was shut down while other nodes were still running.
To avoid losing data, you should start the other nodes first, then
start this one. To force this node to start, first invoke
"rabbitmqctl force_boot". If you do so, any changes made on other
cluster nodes after this one was shut down may be lost.

DIAGNOSTICS
===========

attempted to contact: [rabbit@node3,rabbit@node2]

rabbit@node3:
  * unable to connect to epmd (port 4369) on node3: address (cannot connect to host/port)

rabbit@node2:
  * unable to connect to epmd (port 4369) on node2: address (cannot connect to host/port)

Current node details:
 * node name: rabbit@node1
 * effective user's home directory: /var/lib/rabbitmq
 * Erlang cookie hash: 753AvTJhsnDYrMG0hQ3YTg==
  1. 如果最后关闭的节点因为某种原因无法启动,则可以通过rabbitmqctl_forget_cluster_node来将其踢出集群。
  2. 如果集群中的所有节点由于某种原因,比如集群断电而关闭,那么集群中所有节点均会认为还有其他节点在其之后关闭,此时需要调用rabbitmqctl forec_boot来强制启动一个节点,之后集群才能正常启动。

五、集群迁移

RabbitMQ集群迁移主要包括三个步骤:元数据重建数据迁移客户端连接的切换

元数据重建

元数据重建是指在新的集群中创建原集群的队列,交换机,绑定关系,vhost,用户,权限和Parameter等数据的信息。元数据重建是其他迁移步骤的前置任务。
有多种方法可以完成元数据重建,比如通过手动创建,或编写客户端程序。RabbitMQ推荐的方式是通过Web管理页面的Export/Import definitions功能来完成。
但是Web管理页面迁移元数据的方式也有一些局限性,比如:

  1. RabbitMQ版本兼容。
  2. 需要使用RabbitMQ Management插件。
  3. 采用这种方法将元数据在新集群上重建,则所有的队列都只会落到同一个集群的节点上,而其他节点处于空置状态,这样所有的压力都会集中在单台节点之上。

数据迁移

数据迁移的具体策略要参考具体的业务场景。

  1. 将生产者的客户端与原RabbitMQ集群断开,再与新的集群建立新的连接,这样新的消息会投递到新的集群中。
  2. 消费者客户端等待原集群中的消息全部消费完毕,然后断开连接,最后与新集群建立连接。

某些场景中需要将消费者迅速切换到新集群,这会导致原集群中遗留部分未被消费的消息。这种情况可以通过编写“中转”程序来解决(从原集群中消费消息,并作为生产者将消息投递到新集群中)

六、备份与还原

每个RabbitMQ节点都有一个数据目录(data directory),该目录存储该节点上的所有数据。数据包含两种类型:definitions(元数据,架构/拓扑)消息存储(messages数据。

Definitions

节点和群集存储架构,元数据或拓扑等数据信息(用户,虚拟主机,队列,交换,绑定,运行时参数都属于此类) 。definitions数据可以作为JSON文件导出和导入。
definitions存储在节点内部数据库中,并在所有群集节点之间复制。 集群中的每个节点都有一份完整的集群数据备份。 当definitions的一部分更改时,所有节点均将再一个事务内完成数据的更新。这就意味着从集群中的任何一个节点,都已获取到集群的完整definitions数据。

Messages

每个节点都有自己的数据目录,并存储其主节点(镜像队列涉及主节点)托管在该节点上的队列的消息。 messages可以在镜像队列的各个节点之间复制。messages存储在节点数据目录的子目录中。

Data Lifecycle

definitions通常大多是静态的,而messages 却不断地从发布者流向消费者。执行备份时,第一步是确定是否仅备份definitions或是一同备份messages。 由于messages是短暂的并且可能是瞬态的,因此不要从正在运行的节点下对其进行备份,并且可能导致数据快照不一致。definitions只能从正在运行的节点上备份。

Definitions备份

definitions数据可以通过导入或导出的方式进行备份,尽可能的使用这种方式来备份definitions数据。具体方法参考指导教程
也可以通过手动的方式进行definitions数据备份,但是不推荐这样做。
Definitions are stored in an internal database located in the node's data directory. To get the directory path, run the following command against a running RabbitMQ node:

rabbitmqctl eval 'rabbit_mnesia:dir().'

如上指令输出的数据目录还将在子目录中包含messages数据。 如果不需要拷贝messages数据,可以不拷贝messages文件夹。

Restoring from a Manual Definitions Backup

Messages备份

在备份messages数据前,需要将节点停止。messages数据目前只能通过手动的方式进行备份。

In RabbitMQ versions starting with 3.7.0 all messages data is combined in the msg_stores/vhosts directory and stored in a subdirectory per vhost. Each vhost directory is named with a hash and contains a .vhost file with the vhost name, so a specific vhost's message set can be backed up separately.

从Rabbitmq3.7.0开始,所有的消息数据都被合并到msg_stores/vhosts 文件夹中,并且每一个vhost会以子文件夹的形式单独存储。每一个vhost文件夹都是以hash值的方式命名,文件夹内包含一个以vhost名字命名的.vhost的文件。因此,每一个vhost的messages数据都可以独立备份。

Restoring from a Manual Messages Backup

上一篇下一篇

猜你喜欢

热点阅读