10_RabbitMQ集群搭建

字数 1685阅读 465

@Author Jacky Wang

近日搭建了RabbitMQ集群,特记录与此.转载请标注出处http://www.jianshu.com/p/01527d177e12

一、前提

  • 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集群。

架构图如下:

02.png

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@node1 status
    rabbitmqctl -n rabbit1@node2 status  

3. 访问http://192.168.73.134:15678查看是否可以访问rabbitmq的web管理后台(安装时必须开启)
step5: 创建并部署集群
将rabbit@rabbitmq2与rabbit@rabbitmq1组成集群,且rabbitmq2作为内存节点(硬盘节点有一个即可);

rabbitmq2:
    1. 停止节点2的应用程序:  rabbitmqctl -n rabbit@node2 stop_app
            Stopping rabbit application on node rabbit@rabbitmq2

    2. 作为内存节点加入节点1: rabbitmqctl -n rabbit@node2 join_cluster --ram rabbit@node1
            Clustering node rabbit@node2 with rabbit@node1

    3. 启动节点2的应用程序:  rabbitmqctl -n rabbit@node2 start_app
            Starting node rabbit@node2
step5: 查看集群状态
1.查看节点1的集群状态:   rabbitmqctl -n rabbit@node1 cluster_status
        Cluster status of node rabbit@node1
        [{nodes,[{disc,[rabbit@node1]},{ram,[rabbit@node2]}]},
         {running_nodes,[rabbit@node1]},
         {cluster_name,<<"rabbit@node1">>},
         {partitions,[]},
         {alarms,[{rabbit@node1,[]}]}] 
2. 查看节点2的集群状态:  rabbitmqctl -n rabbit@node2 cluster_status
        Cluster status of node rabbit@node2
        [{nodes,[{disc,[rabbit@node1]},{ram,[rabbit@node2]}]},
         {alarms,[{rabbit@node1,[]}]}]

3. 后台查看集群状态:
06.png
至此,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集群的高可用配置。