一、前提
- erlang安装版本一致
- RabbitMQ安装版本一致
- 下面的例子以192.168.73.134与192.168.73.135为服务器搭建Rabbitmq集群.
二、RabbitMQ集群
RabbitMQ是用erlang开发的,集群非常方便,因为erlang天生就是一门分布式语言,但其本身并不支持负载均衡。Rabbit模式大概分为以下三种:单一模式、普通模式、镜像模式。
-
单一模式:最简单的情况,非集群模式。
-
普通模式:默认的集群模式。
对于Queue来说,消息实体只存在于其中一个节点,A、B两个节点仅有相同的元数据,即队列结构。 当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer。 所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连A或B,出口总在A,会产生瓶颈。 该模式存在一个问题就是当A节点故障后,B节点无法取到A节点中还未消费的消息实体。 如果做了消息持久化,那么得等A节点恢复,然后才可被消费;如果没有持久化的话,然后就没有然后了……
-
镜像模式:把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案。
该模式解决了上述问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。 该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。 所以在对可靠性要求较高的场合中适用(后面会详细介绍这种模式,目前我们搭建的环境属于该模式)。
2.1 集群中的基本概念
RabbitMQ的集群节点包括内存节点、磁盘节点。
顾名思义内存节点就是将所有数据放在内存,磁盘节点将数据放在磁盘。不过,如前文所述,如果在投递消息时,打开了消息的持久化,那即使是内存节点,数据还是安全的放在磁盘。
一个RabbitMQ集群中可以共享user、vhost、queue、exchange等,所有的数据和状态都是必须在所有节点上复制的,一个例外是那些当前只属于创建它的节点的消息队列,尽管它们可见且可被所有节点读取。RabbitMQ节点可以动态地加入到集群中,一个节点它可以加入到集群中,也可以从集群环集群进行一个基本的负载均衡。
集群中有两种节点:
-
内存节点:只保存状态到内存(一个例外的情况是:持久的queue的持久内容将被保存到disk)
-
磁盘节点:保存状态到内存和磁盘。
内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。集群中,只需要一个磁盘节点来保存状态 就足够了
如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。
思路:
那么具体如何实现RabbitMQ高可用,我们先搭建一个普通集群模式,在这个模式基础上再配置镜像模式实现高可用,Rabbit集群前增加一个反向代理,生产者、消费者通过反向代理访问RabbitMQ集群。
架构图如下:
2.2 集群模式配置
step1: 局域网配置
在安装好的三台节点服务器中,分别修改/etc/hosts文件
1. vim /etc/hosts
192.168.73.134 node1
192.168.73.135 node2
step2: 设置不同节点间同一认证的Erlang Cookie
Erlang的集群中各节点是通过一个magic cookie来实现的,这个cookie存放在 /var/lib/rabbitmq/.erlang.cookie 中,文件是400的权限。
所以必须保证各节点cookie保持一致,否则节点之间就无法通信。
采用从主节点copy的方式保持Cookie的一致性:
1. chmod 777 /var/lib/rabbitmq/.erlang.cookie
2. scp -p 22 /var/lib/rabbitmq/.erlang.cookie root@192.168.73.135:/var/lib/rabbitmq/
复制好后查看文件所属用户和组以及权限是否满足要求,不满足则修改。之后还原.erlang.cookie的权限,否则可能会遇到错误:
3. chown rabbitmq:rabbitmq .erlang.cookie
4. chmod 400 /var/lib/rabbitmq/.erlang.cookie
step3: 使用 -detached运行各节点
设置好cookie后将各个节点的RabbitMQ重启:
1. cd /sbin
2. rabbitmqctl stop
3. rabbitmq-server start
这里正常重启可能会提示该节点示例已经再运行中。如果出现使用以下命令启动:
1. ps -aux | grep erl
2. kill -9 {pid}
3. RABBITMQ_NODE_PORT=5678 RABBITMQ_NODENAME=rabbit@node1 ./rabbitmq-server -detached
RABBITMQ_NODE_PORT=5678 RABBITMQ_NODENAME=rabbit@node2 ./rabbitmq-server -detached
ps:上面5678是因为在安装时将rabbitmq的端口修改为5678了,而nodename与hosts里面设置的保持一致。
依次启动所有节点。
step4: 查看各节点的状态
1. 查看启动端口: netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN 27321/epmd
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 760/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1066/master
tcp 0 0 0.0.0.0:15678 0.0.0.0:* LISTEN 27862/beam.smp
tcp 0 0 0.0.0.0:25672 0.0.0.0:* LISTEN 27862/beam.smp
tcp6 0 0 :::5678 :::* LISTEN 27862/beam.smp
tcp6 0 0 :::8080 :::* LISTEN 964/java
tcp6 0 0 :::4369 :::* LISTEN 27321/epmd
tcp6 0 0 :::22 :::* LISTEN 760/sshd
tcp6 0 0 ::1:25 :::* LISTEN 1066/master
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 964/java
tcp6 0 0 :::8009 :::* LISTEN 964/java
2. 查看rabbitmq启动状态:
rabbitmqctl -n rabbit1
step5: 创建并部署集群
将rabbit
step5: 查看集群状态
1.查看节点1的集群状态: rabbitmqctl -n rabbit
至此,rabbitmq集群搭建完毕。
三、RabbitMQ镜像模式
上面配置RabbitMQ默认集群模式,但并不保证队列的高可用性,尽管交换机、绑定这些可以复制到集群里的任何一个节点,但是队列内容不会复制,虽然该模式解决一部分节点压力,但队列节点宕机直接导致该队列无法使用,只能等待重启,所以要想在队列节点宕机或故障也能正常使用,就要复制队列内容到集群里的每个节点,需要创建镜像队列。
step1:增加负载均衡器
关于负载均衡器,商业的比如F5的BIG-IP,Radware的AppDirector,是硬件架构的产品,可以实现很高的处理能力。但这些产品昂贵的价格会让人止步,所以我们还有软件负载均衡方案。互联网公司常用的软件LB一般有LVS、HAProxy、Nginx等。LVS是一个内核层的产品,主要在第四层负责数据包转发,使用较复杂。HAProxy和Nginx是应用层的产品,但Nginx主要用于处理HTTP,所以这里选择HAProxy作为RabbitMQ前端的LB。
1. 安装HAProxy(在192.168.73.136上安装HAProxy)
yum -y install haproxy
2. 修改haproxy.config配置
vim /etc/haproxy/haproxy.config
在其中增加以下配置:
listen rabbitmq_cluster 0.0.0.0:5678
mode tcp
balance roundrobin
server rabbitmaster 192.168.73.134:5678 check inter 2000 rise 2 fall 3
server rabbitslave 192.168.73.135:5678 check inter 2000 rise 2 fall 3
修改完HaProxy配置之后重新启动可能会提示绑定端口失败,此时执行以下命令即可:
setsebool -P haproxy_connect_any=1
负载均衡器会监听192.168.73.136的5678端口,轮询我们的两个节点192.168.73.134、192.168.73.135的5678端口,这样磁盘节点除了故障也不会影响,除非同时出故障。
step2:配置Rabbitmq策略
在任意一个节点上执行:
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
上面的命令会将所有队列设置为镜像队列,即队列会被复制到各个节点,各个节点状态保持一致
step3:使用负载服务器发送消息
客户端使用负载服务器172.16.3.110 (panyuntao3)发送消息,队列会被复制到所有节点。到这里我们完成了RabbitMQ集群的高可用配置。
作者:明天你好向前奔跑
链接:https://www.jianshu.com/p/01527d177e12