rabbitmq+haproxy+keepalived
RabbitMQ
MQ概述
MQ全称,message queue (消息队列),是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信
生产者
生产者--->MQ--->消费者
MQ优势
应用解耦
使用MQ使得应用解耦,提升容错性和可维护性
异步提速
提升用户体验和系统吞吐量(单位时间内处理请求的数目)
削峰填谷
使用mq可提高系统稳定性
MQ的劣势
·
系统可用性降低
·
o
系统引入的外部依赖,系统稳定性越差。一旦MQ宕机,就会对业务造成影响。如何保证MQ的高可用?
o
·
系统复杂度提高
·
o
MQ的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用。如何保证消息不被丢失等情况?
o
rabbitmq核心
简单模式--->工作模式--->发布订阅模式--->路由模式--->主题模式--->发布确认模式
rabbitmq工作原理
名词解释
broker:接收和分发消息的应用,rabbitmq server就是 message broker
connection:publisher/consumer和broker之间的tcp连接
channel:如果每一次访问rabbitmq都建立一个connection内部建立的逻辑连接,在消息量大的时候建立tcp connection的开销将是巨大的,效率低。每一个连接里面有多个信道,每个信道建立逻辑连接不占用多余连接 ,就可以发多个消息
exchange:message到达broker的第一站,根据分发规则,匹配查询表中的routing key,分发消息到queue中去。
queue:消息最终送到这里等待consumer取走
binding:exchange和queue之间的虚拟连接,binding中可以包含routing key binding信息被保存到exchange
中的查询表中,用于message的分发依据
MQ工作原理
RabbitMQ如何工作的?
我们来简单看看RabbitMQ是如何工作的。
首先来看看RabbitMQ里的几个重要概念:
·
生产者(Producer):发送消息的应用。
·
·
消费者(Consumer):接收消息的应用。
·
·
队列(Queue):存储消息的缓存。
·
·
消息(Message):由生产者通过RabbitMQ发送给消费者的信息。
·
·
连接(Connection):连接RabbitMQ和应用服务器的TCP连接。
·
·
通道(Channel):连接里的一个虚拟通道。当你通过消息队列发送或者接收消息时,这个操作都是通过通道进行的。
·
·
交换机(Exchange):交换机负责从生产者那里接收消息,并根据交换类型分发到对应的消息列队里。要实现消息的接收,一个队列必须到绑定一个交换机。
·
·
绑定(Binding):绑定是队列和交换机的一个关联连接。
·
·
路由键(Routing Key):路由键是供交换机查看并根据键来决定如何分发消息到列队的一个键。路由键可以说是消息的目的地址。
·
生产者(Producer)发送/发布消息到代理->消费者(Consumer)从代理那里接收消息。哪怕生产者和消费者运行在不同的机器上,RabbitMQ也能扮演代理中间件的角色。
当生产者发送消息时,它并不是直接把消息发送到队列里的,而是使用交换机(Exchange)来发送。下面的设计图简单展示了这三个主要的组件之间是如何连接起来的。
交换机代理(exchange agent)负责把消息分发到不同的队列里。这样的话,消息就能够从生产者发送到交换机,然后被分发到消息队列里。这就是常见的“发布”方法。
Producer
然后,消息会被消费者从队列里读取并消费,这就是“消费”。
往多个队列里发送消息
对一个复杂的应用而言,往往会有多个消息队列,所以消息也会被发往多个队列。
Multiple queues
给带有多个队列的交换机发送的消息是通过绑定和路由键来进行分发的。绑定是你设置的用来连接一个队列和交换机的连接。路由键是消息的一个属性。交换机会根据路由键来决定消息分发到那个队列里(取决于交换机的类型)。
交换机(Exchange)
消息并不是直接发布到队里里的,而是被生产者发送到一个交换机上。交换机负责把消息发布到不同的队列里。交换机从生产者应用上接收消息,然后根据绑定和路由键将消息发送到对应的队列里。绑定是交换机和队列之间的一个关系连接。
Exchange
RabbitMQ里的消息流程
·
*生产者(producer)*把消息发送给交换机。当你创建交换机的时候,你需要指定类型。交换机的类型接下来会讲到。
·
·
*交换机(exchange)*接收消息并且负责对消息进行路由。根据交换机的类型,消息的多个属性会被使用,例如路由键。
·
·
*绑定(binding)*需要从交换机到队列的这种方式来进行创建。在这个例子里,我们可以看到交换机有到两个不同队列的绑定。交换机根据消息的属性来把消息分发到不同的队列上。
·
·
*消息(message)*消息会一直留在队列里直到被消费。
·
·
*消费者(consumer)*处理消息。
·
交换机类型
Exchange Type
1.
直接(Direct):直接交换机通过消息上的路由键直接对消息进行分发。
2.
3.
扇出(Fanout):一个扇出交换机会将消息发送到所有和它进行绑定的队列上。
4.
5.
主题(Topic):这个交换机会将路由键和绑定上的模式进行通配符匹配。
6.
7.
消息头(Headers):消息头交换机使用消息头的属性进行消息路由。
8.
RabbitMQ核心概念
·
生产者(Producer):发送消息的应用。
·
·
消费者(Consumer):接收消息的应用。
·
·
队列(Queue):存储消息的缓存。
·
·
消息(Message):又生产者通过RabbitMQ发送给消费者的信息。
·
·
连接(Connection):连接RabbitMQ和应用服务器的TCP连接。
·
·
通道(Channel):连接里的一个虚拟通道。当你通过消息队列发送或者接收消息时,这个操作都是通过通道进行的。
·
·
交换机(Exchange):从生产者那里接收消息,并根据交换类型分发到对应的消息列队里。要实现消息的接收,一个队列必须绑定一个交换机。
·
·
绑定(Binding):绑定是队列和交换机的一个链接。
·
·
路由键(Routing Key):路由键是供交换机查看并根据键的值来决定如何分发消息到列队的一个键。路由键可以说是消息的目的地址。
·
·
AMQP:AMQP(高级消息队列协议Advanced Message Queuing Protocol)是RabbitMQ使用的消息协议。
·
·
用户(Users):在RabbitMQ里,是可以通过指定的用户名和密码来进行连接的。每个用户可以分配不同的权限,例如读权限,写权限以及在实例里进行配置的权限。
·
安装
官方网址:https://www.rabbitmq.com/download.html
下载安装包
erlang-21.3.8.16-1.el7.x86_64.rpm (作为rabbitmq的依赖版本)
rabbitmq-server-3.8.8-1.el7.noarch.rpm
wget --content-disposition https://packagecloud.io/rabbitmq/rabbitmq-server/packages/el/7/rabbitmq-server-3.8.8-1.el7.noarch.rpm/download.rpm
wget --content-disposition https://packagecloud.io/rabbitmq/erlang/packages/el/7/erlang-21.3.8.16-1.el7.x86_64.rpm/download.rpm
安装步骤
rpm -ivh erlang-21.3.8.16-1.el7.x86_64.rpm
yum -y install socat (依赖关系)
rpm -ivh rabbitmq-server-3.8.8-1.el7.noarch.rpm
常用命令
chkconfig rabbitmq-server on (设置开机自启)
/sbin/service rabbitmq-server start (启动rabbitmq)
systemctl status rabbitmq-server (查看启动状态是否启动)
开启web管理插件
/sbin/service rabbitmq-server stop (关闭rabbitmq)
rabbitmq-plugins enable rabbitmq_management (安装web插件)
/sbin/service rabbitmq-server start (启动rabbitmq)
访问登录rabbitmq
主机ip:15672
注意事项:如果没有访问到可能是防火墙未关闭或端口号问题
第一次登录出现错误
解决方法
创建用户
[root@localhost opt]# rabbitmqctl add_user admin 123 (添加用户)
Adding user "admin" ... (正在添加中)
设置用户角色
rabbitmqctl set_user_tags admin administrator (添加角色administrator超级管理员)
设置用户权限
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
用户 配置读写权限
登录web
使用设置好的admin登录
集群搭建
搭建方法和单节点一致,创建好3台mq
一.修改三台主机名称
systemctl stop rabbitmq-server (先停止mq)
vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.200.108 node1
192.168.200.109 node2
192.168.200.102 node3
二.确保节点cookie文件使用同一个值
[root@node1 ~]# more /var/lib/rabbitmq/.erlang.cookie
PZIJZCVFEXCZCCXPMZFE
[root@node2 ~]# more /var/lib/rabbitmq/.erlang.cookie
GQJUECIAZXPIYQFBASUT
#对比两台主机cookie文件并不一致,集群必须保证一致性#
[root@node1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@192.168.200.109:/var/lib/rabbitmq/.erlang.cookie
root@192.168.200.109's password:
.erlang.cookie 100% 20 15.5KB/s 00:00
[root@node1 ~]# scp /var/lib/rabbitmq/.erlang.cookie root@192.168.200.102:/var/lib/rabbitmq/.erlang.cookie
root@192.168.200.102's password:
.erlang.cookie
chmod 600 /var/lib/rabbitmq/.erlang.cookie
三.启动mq服务和erlang
在3台节点上分别都执行命令
rabbitmq-server -detached (3台该命令可以重启mq和erlang)
systemctl start rabbitmq-server (3台启动mq)
四. 集群搭建
以node1为主节点,其余的node2和node3加入主节点
# 1.停止服务
rabbitmqctl stop_app
# 2.重置状态
rabbitmqctl reset
# 3.节点加入, 在一个node加入cluster之前,必须先停止该node的rabbitmq应用,即先执行stop_app
# node2加入node1, node3加入node2
rabbitmqctl join_cluster rabbit@node1
# 4.启动服务
rabbitmqctl start_app
五.查看集群状态
rabbitmqctl cluster_status
[root@node2 ~]# rabbitmqctl cluster_status
Cluster status of node rabbit@node2 ...
Basics
Cluster name: rabbit@node2
Disk Nodes
rabbit@node1
rabbit@node2
rabbit@node3
Running Nodes
rabbit@node1
rabbit@node2
rabbit@node3
Versions
rabbit@node1: RabbitMQ 3.8.8 on Erlang 21.3.8.16
rabbit@node2: RabbitMQ 3.8.8 on Erlang 21.3.8.16
rabbit@node3: RabbitMQ 3.8.8 on Erlang 21.3.8.16
六.创建集群账号
[root@node1 ~]# rabbitmqctl add_user admin 123
Adding user "admin" ...
[root@node1 ~]# rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
[root@node1 ~]# rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
Setting permissions for user "admin" in vhost "/" ...
[root@node1 ~]#
步骤
1.创建用户admin密码123 (生产环境密码必须高难度密码)
2.给admin用户管理员身份
3.授予admin用户权限
七.登录web页面查看
无论输入那个节点ip地址:15672都可访问到集群
八.总结
操作步骤
1.
准备好安装环境,erlang-21.3.8.16-1.el7.x86_64.rpm rabbitmq-server-3.8.8-1.el7.noarch.rpm
2.
3.
解压缩安装erlang和rabbitmq
4.
5.
设置开机自启,启动,查看mq状态 安装web插件并验证web是否安装成功
6.
7.
搭建集群首先关闭mq并修改主机名称和映射文件
8.
9.
同步统一节点的cookie文件号码
10.
11.
启动mq将其他节点接入主节点来
12.
13.
查看集群状态,并创建集群用户
14.
15.
登录web页面查看集群
16.
九.注意事项
集群各节点的hosts解析 erlang的cookie要一致 指定加入的集群名要准确 erlang和rabbitmq的版本对应 创建的用户和权限要一致 时间同步
镜像队列
镜像队列又可称为备份,将单个节点上的队列复制到另一台节点上面,实现队列同步亦或者是队列复制,这样大大的保证了队列安全性,也提高了可靠性,双重保障
搭建步骤
1.
启动三台mq服务器
2.
3.
添加策略
4.
5.
6.
mirror-two 起的名字
^mirror 支持正则,以^mirror开头的队列
ha-mode=exactly 备份的模式=指定模式
ha-params=2 备份指定=2份
ha-sync-mode=automatic 同步的模式=自动同步
1.
就算集群内只剩下了一台机器,依然能处理消息队列
2.
3.
rabbitmq集群出现宕机现象他会自我选举传递备份处理消息队列
4.
项目实战
rabbitmq+haproxy+keepalived
消息队列+负载均衡+故障转移=rabbitmq高可用
HAproxy
#解压haprpxy
tar xf haproxy-2.1.10.tar.gz
#进入目录编译安装
cd /opt/haproxy-2.1.10
make TARGET=linux-glibc PREFIX=/opt/haproxy-2.1.10
make install PREFIX=/opt/haproxy-2.1.10
#设置环境变量并生效
vim /etc/profile
export HAPROXY_HOME=/opt/haproxy-2.1.10
export PATH=$PATH:$HAPROXY_HOME/sbin
source /etc/profile
#查看版本验证安装是否成功
haproxy -v
HA-Proxy version 2.1.10-7aff177 2020/11/05 - https://haproxy.org/
Status: stable branch - will stop receiving fixes around Q1 2021.
Known bugs: http://www.haproxy.org/bugs/bugs-2.1.10.html
Running on: Linux 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64
配置haproxy文件
mkdir /etc/haproxy
vim /etc/haproxy/haproxy.cfg
# 全局配置
global
# 日志输出配置、所有日志都记录在本机,通过 local0 进行输出
log 127.0.0.1 local0 info
# 最大连接数
maxconn 4096
# 改变当前的工作目录
chroot /opt/haproxy-2.1.10
# 以指定的 UID 运行 haproxy 进程
uid 99
# 以指定的 GID 运行 haproxy 进程
gid 99
# 以守护进行的方式运行
daemon
# 当前进程的 pid 文件存放位置
pidfile /opt/haproxy-2.1.10/haproxy.pid
# 默认配置
defaults
# 应用全局的日志配置
log global
# 使用4层代理模式,7层代理模式则为"http"
mode tcp
# 日志类别
option tcplog
# 不记录健康检查的日志信息
option dontlognull
# 3次失败则认为服务不可用
retries 3
# 每个进程可用的最大连接数
maxconn 2000
# 连接超时
timeout connect 5s
# 客户端超时
timeout client 120s
# 服务端超时
timeout server 120s
# 绑定配置
listen rabbitmq_cluster
bind :15671
# 配置TCP模式
mode tcp
# 采用加权轮询的机制进行负载均衡
balance roundrobin
# RabbitMQ 集群节点配置
server mq-node1 node1:15672 check inter 5000 rise 2 fall 3 weight 1
server mq-node2 node2:15672 check inter 5000 rise 2 fall 3 weight 1
server mq-node3 node3:15672 check inter 5000 rise 2 fall 3 weight 1
# 配置监控页面
listen monitor
bind :8100
mode http
option httplog
stats enable
stats uri /stats
stats refresh 5s
#启动haproxy配置文件
haproxy -f /etc/haproxy/haproxy.cfg
网页访问
访问haproxy网址http://192.168.200.102:8100/stats检查是否配置成功,所有节点表示绿色mq集群状态健康。
keepalived
keepalived配置文件
主节点配置文件
vim keepalived.conf
global_defs {
# 路由id,主备节点不能相同
router_id node1
notification_email {
# email 接收方
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# email 发送方
notification_email_from Alexandre.Cassen@firewall.loc
# 邮件服务器, smtp 协议
smtp_server 192.168.200.1
smtp_connect_timeout 30
vrrp_skip_check_adv_addr
# 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
#vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
# 自定义监控脚本
vrrp_script chk_haproxy {
# 脚本位置
script "/etc/keepalived/haproxy_check.sh"
# 脚本执行的时间间隔
interval 5
weight 10
}
vrrp_instance VI_1 {
# Keepalived的角色,MASTER 表示主节点,BACKUP 表示备份节点
state MASTER
# 指定监测的网卡,可以使用 ifconfig 进行查看
interface ens32
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 51
# 优先级,主节点的优先级需要设置比备份节点高
priority 100
# 设置主备之间的检查时间,单位为秒
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.200.108
unicast_peer {
192.168.200.102
}
# 定义验证类型和密码
authentication {
auth_type PASS
auth_pass 123456
}
# 调用上面自定义的监控脚本
track_script {
chk_haproxy
}
virtual_ipaddress {
# 虚拟IP地址,可以设置多个
192.168.200.127
}
}
vrrp_instance VI_2 {
state BACKUP
interface ens32
virtual_router_id 90
priority 50
advert_int 1
unicast_src_ip 192.168.200.102
unicast_peer {
192.168.200.108
}
authentication {
auth_type PASS
auth_pass 123456
}
track_script {
chk_haproxy
}
virtual_ipaddress {
192.168.200.128
}
}
从节点配置文件
vim keepalived.conf
global_defs {
# 路由id,主备节点不能相同
router_id node2
notification_email {
# email 接收方
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
# email 发送方
notification_email_from Alexandre.Cassen@firewall.loc
# 邮件服务器, smtp 协议
smtp_server 192.168.200.1
smtp_connect_timeout 30
vrrp_skip_check_adv_addr
# 使用 unicast_src_ip 需要注释 vrrp_strict,而且也可以进行 ping 测试
#vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script chk_haproxy {
script "/etc/keepalived/haproxy_check.sh"
interval 5
weight 10
}
vrrp_instance VI_1 {
# BACKUP 表示备份节点
state BACKUP
# 指定监测的网卡
interface ens32
# 虚拟路由的id,主备节点需要设置为相同
virtual_router_id 90
# 优先级,备份节点要比主节点低
priority 50
advert_int 1
# 如果两节点的上联交换机禁用了组播,则采用 vrrp 单播通告的方式
unicast_src_ip 192.168.200.102
unicast_peer {
192.168.200.108
}
authentication {
auth_type PASS
auth_pass 123456
}
track_script {
chk_haproxy
}
virtual_ipaddress {
192.168.200.127
}
}
vrrp_instance VI_2 {
state MASTER
interface ens32
virtual_router_id 51
priority 100
advert_int 1
unicast_src_ip 192.168.200.108
unicast_peer {
192.168.200.102
}
authentication {
auth_type PASS
auth_pass 123456
}
track_script {
chk_haproxy
}
virtual_ipaddress {
192.168.200.128
}
}
互为主备配置文件防止脑裂问题出现
配置 HAProxy 检查脚本
vim /etc/keepalived/haproxy_check.sh
#!/bin/bash
A=`ps -C haproxy --no-header |wc -l`
# 判断haproxy是否已经启动
if [ $A -eq 0 ] ; then
#如果没有启动,则启动
haproxy -f /etc/haproxy/haproxy.cfg
fi
#睡眠3秒以便haproxy完全启动
sleep 3
#如果haproxy还是没有启动,此时需要将本机的keepalived服务停掉,以便让VIP自动漂移到另外一台haproxy
if [ $A -eq 0 ] ; then
systemctl stop keepalived
fi
#给脚本添加执行权限
chmod +x /etc/keepalived/haproxy_check.sh
#配置ip转发
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
#生效
sysctl -p
#启动keepalived并设置开机自启
systemctl start keepalived
systemctl enable keepalived
测试vip漂移
由于是双主模式会有两个vip127和128,两个vip目前均可访问到haproxy的界面,当关闭node1节点上的keepalived的时候,127和128还可以进行访问证明漂移成功没有问题,为了验证是否双主配置真的起效,关闭node2和node1两个节点keepalived发现vip不见了,再次证明双主漂移都可以实现,这也是一种双重保障
192.168.200.128
192.168.200.127
关闭双节点发现都无法访问到了,实验证明双主模式成功