http://www.cnblogs.com/telwanggs/p/7124832.html
http://www.ywnds.com/?p=4741
https://blog.csdn.net/u013256816/article/details/77150922
集群理论知识:
由于RabbitMQ是用erlang开发的,RabbitMQ完全依赖Erlang的Cluster,因为erlang天生就是一门分布式语言,集群非常方便,但其本身并不支持负载均衡。Erlang的集群中各节点是经由过程一个magic cookie来实现的,这个cookie存放在 $home/.erlang.cookie 中(像我的root用户安装的就是放在我的root/.erlang.cookie中),文件是400的权限。所以必须包管各节点cookie对峙一致,不然节点之间就无法通信。
RabbitMQ的集群节点包括内存节点、磁盘节点。顾名思义内存节点就是将所有数据放在内存,磁盘节点将数据放在磁盘。不过,如果在投递消息时,打开了消息的持久化,那么即使是内存节点,数据还是安全的放在磁盘。
Rabbitmq集群大概分为二种方式:
(1)普通模式:默认的集群模式。
(2)镜像模式:把需要的队列做成镜像队列。
一个rabbitmq集 群中可以共享 user,vhost,queue,exchange等,所有的数据和状态都是必须在所有节点上复制的,一个例外是,那些当前只属于创建它的节点的消息队列,尽管它们可见且可被所有节点读取。rabbitmq节点可以动态的加入到集群中,一个节点它可以加入到集群中,也可以从集群环境中移除。
集群中有两种节点:
1 内存节点:只保存状态到内存(一个例外的情况是:持久的queue的持久内容将被保存到disk)
2 磁盘节点:保存状态到内存和磁盘。
内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。集群中,只需要一个磁盘节点来保存状态 就足够了如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。
良好的设计架构可以如下:在一个集群里,有3台以上机器,其中1台使用磁盘模式,其它使用内存模式。其它几台为内存模式的节点,无疑速度更快,因此客户端(consumer、producer)连接访问它们。而磁盘模式的节点,由于磁盘IO相对较慢,因此仅作数据备份使用。
一、普通模式:默认的集群模式
默认的集群模式,queue创建之后,如果没有其它policy,则queue就会按照普通模式集群。对于Queue来说,消息实体只存在于其中一个节点,A、B两个节点仅有相同的元数据,即队列结构,但队列的元数据仅保存有一份,即创建该队列的rabbitmq节点(A节点),当A节点宕机,你可以去其B节点查看,./rabbitmqctl list_queues 发现该队列已经丢失,但声明的exchange还存在。当消息进入A节点的Queue中后,consumer从B节点拉取时,RabbitMQ会临时在A、B间进行消息传输,把A中的消息实体取出并经过B发送给consumer,所以consumer应平均连接每一个节点,从中取消息。该模式存在一个问题就是当A节点故障后,B节点无法取到A节点中还未消费的消息实体。如果做了队列持久化或消息持久化,那么得等A节点恢复,然后才可被消费,并且在A节点恢复之前其它节点不能再创建A节点已经创建过的持久队列;如果没有持久化的话,消息就会失丢。这种模式更适合非持久化队列,只有该队列是非持久的,客户端才能重新连接到集群里的其他节点,并重新创建队列。假如该队列是持久化的,那么唯一办法是将故障节点恢复起来。
为什么RabbitMQ不将队列复制到集群里每个节点呢?这与它的集群的设计本意相冲突,集群的设计目的就是增加更多节点时,能线性的增加性能(CPU、内存)和容量(内存、磁盘)。理由如下
1。存储空间:如果每个集群节点每个队列的一个完整副本,增加节点需要更多的存储容量。例如,如果一个节点可以存储1 gb的消息,添加两个节点需要两份相同的1 gb的消息
2。性能:发布消息需要将这些信息复制到每个集群节点。对持久消息,要求为每条消息触发磁盘活动在所有节点上。每次添加一个节点都会带来 网络和磁盘的负载。
当然RabbitMQ新版本集群也支持队列复制(有个选项可以配置)。比如在有五个节点的集群里,可以指定某个队列的内容在2个节点上进行存储,从而在性能与高可用性之间取得一个平衡(应该就是指镜像模式)。
二、镜像模式:把需要的队列做成镜像队列,存在于多个节点,属于RabbitMQ的HA方案(镜像模式是在普通模式的基础上,增加一些镜像策略)
该模式解决了上述问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在consumer取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用,一个队列想做成镜像队列,需要先设置policy,然后客户端创建队列的时候,rabbitmq集群根据“队列名称”自动设置是普通集群模式或镜像队列。具体如下:
队列通过策略来使能镜像。策略能在任何时刻改变,rabbitmq队列也近可能的将队列随着策略变化而变化;非镜像队列和镜像队列之间是有区别的,前者缺乏额外的镜像基础设施,没有任何slave,因此会运行得更快。为了使队列称为镜像队列,你将会创建一个策略来匹配队列,设置策略有两个键“ha-mode和 ha-params(可选)”。ha-params根据ha-mode设置不同的值,下面表格说明这些key的选项:
语法讲解:
在cluster中任意节点启用策略,策略会自动同步到集群节点 (hrsystem 一般"/")
rabbitmqctl set_policy -p hrsystem ha-allqueue"^" '{"ha-mode":"all"}'
rabbitmqctl set_policy -p / ha-all "^" '{"ha-mode":"all"}'
这行命令在vhost名称为hrsystem创建了一个策略,策略名称为ha-allqueue,策略模式为 all 即复制到所有节点,包含新增节点,策略正则表达式为 “^” 表示所有匹配所有队列名称。
例如rabbitmqctl set_policy -p hrsystem ha-allqueue "^message" '{"ha-mode":"all"}'
rabbitmqctl set_policy -p / ha-all "^message" '{"ha-mode":"all"}'
注意:"^message" 这个规则要根据自己修改,这个是指同步"message"开头的队列名称,我们配置时使用的应用于所有队列,所以表达式为"^"
官方set_policy说明参见
set_policy [-p vhostpath] {name} {pattern} {definition} [priority]
“nodes”策略和迁移master
需要注意的是设置和修改一个“nodes”策略将不会引起已经存在的master离开,尽管你让其离开。比如:如果一个队列在{A},并且你给它一个节点策略告知它在{B C},它将会在{A B C}。如果节点A那时失败或者停机了,那个节点上的镜像将不回来且队列将继续保持在{B C}(注:当队列已经是镜像队列且同步到其它节点,就算原节点宕机,也不影响其它节点对此队列使用)。
队列名称以“ha.”开头的队列都是镜像队列,镜像到集群内所有节点:
列名称以“two.”开头的队列,其策略镜像到集群内任何两个节点:
队列同步到指rabbitmq 节点 ,rabbitmqctl:
./rabbitmqctl set_policy sa-specify "^sa\.specify\." '{"ha-mode":"nodes","ha-params":["rabbit@is137","rabbit@raxtone"]}'
切记,需要把队列同步到的节点都写进去。
4台机器 44、45、46,47,前3台部署rabbitmq,后一台部署ha
1. 修改主机名称 zcy44,zcy45,zcy46,zcy47(参考之前的blog)
hostnamectl --static set-hostname zcy44
重启命令:reboot
2. 修改/etc/hosts (44,45,46 三台集群的hosts文件中添加以下,同步主机的/etc/hosts文件)
172.18.8.44 zcy44
172.18.8.45 zcy45
172.18.8.46 zcy46
3. 3台主机分别安装rabbitmq
在3台主机上分别安装rabbitmq ,并且启动,并且打开管理界面
安装参考另一个blog
3. 同步erlang.cookie文件 (此文件是隐藏,所以ls -al )
Erlang Cookie 文件:/var/lib/rabbitmq/.erlang.cookie。这里将 node1 的该文件复制到 node2、node3,由于这个文件权限是 400,所以需要先修改 node2、node3 中的该文件权限为 777
然后将 node1 中的该文件拷贝到 node2、node3,最后将权限和所属用户/组修改回来
4. 加入集群
1> zcy44 上启动(命令必须是这样):service rabbitmq-server start
在zcy44节点上查看集群信息,此时集群中应只有自己
rabbitmqctl cluster_status
2> 下面zcy44,45,46 组成集群:
在zcy45上面先用service rabbitmq-server start启动,执行 rabbitmqctl cluster_status 看看,然后执行以下
1
2
3
|
root
@
live
-
mq
-
02
:
~
# rabbitmqctl stop_app
root
@
live
-
mq
-
02
:
~
# rabbitmqctl join_cluster rabbit@zcy44
root
@
live
-
mq
-
02
:
~
# rabbitmqctl start_app
|
在zcy46上面先用service rabbitmq-server start启动,执行 rabbitmqctl cluster_status 看看,然后执行以下
1
2
3
|
root
@
live
-
mq
-
03
:
~
# rabbitmqctl stop_app
root
@
live
-
mq
-
03
:
~
# rabbitmqctl join_cluster rabbit@zcy44 --ram
root
@
live
-
mq
-
03
:
~
# rabbitmqctl start_app
|
3> 在任何一台节点上执行 rabbitmqctl cluster_status (结果忽略,贴的别人),反正就是3台现在集群了
5. 设置镜像队列策略
6. 同步队列
rabbitmqctl sync_queue ryttest。 或者在rabbitmq 界面上点击队列,然后同步
6. 安装并配置 HAProxy及配置 (43主机)
https://www.jianshu.com/p/2bee5e32deeb
1>安装
yum install haproxy
2>修改 /etc/haproxy/haproxy.cfg (注意红色部分,其他不修改)
#全局配置
global
#日志输出配置,所有日志都记录在本机,通过local0输出
log 127.0.0.1 local0 info
#最大连接数
maxconn 4096
#改变当前的工作目录
chroot /opt/haproxy-1.7.8
#以指定的UID运行haproxy进程
uid 99
#以指定的GID运行haproxy进程
gid 99
#以守护进程方式运行haproxy #debug #quiet
daemon
#debug
#当前进程pid文件
pidfile /opt/haproxy-1.7.8/haproxy.pid
#默认配置
defaults
#应用全局的日志配置
log global
#默认的模式mode{tcp|http|health}
#tcp是4层,http是7层,health只返回OK
mode tcp
#日志类别tcplog
option tcplog
#不记录健康检查日志信息
option dontlognull
#3次失败则认为服务不可用
retries 3
#每个进程可用的最大连接数
maxconn 2000
#连接超时
timeout connect 5s
#客户端超时
timeout client 120s
#服务端超时
timeout server 120s
#绑定配置
listen rabbitmq_cluster
bind 43主机ip:5672
#配置TCP模式
mode tcp
#简单的轮询
balance roundrobin
#RabbitMQ集群节点配置
server zcy44 192.168.0.2:5672 check inter 5000 rise 2 fall 3 weight 1
server zcy45 192.168.0.3:5672 check inter 5000 rise 2 fall 3 weight 1
server zcy46 192.168.0.4:5672 check inter 5000 rise 2 fall 3 weight 1
#haproxy监控页面地址
listen monitor
bind 43ip:8100
mode http
option httplog
stats enable
stats uri /stats
stats refresh 5s
#---------------------------------------------------------------------
#---------------------------------------------------------------------
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
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 http
log global
option httplog
option dontlognull
option http-server-close
#option forwardfor except 127.0.0.0/8#注意这行得注释掉,不然报错
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
#---------------------------------------------------------------------
#---------------------------------------------------------------------
#对MQ集群进行监听
listen rabbitmq_cluster
bind 0.0.0.0:5673 #通过5673对m1和m2进行映射
option tcplog #记录TCP连接状态和时间
mode tcp #四层协议代理,即对TCP进行转发
option clitcpka #开启TCP的Keep Alive(长连接模式)
timeout connect 1s #haproxy与mq建立连接的超时时间
timeout client 10s #客户端与haproxy最大空闲时间
timeout server 10s #服务器与haproxy最大空闲时间
balance roundrobin #采用轮询转发消息
#每5秒发送一次心跳包,如果连续两次有响应则代表状态良好
#如果连续3次没有响应,则视为服务故障,该节点将被剔除
server 85node 192.168.7.85:5672 check inter 5s rise 2 fall 3
server 86node 192.168.7.86:5672 check inter 5s rise 2 fall 3
server 87node 192.168.7.87:5672 check inter 5s rise 2 fall 3
listen rabbitmq_admin
bind 0.0.0.0:8100
server 85node 192.168.7.85:15672
server 86node 192.168.7.86:15672
server 87node 192.168.7.87:15672
#开启监控服务
listen http_front
bind 0.0.0.0:1080 #监听端口
stats refresh 30s #每30秒刷新一次
stats uri /haproxy?stats #统计页面uri
stats auth admin123:admin123 #统计页面用户名和密码设置
#---------------------------------------------------------------------
#---------------------------------------------------------------------
在上面的配置中“listen rabbitmq_cluster bind 192.168.0.9.5671”这里定义了客户端连接IP地址和端口号。这里配置的负载均衡算法是roundrobin,注意这里的roundrobin是加权轮询。和RabbitMQ最相关的是“ server rmq_node1 192.168.0.2:5672 check inter 5000 rise 2 fall 3 weight 1”这种,它定义了RabbitMQ服务,每个RabbitMQ服务定义指令包含6个部分
server <name>:定义RabbitMQ服务的内部标示,注意这里的“rmq_node”是指包含有含义的字符串名称,不是指RabbitMQ的节点名称。
<ip>:<port>:定义RabbitMQ服务的连接的IP地址和端口号。
check inter <value>:定义了每隔多少毫秒检查RabbitMQ服务是否可用。
rise <value>:定义了RabbitMQ服务在发生故障之后,需要多少次健康检查才能被再次确认可用。
fall <value>:定义需要经历多少次失败的健康检查之后,HAProxy才会停止使用此RabbitMQ服务。
weight <value>:定义了当前RabbitMQ服务的权重。
最后一段配置定义的是HAProxy的数据统计页面。数据统计页面包含各个服务节点的状态、连接、负载等信息。在调用
haproxy -f haproxy.cfg
行HAProxy之后可以在浏览器上输入http://192.168.0.9:8100/stats来加载相关的页面
7.其他
1> 磁盘节点改成内存节点
此时live-mq-02与live-mq-03也会自动建立连接,上面我的两个节点,其中live-mq-02是磁盘节点,live-mq-03是内存节点,但live-mq-01节点默认是磁盘节点(一个集群中最少要有一个磁盘节点)。如果想把live-mq-02由磁盘节点改成内存节点,使用如下change_cluster_node_type命令修改即可,但要先stop:
1
2
3
4
5
6
7
8
9
|
root
@
live
-
mq
-
02
:
~
# rabbitmqctl stop_app
Stopping
node
'rabbit@live-mq-02'
.
.
.
.
.
.done
.
root
@
live
-
mq
-
02
:
~
# rabbitmqctl change_cluster_node_type ram
Turning
'rabbit@live-mq-02'
into
a
ram
node
.
.
.
.
.
.done
.
root
@
live
-
mq
-
02
:
~
# rabbitmqctl start_app
Starting
node
'rabbit@live-mq-02'
.
.
.
.
.
.done
.
|
2> RabbitMQ退出集群
假设要把rabbit@live-mq-02退出集群,在rabbit@live-mq-02上执行:
1
2
3
|
$
rabbitmqctl
stop
_app
$
rabbitmqctl
reset
$
rabbitmqctl
start_app
|
或者:
在集群主节点上执行
1
|
$
rabbitmqctl
forget_cluster
_node
rabbit
@
live
-
mq
-
02
|
3> RabbitMQ集群重启
集群重启时,最后一个挂掉的节点应该第一个重启,如果因特殊原因(比如同时断电),而不知道哪个节点最后一个挂掉。可用以下方法重启:
先在一个节点上执行
1
2
|
$
rabbitmqctl
force
_boot
$
service
rabbitmq
-
server
start
|
在其他节点上执行
1
|
$
service
rabbitmq
-
server
start
|
查看cluster状态是否正常(要在所有节点上查询)。
1
|
rabbitmqctl
cluster_status
|
如果有节点没加入集群,可以先退出集群,然后再重新加入集群。
队列删除不了,处理方式:
-
输入命令rabbitmqctl list_queues,有2万多条数据
-
关闭应用
rabbitmqctl stop_app
执行清除命令
-
rabbitmqctl reset
启动应权用
-
rabbitmqctl start_app
验证清除结果rabbitmqctl list_queues