logo资料库

Centos6.9下RabbitMQ高可用集群完整部署记录(个人精华版).doc

第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
资料共19页,剩余部分请下载后查看
之前简单介绍了 CentOS 下单机部署 RabbltMQ 环境的操作记录,下面详细说下 RabbitMQ 集群知识, RabbitMQ 是用 erlang 开发的,集群非常方便,因为 erlang 天生就是一门分布式语言,但其本身并不支持负载 均衡。 Rabbit 集群模式大概分为以下三种:单一模式、普通模式、镜像模式,其中: 1)单一模式:最简单的情况,非集群模式,没什么好说的。 2)普通模式:默认的集群模式。 -> 对于 Queue 来说,消息实体只存在于其中一个节点,A、B 两个节点仅有相同的元数据,即队列结构。 -> 当消息进入 A 节点的 Queue 中后,consumer 从 B 节点拉取时,RabbitMQ 会临时在 A、B 间进行消息传 输,把 A 中的消息实体取出并经过 B 发送给 consumer。 -> 所以 consumer 应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连 A 或 B,出口总在 A,会产生瓶颈。 -> 该模式存在一个问题就是当 A 节点故障后,B 节点无法取到 A 节点中还未消费的消息实体。 -> 如果做了消息持久化,那么得等 A 节点恢复,然后才可被消费;如果没有持久化的话,然后就没有然后了。 3)镜像模式:把需要的队列做成镜像队列,存在于多个节点,属于 RabbitMQ 的 HA 方案。 -> 该模式解决了上述问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在 consumer 取数据时临时拉取。 -> 该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群 内部的网络带宽将会被这种同步通讯大大消耗掉。 -> 所以在对可靠性要求较高的场合中适用于该模式(比如下面图中介绍该种集群模式)。 RabbitMQ 集群中的基本概念: 1)RabbitMQ 的集群节点包括内存节点、磁盘节点。顾名思义内存节点就是将所有数据放在内存,磁盘节点将 数据放在磁盘。不过,如前文所述,如果在投递消息时,打开了消息的持久化,那么即使是内存节点,数据还是 安全的放在磁盘。 2)一个 rabbitmq 集 群中可以共享 user,vhost,queue,exchange 等,所有的数据和状态都是必须在所有 节点上复制的,一个例外是,那些当前只属于创建它的节点的消息队列,尽管它们可见且可被所有节点读取。 rabbitmq 节点可以动态的加入到集群中,一个节点它可以加入到集群中,也可以从集群环集群会进行一个基本 的负载均衡。 RabbitMQ 集群中有两种节点: 1)Ram 内存节点:只保存状态到内存(一个例外的情况是:持久的 queue 的持久内容将被保存到 disk) 2)Disk 磁盘节点:保存状态到内存和磁盘。 内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。RabbitMQ 集群中,只需要一个磁盘节点来保存状态就 足够了;如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。 RabbitMQ 集群思路: 那么具体如何实现 RabbitMQ 高可用,我们先搭建一个普通集群模式,在这个模式基础上再配置镜像模式实现 高可用,Rabbit 集群前增加一个反向代理,生产者、消费者通过反向代理访问 RabbitMQ 集群。
上图中 3 个 RabbitMQ 运行在同一主机上,分别用不同的服务端口。当然在生产环境里,多个 RabbitMQ 肯定 是运行在不同的物理服务器上,否则就失去了高可用的意义。 RabbitMQ 集群: 1)RabbitMQ broker 集群是多个 erlang 节点的逻辑组,每个节点运行 rabbitmq 应用,他们之间共享用户、 虚拟主机、队列、exchange、绑定和运行时参数; 2)RabbitMQ 集群之间复制什么信息:除了 message queue(存在一个节点,从其他节点都可见、访问该队 列,要实现 queue 的复制就需要做 queue 的 HA)之外,任何一个 rabbitmq broker 上的所有操作的 data 和 state 都会在所有的节点之间进行复制; 3)RabbitMQ 消息队列是非常基础的关键服务。本文 3 台 rabbitMQ 服务器构建 broker 集群,1 个 master,2 个 slave。允许 2 台服务器故障而服务不受影响。 RabbitMQ 集群的目的 1)允许消费者和生产者在 RabbitMQ 节点崩溃的情况下继续运行 2)通过增加更多的节点来扩展消息通信的吞吐量 RabbitMQ 集群运行的前提: 1)集群所有节点必须运行相同的 erlang 及 rabbitmq 版本 2)hostname 解析,节点之间通过域名相互通信,本文为 3 个 node 的集群,采用配置 hosts 的形式。 RabbitMQ 端口及用途 1)5672 客户端连接用途 2)15672 web 管理接口 3)25672 集群通信用途
RabbitMQ 集群的搭建方式: 1)通过 rabbitmqctl 手工配置 (本文采用此方式) 2)通过配置文件声明 3)通过 rabbitmq-autocluster 插件声明 4)通过 rabbitmq-clusterer 插件声明 RabbitMQ 集群故障处理机制: 1)rabbitmq broker 集群允许个体节点 down 机, 2)对应集群的的网络分区问题( network partitions) RabbitMQ 集群推荐用于 LAN 环境,不适用 WAN 环境;要通过 WAN 连接 broker,Shovel or Federation 插件是最佳的解决方案;Shovel or Federation 不同于集群。 RabbitMQ 集群的节点运行模式: 为保证数据持久性,目前所有 node 节点跑在 disk 模式,如果今后压力大,需要提高性能,考虑采用 ram 模式 RabbitMQ 节点类型 1)RAM node:内存节点将所有的队列、交换机、绑定、用户、权限和 vhost 的元数据定义存储在内存中,好 处是可以使得像交换机和队列声明等操作更加的快速。 2)Disk node:将元数据存储在磁盘中,单节点系统只允许磁盘类型的节点,防止重启 RabbitMQ 的时候,丢 失系统的配置信息。 问题说明: RabbitMQ 要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必 须要将该变更通知到至少一个磁盘节点。 如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到 节点恢复。 解决方案:设置两个磁盘节点,至少有一个是可用的,可以保存元数据的更改。 RabbitMQ 集群节点之间是如何相互认证的: 1)通过 Erlang Cookie,相当于共享秘钥的概念,长度任意,只要所有节点都一致即可。 2)rabbitmq server 在启动的时候,erlang VM 会自动创建一个随机的 cookie 文件。cookie 文件的位置是 /var/lib/rabbitmq/.erlang.cookie 或者 /root/.erlang.cookie,为保证 cookie 的完全一致,采用从一个节 点 copy 的方式。 Erlang Cookie 是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的 Erlang Cookie。具体的目录存放在/var/lib/rabbitmq/.erlang.cookie。 说明:这就要从 rabbitmqctl 命令的工作原理说起,RabbitMQ 底层是通过 Erlang 架构来实现的,所以 rabbitmqctl 会启动 Erlang 节点,并基于 Erlang 节点来使用 Erlang 系统连接 RabbitMQ 节点,在连接过程 中需要正确的 Erlang Cookie 和节点名称,Erlang 节点通过交换 Erlang Cookie 以获得认证。 =======以下记录 CentOS6.9 下 RabbitMQ 集群部署过程 ======= 集群机器信息: rabbitmq01.kevin.cn rabbitmq02.kevin.cn rabbitmq03.kevin.cn 192.168.1.40 192.168.1.41 192.168.1.42 1)设置 hosts 主机解析,rabbitmq 集群通信用途,所有节点配置相同。 [root@rabbitmq01 ~]# cat /etc/hosts
localhost localhost.localdomain localhost4 localhost4.localdomain4 localhost localhost.localdomain localhost6 localhost6.localdomain6 127.0.0.1 ::1 192.168.1.40 rabbitmq01.kevin.cn 192.168.1.41 rabbitmq02.kevin.cn 192.168.1.42 rabbitmq03.kevin.cn 其他两个节点的 hosts 配置一致。 2)三台节点服务器上都要部署 rabbitmq 环境,可以参考: http://www.cnblogs.com/kevingrace/p/7693042.html 前台运行 rabbitmq 服务: # /etc/init.d/rabbitmq-server start 或者 (用户关闭连接后,自动结束进程) # rabbitmq-server start 设置开机启动 # chkconfig rabbitmq-server on 后台运行 rabbitmq 服务: # rabbitmq-server -detached # lsof -i:5672 # lsof -i:15672 # lsof -i:25672 查看各节点状态: # rabbitmqctl status 或者 # /etc/init.d/rabbitmq-server status 3)设置节点间认证的 cookie。可以把其中一个节点(比如 rabbitmq01)的文件使用 scp 拷贝到其他两个节点上 [root@rabbitmq01 ~]# cat /var/lib/rabbitmq/.erlang.cookie FXQTFVXIUWEBZRLXFQOZ [root@rabbitmq02 ~]# cat /var/lib/rabbitmq/.erlang.cookie
FXQTFVXIUWEBZRLXFQOZ [root@rabbitmq03 ~]# cat /var/lib/rabbitmq/.erlang.cookie FXQTFVXIUWEBZRLXFQOZ 同步完 cookie 之后,重启 rabbitmq-server。 # /etc/init.d/rabbitmq-server restart 4)为了把集群中的 3 个节点联系起来,可以将其中两个节点加入到另一个节点中。 比如:将 rabbitmq01、rabbitmq03 分别加入到集群 rabbitmq02 中,其中 rabbitmq01 和 rabbitmq02 节点 为内存节点。rabbitmq02 为磁盘节点。 注意:rabbitmqctl stop_app ---仅关闭应用,节点不被关闭 [root@rabbitmq01 ~]# rabbitmqctl stop_app [root@rabbitmq01 ~]# rabbitmqctl join_cluster --ram rabbit@rabbitmq02 [root@rabbitmq01 ~]# rabbitmqctl start_app [root@rabbitmq03 ~]# rabbitmqctl stop_app [root@rabbitmq03 ~]# rabbitmqctl join_cluster --ram rabbit@rabbitmq02 [root@rabbitmq03 ~]# rabbitmqctl start_app 查看 RabbitMQ 集群情况(三个节点查看的结果一样) [root@rabbitmq01 ~]# rabbitmqctl cluster_status Cluster status of node rabbit@rabbitmq01 ... [{nodes,[{disc,[rabbit@rabbitmq02]}, {ram,[rabbit@rabbitmq03,rabbit@rabbitmq01]}]}, {running_nodes,[rabbit@rabbitmq03,rabbit@rabbitmq02,rabbit@rabbitmq01]}, {cluster_name,<<"rabbit@rabbitmq02.kevin.cn">>}, {partitions,[]}, {alarms,[{rabbit@rabbitmq03,[]}, {rabbit@rabbitmq02,[]}, {rabbit@rabbitmq01,[]}]}] RabbitMQ 集群的名字默认是第一个节点的名字,比如上面集群的名字是 rabbitmq01。
修改 RabbitMQ 集群的名字 kevinmq # rabbitmqctl set_cluster_name kevinmq # rabbitmqctl cluster_status 重启集群: # rabbitmqctl stop # rabbitmq-server -detached # rabbitmqctl cluster_status //观察集群的运行状态变化 5)重要信息: 当整个集群 down 掉时,最后一个 down 机的节点必须第一个启动到在线状态,如果不是这样,节点会等待 30s 等最 后的磁盘节点恢复状态,然后失败。 如果最后下线的节点不能上线,可以通过 forget_cluster_node 指令来踢出集群。 如果所有的节点不受控制的同时宕机,比如掉电,会进入所有的节点都会认为其他节点比自己宕机的要晚,即自己先宕 机,这种情况下可以使用 force_boot 指令来启动一个节点。 6)打破集群: 当一个节点不属于这个集群的时候,需要及时踢出,可以通过本地或者远程的方式 # rabbitmqctl stop_app # rabbitmqctl reset # rabbitmqctl start_app 这样再次查看 RabbitMQ 集群的时候,该节点就不会在这里面了 # rabbitmqctl cluster_status 7)客户端连接集群测试 通过 web 管理页面进行创建队列、发布消息、创建用户、创建 policy 等。 http://192.168.1.41:15672/ 或者通过 rabbitmqadmin 命令行来测试 [root@rabbitmq02 ~]# wget https://192.168.1.41:15672/cli/rabbitmqadmin
[root@rabbitmq02 ~]# chmod +x rabbitmqadmin [root@rabbitmq02 ~]# mv rabbitmqadmin /usr/sbin/ Declare an exchange [root@rabbitmq02 ~]# rabbitmqadmin declare exchange name=my-new-exchange type=fanout exchange declared Declare a queue, with optional parameters [root@rabbitmq02 ~]# rabbitmqadmin declare queue name=my-new-queue durable=false queue declared Publish a message [root@rabbitmq02 ~]# rabbitmqadmin publish exchange=my-new-exchange routing_key=test payload="hello, world" Message published And get it back | payload_encoding | [root@rabbitmq02 ~]# rabbitmqadmin get queue=test requeue=false +-------------+----------+---------------+--------------+------------------+---------- ---+ | routing_key | exchange | message_count | payload redelivered | +-------------+----------+---------------+--------------+------------------+---------- ---+ | test | +-------------+----------+---------------+--------------+------------------+---------- ---+ 测试后发现问题问题: [root@rabbitmq01 ~]# rabbitmqctl stop_app [root@rabbitmq01 ~]# rabbitmqctl stop 在 stop_app 或者 stop 掉 broker 之后在 rabbitmq01 节点的上队列已经不可用了,重启 rabbitmq01 的 app 或 broker 之后,虽然集群工作正常,但 rabbitmq01 上队列中消息会被清空(queue 还是存在的) | hello, world | string | | 0 | False 对于生产环境而已,这肯定是不可接受的,如果不能保证队列的高可用,那么做集群的意义也不太大了,还好 rabbitmq 支持 Highly Available Queues,下面介绍下 queue 的 HA。
=================Queue HA 配置=============== 默认情况下,RabbitMQ 集群中的队列存在于集群中的单个节点上,这要看创建队列时声明在那个节点上创建, 而 exchange 和 binding 则默认存在于集群中所有节点。 队列可以通过镜像来提高可用性,HA 依赖 rabbitmq cluster,所以队列镜像也不适合 WAN 部署,每个被镜像 的队列包含一个 master 和一个或者多个 slave,当 master 因任何原因故障时,最老的 slave 被提升为新的 master。发布到队列的消息被复制到所有的 slave 上,消费者 无论连接那个 node,都会连接到 master;如果 master 确 认要删除消息,那么所有 slave 就会删除队列中消息。队列镜像可以提供 queue 的高可用性,但不能分担负 载,因为所有参加的节点都做所有的工作。 1. 配置队列镜像 通过 policy 来配置镜像,策略可在任何时候创建,比如先创建一个非镜像的队列,然后在镜像,反之亦然。 镜像队列和非镜像队列的区别是非镜像队列没有 slaves,运行速度也比镜像队列快。 设置策略,然后设置 ha-mode,3 种模式:all、exactly、nodes。 每个队列都有一个 home node,叫做 queue master node 1)设置 policy,以 ha.开头的队列将会被镜像到集群其他所有节点,一个节点挂掉然后重启后需要手动同步队 列消息 1 # rabbitmqctl set_policy ha-all-queue "^ha\." '{"ha- mode":"all"}' 2)设置 policy,以 ha.开头的队列将会被镜像到集群其他所有节点,一个节点挂掉然后重启后会自动同步队列消 息(生产环境采用这个方式) 1 # rabbitmqctl set_policy ha-all- queue "^ha\." '{"ha- mode":"all","ha- sync- mode":"automatic"}' 2. 问题: 配置镜像队列后,其中 1 台节点失败,队列内容是不会丢失,如果整个集群重启,队列中的消息内容仍然丢失, 如何实现队列消息内容持久化那? 集群节点跑在 disk 模式,创建见消息的时候也声明了持久化,为什么还是不行那? 因为创建消息的时候需要指定消息是否持久化,如果启用了消息的持久化的话,重启集群消息也不会丢失了,前 提是创建的队列也应该是创建的持久化队列。
分享到:
收藏