• Centos6.9下RabbitMQ集群部署记录


    转载于http://www.cnblogs.com/kevingrace/p/8012792.html

    之前简单介绍了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集群模式配置
    该设计架构可以如下:在一个集群里,有3台机器,其中1台使用磁盘模式,另2台使用内存模式。2台内存模式的节点,无疑速度更快,因此客户端(consumer、producer)连接访问它们。而磁盘模式的节点,由于磁盘IO相对较慢,因此仅作数据备份使用,另外一台作为反向代理。

    配置RabbitMQ集群非常简单,只需要几个命令,如下面范例,简单说下配置的几个步骤:
    第一步:queue、kevintest1、kevintest2做为RabbitMQ集群节点,分别安装RabbitMq-Server ,安装后分别启动RabbitMq-server。

    1
    2
    启动命令 
    # Rabbit-Server start

    第二步:在安装好的三台节点服务器中,分别修改/etc/hosts文件,指定queue、kevintest1、kevintest2的hosts。

    1
    2
    3
    4
    5
    6
    172.16.3.32  queue
    172.16.3.107 kevintest1
    172.16.3.108 kevintest2
      
    三台节点的hostname要正确,主机名分别是queue、kevintest1、kevintest2,如果修改hostname,建议安装rabbitmq前修改。请注意RabbitMQ集群节点必须在同一个网段里,
    如果是跨广域网效果就差。

    第三步:设置每个节点Cookie

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Rabbitmq的集群是依赖于erlang的集群来工作的,所以必须先构建起erlang的集群环境。Erlang的集群中各节点是通过一个magic cookie来实现的,这个cookie存放在
    /var/lib/rabbitmq/.erlang.cookie 中,文件是400的权限。所以必须保证各节点cookie保持一致,否则节点之间就无法通信。
    # ll /var/lib/rabbitmq/.erlang.cookie
    -r-------- 1 rabbitmq rabbitmq 21 12月  6 00:40 /var/lib/rabbitmq/.erlang.cookie
     
    将queue的/var/lib/rabbitmq/.erlang.cookie这个文件,拷贝到kevintest1、kevintest2的同一位置(反过来亦可),该文件是集群节点进行通信的验证密钥,所有
    节点必须一致。拷完后重启下RabbitMQ。复制好后别忘记还原.erlang.cookie的权限,否则可能会遇到错误
    # chmod 400 /var/lib/rabbitmq/.erlang.cookie
     
    设置好cookie后先将三个节点的rabbitmq重启
    # rabbitmqctl stop
    # rabbitmq-server start

    第四步:停止所有节点RabbitMq服务,然后使用detached参数独立运行,这步很关键,尤其增加节点停止节点后再次启动遇到无法启动,都可以参照这个顺序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    [root@queue ~]# rabbitmqctl stop
    [root@kevintest1 ~]# rabbitmqctl stop
    [root@kevintest2 ~]# rabbitmqctl stop
      
    [root@queue ~]# rabbitmq-server -detached
    [root@kevintest1 ~]# rabbitmq-server -detached
    [root@kevintest2 ~]# rabbitmq-server -detached
      
    分别查看下每个节点
    [root@queue ~]# rabbitmqctl cluster_status
    Cluster status of node rabbit@queue ...
    [{nodes,[{disc,[rabbit@queue]}]},
    {running_nodes,[rabbit@queue]},
    {partitions,[]}]
    ...done.
      
    [root@kevintest1 ~]# rabbitmqctl cluster_status
    Cluster status of node rabbit@kevintest1...
    [{nodes,[{disc,[rabbit@kevintest1]}]},
    {running_nodes,[rabbit@kevintest1]},
    {partitions,[]}]
    ...done.
     
    [root@kevintest2 ~]# rabbitmqctl cluster_status
    Cluster status of node rabbit@kevintest2...
    [{nodes,[{disc,[rabbit@kevintest2]}]},
    {running_nodes,[rabbit@kevintest2]},
    {partitions,[]}]
    ...done.

    第五步:将kevintest1、kevintest2作为内存节点与queue连接起来,在kevintest1上,执行如下命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@kevintest1 ~]# rabbitmqctl stop_app
    [root@kevintest1 ~]# rabbitmqctl join_cluster --ram rabbit@queue  
    [root@kevintest1 ~]# rabbitmqctl start_app
     
    [root@kevintest2 ~]# rabbitmqctl stop_app
    [root@kevintest2 ~]# rabbitmqctl join_cluster --ram rabbit@queue   #上面已经将kevintest1与queue连接,也可以直接将kevintest2与kevintest1连接,同样而已加入集群中
    [root@kevintest2 ~]# rabbitmqctl start_app
     
    1)上述命令先停掉rabbitmq应用,然后调用cluster命令,将kevintest1连接到,使两者成为一个集群,最后重启rabbitmq应用。
    2)在这个cluster命令下,kevintest1、kevintest2是内存节点,queue是磁盘节点(RabbitMQ启动后,默认是磁盘节点)。
    3)queue如果要使kevintest1或kevintest2在集群里也是磁盘节点,join_cluster 命令去掉--ram参数即可
    #rabbitmqctl join_cluster rabbit@queue  
    只要在节点列表里包含了自己,它就成为一个磁盘节点。在RabbitMQ集群里,必须至少有一个磁盘节点存在。

    第六步:在queue、kevintest1、kevintest2上,运行cluster_status命令查看集群状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # rabbitmqctl cluster_status
    Cluster status of node rabbit@queue ...
    [{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@kevintest2,rabbit@kevintest1]}]},
    {running_nodes,[rabbit@kevintest2,rabbit@kevintest1,rabbit@queue]},
    {partitions,[]}]
    ...done.
     
    [root@kevintest1 rabbitmq]# rabbitmqctl cluster_status
    Cluster status of node rabbit@kevintest1 ...
    [{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@kevintest2,rabbit@kevintest1]}]},
    {running_nodes,[rabbit@kevintest2,rabbit@queue,rabbit@kevintest1]},
    {partitions,[]}]
    ...done.
      
    [root@kevintest2 rabbitmq]# rabbitmqctl cluster_status
    Cluster status of node rabbit@kevintest2 ...
    [{nodes,[{disc,[rabbit@queue]},{ram,[rabbit@kevintest2,rabbit@kevintest1]}]},
    {running_nodes,[rabbit@kevintest1,rabbit@queue,rabbit@kevintest2]},
    {partitions,[]}]
    ...done.
     
    这时可以看到每个节点的集群信息,分别有两个内存节点一个磁盘节点

    第七步:往任意一台集群节点里写入消息队列,会复制到另一个节点上,我们看到两个节点的消息队列数一致:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    [root@kevintest2 ~]# rabbitmqctl list_queues -p hrsystem
     
    Listing queues …
    test_queue 10000
    done.
     
    [root@kevintest1 ~]# rabbitmqctl list_queues -p hrsystem
    Listing queues …
    test_queue 10000
    done.
      
    [root@queue ~]# rabbitmqctl list_queues -p hrsystem
    Listing queues …
    test_queue 10000
    done.
      
    -p参数为vhost名称

    这样RabbitMQ集群就正常工作了,这种模式更适合非持久化队列,只有该队列是非持久的,客户端才能重新连接到集群里的其他节点,并重新创建队列。假如该队列是持久化的,那么唯一办法是将故障节点恢复起来;为什么RabbitMQ不将队列复制到集群里每个节点呢?这与它的集群的设计本意相冲突,集群的设计目的就是增加更多节点时,能线性的增加性能(CPU、内存)和容量(内存、磁盘)。理由如下:当然RabbitMQ新版本集群也支持队列复制(有个选项可以配置)。比如在有五个节点的集群里,可以指定某个队列的内容在2个节点上进行存储,从而在性能与高可用性之间取得一个平衡。

    =============清理RabbitMQ消息队列中的所有数据============

    1
    2
    3
    4
    5
    6
    方法如下:
    # rabbitmqctl list_queues    //查看所有队列数据
    # rabbitmqctl stop_app      //要先关闭应用,否则不能清除
    # rabbitmqctl reset
    # rabbitmqctl start_app
    # rabbitmqctl list_queues   //这时候看到listing 及queues都是空的

    =========================================================================================

    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集群部署过程=======

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    集群机器信息:
    rabbitmq01.kevin.cn      192.168.1.40
    rabbitmq02.kevin.cn      192.168.1.41
    rabbitmq03.kevin.cn      192.168.1.42
      
    1)设置hosts主机解析,rabbitmq 集群通信用途,所有节点配置相同。
    [root@rabbitmq01 ~]# cat /etc/hosts
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    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
     
    [root@rabbitmq02 ~]# rabbitmqadmin get queue=test requeue=false
    +-------------+----------+---------------+--------------+------------------+-------------+
    | routing_key | exchange | message_count | payload      | payload_encoding | redelivered |
    +-------------+----------+---------------+--------------+------------------+-------------+
    test        |          | 0             | hello, world | string           | False       |
    +-------------+----------+---------------+--------------+------------------+-------------+

    测试后发现问题问题:
    [root@rabbitmq01 ~]# rabbitmqctl stop_app
    [root@rabbitmq01 ~]# rabbitmqctl stop
    在stop_app或者stop掉broker之后在rabbitmq01节点的上队列已经不可用了,重启rabbitmq01的app或broker之后,虽然集群工作正常,但rabbitmq01上队列中消息会被清空(queue还是存在的)

    对于生产环境而已,这肯定是不可接受的,如果不能保证队列的高可用,那么做集群的意义也不太大了,还好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模式,创建见消息的时候也声明了持久化,为什么还是不行那?

    因为创建消息的时候需要指定消息是否持久化,如果启用了消息的持久化的话,重启集群消息也不会丢失了,前提是创建的队列也应该是创建的持久化队列。

    客户端连接rabbitMQ集群服务的方式:
    1)客户端可以连接集群中的任意一个节点,如果一个节点故障,客户端自行重新连接到其他的可用节点;(不推荐,对客户端不透明)
    2)通过动态DNS,较短的ttl
    3)通过HA+4层负载均衡器(比如haproxy+keepalived)

    ==========Haproxy+keepalived的部署===============
    消息队列作为公司的关键基础服务,为给客户端提供稳定、透明的rabbitmq服务,现通过Haproxy+keepalived构建高可用的rabbitmq统一入口,及基本的负载均衡服务。
    为简化安装配置,现采用yum的方式安装haproxy和keepalived,可参考 基于keepalived+nginx部署强健的高可用7层负载均衡方案。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    在两台两台服务器部署haproxy+Keepalived环境,部署过程一样。
    haroxy01.kevin.cn      192.168.1.43
    haroxy02.kevin.cn      192.168.1.44
     
    1)安装
    [root@haproxy01 ~]# yum install haproxy keepalived -y
    [root@haproxy01 ~]# /etc/init.d/keepalived start
     
    2)设置关键服务开机自启动
    [root@haproxy01 ~]# chkconfig --list|grep haproxy
    [root@haproxy01 ~]# chkconfig haproxy on
    [root@haproxy01 ~]# chkconfig --list|grep haproxy
     
    3) 配置将haproxy的log记录到 /var/log/haproxy.log
    [root@haproxy01 ~]# more /etc/rsyslog.d/haproxy.conf
    $ModLoad imudp
    $UDPServerRun 514
    local0.* /var/log/haproxy.log
     
    [root@haproxy01 ~]# /etc/init.d/rsyslog restart
     
    4)haproxy的配置,2台机器上的配置完全相同
    [root@haproxy01 ~]# more /etc/haproxy/haproxy.cfg
    #---------------------------------------------------------------------
    # Example configuration for a possible web application. See the
    # full configuration options online.
    #
    # https://haproxy.1wt.eu/download/1.4/doc/configuration.txt
    #
    #---------------------------------------------------------------------
     
     
    #---------------------------------------------------------------------
    # Global settings
    #---------------------------------------------------------------------
    global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events. This is done
    # by adding the '-r' option to the SYSLOGD_OPTIONS in
    # /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    # file. A line like the following can be added to
    # /etc/sysconfig/syslog
    #
    # local2.* /var/log/haproxy.log
    #
    log 127.0.0.1 local2 notice
     
    chroot /var/lib/haproxy
    pidfile /var/run/haproxy.pid
    maxconn 4000
    user haproxy
    group haproxy
    daemon
     
    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats
     
    #---------------------------------------------------------------------
    # common defaults that all the 'listen' and 'backend' sections will
    # use if not designated in their block
    #---------------------------------------------------------------------
    defaults
    mode tcp
    option tcplog
    option dontlognull
    option http-server-close
    option redispatch
    retries 3
    timeout http-request 10s
    timeout queue 1m
    timeout connect 10s
    timeout client 1m
    timeout server 1m
    timeout http-keep-alive 10s
    timeout check 10s
    maxconn 3000
     
    ###haproxy statistics monitor by laijingli 20160222
    listen statics 0.0.0.0:8888
    mode http
    log 127.0.0.1 local0 debug
    transparent
    stats refresh 60s
    stats uri / haproxy-stats
    stats realm Haproxy statistic
    stats auth laijingli:xxxxx
     
    #---------------------------------------------------------------------
    # main frontend which proxys to the backends
    #---------------------------------------------------------------------
    frontend kevin_rabbitMQ_cluster_frontend
    mode tcp
    option tcpka
    log 127.0.0.1 local0 debug
    bind 0.0.0.0:5672
    use_backend kevin_rabbitMQ_cluster_backend
     
    frontend kevin_rabbitMQ_cluster_management_frontend
    mode tcp
    option tcpka
    log 127.0.0.1 local0 debug
    bind 0.0.0.0:15672
    use_backend kevin_rabbitMQ_cluster_management_backend
     
     
    #---------------------------------------------------------------------
    # round robin balancing between the various backends
    #---------------------------------------------------------------------
    backend kevin_rabbitMQ_cluster_backend
    balance roundrobin
    server rabbitmq01.kevin.cn 192.168.1.40:5672 check inter 3s rise 1 fall 2
    server rabbitmq02.kevin.cn 192.168.1.41:5672 check inter 3s rise 1 fall 2
    server rabbitmq03.kevin.cn 192.168.1.42:5672 check inter 3s rise 1 fall 2
     
     
    backend kevin_rabbitMQ_cluster_management_backend
    balance roundrobin
    server rabbitmq01.kevin.cn 192.168.1.40:15672 check inter 3s rise 1 fall 2
    server rabbitmq02.kevin.cn 192.168.1.41:15672 check inter 3s rise 1 fall 2
    server rabbitmq03.kevin.cn 192.168.1.42:15672 check inter 3s rise 1 fall 2
     
    5)keepalived配置,特别注意2台服务器上的keepalived配置不一样。
    =======================先看下haroxy01.kevin.cn机器上的配置===========================
    [root@haproxy01 ~]# more /etc/keepalived/keepalived.conf
    global_defs {
    notification_email {
    wangshibo@kevin.cn
    102533678@qq.com
    }
    notification_email_from notice@kevin.cn
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id haproxy43      ## xxhaproxy101 on master , xxhaproxy102 on backup
    }
     
     
    ###simple check with killall -0 which is less expensive than pidof to verify that nginx is running
    vrrp_script chk_nginx {
    script "killall -0 nginx"
    interval 1
    weight 2
    fall 2
    rise 1
    }
     
     
    vrrp_instance KEVIN_GATEWAY {
    state MASTER              ## MASTER on master , BACKUP on backup
    interface em1
    virtual_router_id 101         ## KEVIN_GATEWAY virtual_router_id
    priority 200            ## 200 on master , 199 on backup
    advert_int 1
    ###采用单播通信,避免同一个局域网中多个keepalived组之间的相互影响
    unicast_src_ip 192.168.1.43     ##本机ip
    unicast_peer {
    192.168.1.44     ##对端ip
    }
    authentication {
    auth_type PASS
    auth_pass 123456
    }
    virtual_ipaddress {
    192.168.1.45                  ## VIP
    }
    ###如果只有一块网卡的话监控网络接口就没有必要了
    #track_interface {
    # em1
    #}
    track_script {
    chk_nginx
    }
    ###状态切换是发送邮件通知,本机记录log,后期会触发短信通知
    notify_master /usr/local/bin/keepalived_notify.sh notify_master
    notify_backup /usr/local/bin/keepalived_notify.sh notify_backup
    notify_fault /usr/local/bin/keepalived_notify.sh notify_fault
    notify /usr/local/bin/keepalived_notify.sh notify
    smtp_alert
    }
     
    ###simple check with killall -0 which is less expensive than pidof to verify that haproxy is running
    vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 1
    weight 2
    fall 2
    rise 1
    }
    vrrp_instance kevin_rabbitMQ_GATEWAY {
    state BACKUP          ## MASTER on master , BACKUP on backup
    interface em1
    virtual_router_id 111 ## kevin_rabbitMQ_GATEWAY virtual_router_id
    priority 199         ## 200 on master , 199 on backup
    advert_int 1
    ###采用单播通信,避免同一个局域网中多个keepalived组之间的相互影响
    unicast_src_ip 192.168.1.43      ##本机ip
    unicast_peer {
    192.168.1.44        ##对端ip
    }
    authentication {
    auth_type PASS
    auth_pass 123456
    }
    virtual_ipaddress {
    192.168.1.46        ## VIP
    }
    ###如果只有一块网卡的话监控网络接口就没有必要了
    #track_interface {
    # em1
    #}
    track_script {
    chk_haproxy
    }
    ###状态切换是发送邮件通知,本机记录log,后期会触发短信通知
    notify_master /usr/local/bin/keepalived_notify_for_haproxy.sh notify_master
    notify_backup /usr/local/bin/keepalived_notify_for_haproxy.sh notify_backup
    notify_fault /usr/local/bin/keepalived_notify_for_haproxy.sh notify_fault
    notify /usr/local/bin/keepalived_notify_for_haproxy.sh notify
    smtp_alert
    }
     
     
    =============================再看下haroxy02.kevin.cn机器上的配置==========================
    [root@haproxy02 ~]# more /etc/keepalived/keepalived.conf
    global_defs {
    notification_email {
    wangshibo@kevin.cn
    102533678@qq.com
    }
    notification_email_from notice@kevin.cn
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id haproxy44     ## xxhaproxy101 on master , xxhaproxy102 on backup
    }
     
    ###simple check with killall -0 which is less expensive than pidof to verify that nginx is running
    vrrp_script chk_nginx {
    script "killall -0 nginx"
    interval 1
    weight 2
    fall 2
    rise 1
    }
     
    vrrp_instance KEVIN_GATEWAY {
    state BACKUP         ## MASTER on master , BACKUP on backup
    interface em1
    virtual_router_id 101       ## KEVIN_GATEWAY virtual_router_id
    priority 199      ## 200 on master , 199 on backup
    advert_int 1
    ###采用单播通信,避免同一个局域网中多个keepalived组之间的相互影响
    unicast_src_ip 192.168.1.44     ##本机ip
    unicast_peer {
    192.168.1.43       ##对端ip
    }
    authentication {
    auth_type PASS
    auth_pass YN_API_HA_PASS
    }
    virtual_ipaddress {
    192.168.1.45     ## VIP
    }
    ###如果只有一块网卡的话监控网络接口就没有必要了
    #track_interface {
    # em1
    #}
    track_script {
    chk_nginx
    }
    ###状态切换是发送邮件通知,本机记录log,后期会触发短信通知
    notify_master /usr/local/bin/keepalived_notify.sh notify_master
    notify_backup /usr/local/bin/keepalived_notify.sh notify_backup
    notify_fault /usr/local/bin/keepalived_notify.sh notify_fault
    notify /usr/local/bin/keepalived_notify.sh notify
    smtp_alert
    }
     
    ###simple check with killall -0 which is less expensive than pidof to verify that haproxy is running
    vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 1
    weight 2
    fall 2
    rise 1
    }
    vrrp_instance kevin_rabbitMQ_GATEWAY {
    state MASTER        ## MASTER on master , BACKUP on backup
    interface em1
    virtual_router_id 111       ## kevin_rabbitMQ_GATEWAY virtual_router_id
    priority 200       ## 200 on master , 199 on backup
    advert_int 1
    ###采用单播通信,避免同一个局域网中多个keepalived组之间的相互影响
    unicast_src_ip 192.168.1.44      ##本机ip
    unicast_peer {
    192.168.1.43      ##对端ip
    }
    authentication {
    auth_type PASS
    auth_pass YN_MQ_HA_PASS
    }
    virtual_ipaddress {
    192.168.1.46      ## VIP
    }
    ###如果只有一块网卡的话监控网络接口就没有必要了
    #track_interface {
    # em1
    #}
    track_script {
    chk_haproxy
    }
    ###状态切换是发送邮件通知,本机记录log,后期会触发短信通知
    notify_master /usr/local/bin/keepalived_notify_for_haproxy.sh notify_master
    notify_backup /usr/local/bin/keepalived_notify_for_haproxy.sh notify_backup
    notify_fault /usr/local/bin/keepalived_notify_for_haproxy.sh notify_fault
    notify /usr/local/bin/keepalived_notify_for_haproxy.sh notify
    smtp_alert
    }
     
     
    配置中用到的通知脚本,2台haproxy服务器上完全一样:
    [root@haproxy01 ~]# more /usr/local/bin/keepalived_notify.sh
    #!/bin/bash
    ###keepalived notify script for record ha state transtion to log files
     
    ###将将状态转换过程记录到log,便于排错
    logfile=/var/log/keepalived.notify.log
    echo --------------- >> $logfile
    echo `date` [`hostname`] keepalived HA role state transition: $1 $2 $3 $4 $5 $6 >> $logfile
     
    ###将状态转换记录到nginx的文件,便于通过web查看ha状态(一定注意不要开放到公网)
    echo `date` `hostname` $1 $2 $3 $4 $5 $6 "
    " > /usr/share/nginx/html/index_for_nginx.html
     
    ###将nginx api和rabbitmq的ha log记录到同一个文件里
    cat /usr/share/nginx/html/index_for* > /usr/share/nginx/html/index.html
     
     
    6)haproxy监控页面。
    访问地址http://192.168.1.43:8888
     
    7)查看keepalived中高可用服务运行在那台服务器上
    https://192.168.1.43
     
    8)通过VIP访问rabbitMQ服务
    http://192.168.1.46:5672
     
    9)其他问题
    rabbitmq服务客户端使用规范
    1)使用vhost来隔离不同的应用、不同的用户、不同的业务组
    2)消息持久化,exchange、queue、message等持久化需要在客户端声明指定
  • 相关阅读:
    海量数据查询关系型数据库存储大数据,要点就是:简单存储、分区分表、高效索引、批量写入
    微服务架构
    多租户系统架构
    SaaS模式实现架构
    net Core 2.1新功能Generic Host(通用主机)
    深度学习与机器学习
    RabbitMQ和Kafka
    为什么使用框架
    迅雷在P2P网络中的另类上传速度
    Spring配置中的"classpath:"与"classpath*:"的区别研究(转)
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/9057131.html
Copyright © 2020-2023  润新知