HAproxy介绍
Keepalive介绍
应用服务器对只读的应用程序连接虚拟IP地址,连接到haproxy,然后通过haproxy将TCP协议转移到下面的2个MySQL SLAVE数据库服务器中。Haproxy在此做4层的TCP交换服务。keepalived为了防止haproxy单点故障。但是我这里使用两个VIP(虚拟IP)就可以做到haproxy代理服务器的高可用负载均衡。对于这两个VIP而言,可以添加两条DNS记录进行轮训,也可以在程序中直接分开使用,当任何一个haproxy节点有问题时这两个VIP都能转到同一个节点上继续提供服务。
一、MySQL配置
这里安装两个MySQL实例,由于我是测试环境,我这里就在同一台机器上创建两个数据库实例进行测试(3306和3307)。数据库安装这里就不介绍了,但为了测试需要在两个实例中分别创建一个haproxy账号。
10.99.73.10:(3306,3307)
1 2 3 4 5 |
mysql> grant all on *.* to 'haproxy'@'%' identified by '123456'; Query OK, 0 rows affected, 2 warnings (0.00 sec) mysql> flush privileges; Query OK, 0 rows affected (0.00 sec) |
二、haproxy+keepalived配置
在配置之前,先将HA中个节点进行时间同步,主机名之间相互解析,以及配置双机互信,关闭防火墙和selinux。
haproxy-01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[root@haproxy-01 ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) [root@haproxy-01 ~]# systemctl stop firewalld [root@haproxy-01 ~]# setenforce 0 [root@haproxy-01 ~]# cat /etc/hosts 172.29.28.193 haproxy-01 172.29.28.195 haproxy-02 [root@haproxy-01 ~]# ssh-keygen -t rsa -P '' [root@haproxy-01 ~]# ssh-copy-id haproxy-02 [root@haproxy-01 ~]# yum install ntp [root@haproxy-01 ~]# ntpdate s2c.time.edu.cn |
haproxy-02
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[root@haproxy-01 ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) [root@haproxy-02 ~]# systemctl stop firewalld [root@haproxy-02 ~]# setenforce 0 [root@haproxy-02 ~]# cat /etc/hosts 172.29.28.193 haproxy-01 172.29.28.195 haproxy-02 [root@haproxy-02 ~]# ssh-keygen -t rsa -P '' [root@haproxy-02 ~]# ssh-copy-id haproxy-01 [root@haproxy-02 ~]# yum install ntp [root@haproxy-02 ~]# ntpdate s2c.time.edu.cn |
安装haproxy和keepalived
1 2 3 4 5 6 |
[root@haproxy-01 ~]# yum install keepalived haproxy -y [root@haproxy-02 ~]# yum install keepalived haproxy -y [root@haproxy-01 ~]# keepalived -v Keepalived v1.2.13 (11/05,2016) [root@haproxy-01 ~]# haproxy -v HA-Proxy version 1.5.18 2016/05/10 |
配置(haproxy-01,haproxy-02)
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 |
[root@haproxy-01 ~]# cat /etc/haproxy/haproxy.cfg #--------------------------------------------------------------------- # global configure #--------------------------------------------------------------------- global #定义全局配置段; log 127.0.0.1 local2 #通过rsyslog将日志进行归档记录; pidfile /var/run/haproxy.pid #指定pid文件; maxconn 8000 #最大并发连接数; user haproxy #运行haproxy的用户; group haproxy #运行haproxy的组; daemon #以守护进程的形式运行,即后台运行; #--------------------------------------------------------------------- # common defaults that all the 'listen' and 'backend' sections will # use if not designated in their block #--------------------------------------------------------------------- defaults #默认配置端; mode http #工作模式,源码包编译默认为tcp; log global #记录全局日志; option httplog #详细记录http日志; option dontlognull #不记录健康检测的日志信息; option http-server-close #启用服务器端主动关闭功能; option forwardfor except 127.0.0.0/8#传递client端IP至后端real server; option redispatch #基于cookie做会话保持时,后端对应存放session的服务器出现故障时,会话会被重定向至别的服务器; retries 3 #请求重传次数; timeout http-request 10s #断开客户端连接的时长; timeout queue 1m #一个请求在队列里的超时时长; timeout connect 10s #设定在haproxy转发至后端upstream server时等待的超时时长; timeout client 1m #client的一次非活动状态的超时时长; timeout server 1m #等待服务器端的非活动的超时时长; timeout http-keep-alive 10s #持久连接超时时长; timeout check 10s #检查请求连接的超时时长; maxconn 3000 #最大连接数; listen mysql_3306 *:3306 mode tcp option tcpka balance roundrobin #将此server命名为mysql_01,每隔3000ms检测一个健康状态,如果检测3次都失败,将此server剔除,在离线的状态下,只要检测1次成功,就让其上线; server mysql_01 10.99.73.10:3306 check inter 3000 rise 1 maxconn 4000 fall 3 server mysql_02 10.99.73.10:3307 check inter 3000 rise 1 maxconn 4000 fall 3 listen state #使用单独输出,不需要frontedn调用:定义haproxy的状态统计页面; bind *:8080 #监听的地址; mode http #http 7层工作模式:对应用层数据做深入分析,因此支持7层的过滤、处理、转换等机制; stats enable #开启统计页面输出; stats hide-version #隐藏状态页面版本号; stats uri /haproxyadmin?stats #指定状态页的访问路径; stats auth admin:admin #基于用户名,密码验证; stats admin if TRUE #验证通过时运行登录; acl num1 src 172.29.0.0/16 #定义源地址为172.29.0.0/16网段的acl规则,将其命名为num1; tcp-request content accept if num1 #如果满足此规则,则允许访问; tcp-request content reject #拒绝其他所有的访问; |
对于global端的log配置,需要在/etc/rsyslog.conf配置文件中,添加’local2.* /var/log/haproxy.log’,并且启用$ModLoad imudp,$UDPServerRun 514,$ModLoad imtcp,$InputTCPServerRun 514此四项功能,最后重启rsyslog进程。
1 2 3 4 5 6 7 8 9 |
# Provides UDP syslog reception $ModLoad imudp $UDPServerRun 514 # Provides TCP syslog reception $ModLoad imtcp $InputTCPServerRun 514 local2.* /var/log/haproxy.log |
1 |
[root@haproxy-01 ~]# systemctl restart rsyslog.service |
启动两个节点
1 |
[root@haproxy-01 ~]# systemctl restart haproxy |
配置keepalived:双主模型
haproxy-01
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 |
[root@haproxy-01 ~]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { #定义收件人邮箱; 18612100045@163.com } notification_email_from root #定义发件人邮箱; smtp_server localhost #定义邮件服务器地址; smtp_connect_timeout 30 #定有邮件服务器连接超时时长为30秒; router_id LVS_DEVEL #运行keepalive的机器的标识; } vrrp_instance VI_1 { #定义VRRP实例,实例名自定义; state MASTER #指定当前节点的角色,master为主,backup为从; interface eno16777736 #直接HA监测的接口; virtual_router_id 51 #虚拟路由标识,在同一VRRP实例中,主备服务器ID必须一样; priority 100 #定义节点优先级,数字越大越优先,主服务器优先级高于从服务器; advert_int 1 #设置主备之间永不检查时间间隔,单位为秒; authentication { #设置主从之间验证类型和密码; auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.29.28.243 #定义虚拟ip地址; } } vrrp_instance VI_2 { state BACKUP interface eno16777736 virtual_router_id 52 priority 50 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.29.28.254 } } |
haproxy-02
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 |
[root@haproxy-02 ~]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { 18612100045@163.com } notification_email_from root smtp_server localhost smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_instance VI_1 { state BACKUP interface eno16777736 virtual_router_id 51 priority 50 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.29.28.253 } } vrrp_instance VI_2 { state MASTER interface eno16777736 virtual_router_id 52 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.29.28.254 } } |
PS:修改了优先级和角色。
重启keepalived
1 2 |
[root@haproxy-01 ~]# systemctl restart keepalived.service [root@haproxy-02 ~]# systemctl restart keepalived.service |
查看启动情况
1 2 3 4 5 6 7 8 9 |
[root@haproxy-01 ~]# netstat -nplt 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:3306 0.0.0.0:* LISTEN 3351/haproxy [root@haproxy-02 ~]# netstat -nplt 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:3306 0.0.0.0:* LISTEN 3355/haproxy |
查看这两个节点获取IP的情况
1 2 3 4 5 6 7 8 9 |
[root@haproxy-01 ~]# ip addr show eno16777736 2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:03:cc:88 brd ff:ff:ff:ff:ff:ff inet 172.29.28.193/22 brd 172.29.31.255 scope global dynamic eno16777736 valid_lft 85737sec preferred_lft 85737sec inet 172.29.28.253/32 scope global eno16777736 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fe03:cc88/64 scope link valid_lft forever preferred_lft forever |
1 2 3 4 5 6 7 8 9 |
[root@haproxy-02 ~]# ip addr show eno16777736 2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:d7:d3:ae brd ff:ff:ff:ff:ff:ff inet 172.29.28.195/22 brd 172.29.31.255 scope global dynamic eno16777736 valid_lft 85000sec preferred_lft 85000sec inet 172.29.28.254/32 scope global eno16777736 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fed7:d3ae/64 scope link valid_lft forever preferred_lft forever |
通过这两个节点的的IP可以看出,haproxy-01节点担任172.29.28.253的主,haproxy-02担任172.29.28.254的主,达到了负载均衡的效果。
三、测试
3.1 测试负载均衡
先来测试双VIP负载均衡效果,随便找个机器使用mysql客户端分别连接VIP地址,haproxy使用的调度算法是轮训,所以应该是每次分配到一个不同的real server服务器,效果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ mysql -h 172.29.28.253 -P3306 -uhaproxy -p123456 mysql> show variables like 'port'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3306 | +---------------+-------+ 1 row in set (0.00 sec) $ mysql -h 172.29.28.253 -P3306 -uhaproxy -p123456 mysql> show variables like 'port'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3307 | +---------------+-------+ 1 row in set (0.00 sec) |
然后,我们也可以测试另一个VIP。
1 2 3 4 5 6 7 8 |
$ mysql -h 172.29.28.254 -P3306 -uhaproxy -p123456 mysql> show variables like 'port'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | port | 3306 | +---------------+-------+ 1 row in set (0.00 sec) |
3.2 测试故障转移
我们关闭掉haproxy-01节点。
1 |
[root@haproxy-01 ~]# systemctl stop keepalived.service |
然后去看haproxy-02节点漂移过来的VIP。
1 2 3 4 5 6 7 8 9 10 11 |
[root@haproxy-02 ~]# ip addr show eno16777736 2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:0c:29:d7:d3:ae brd ff:ff:ff:ff:ff:ff inet 172.29.28.195/22 brd 172.29.31.255 scope global dynamic eno16777736 valid_lft 82015sec preferred_lft 82015sec inet 172.29.28.253/32 scope global eno16777736 valid_lft forever preferred_lft forever inet 172.29.28.254/32 scope global eno16777736 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fed7:d3ae/64 scope link valid_lft forever preferred_lft forever |
现在我们可以看出,两个IP都漂移到了haproxy-02节点上了,再把haproxy-01打开后,172.29.28.100又会飘回去。
并且在这期间我一直ping主节点的VIP,在切换过程中很快,只丢了两个包。
1 2 3 4 5 |
64 bytes from 172.29.28.254: icmp_seq=12 ttl=64 time=0.398 ms 64 bytes from 172.29.28.254: icmp_seq=15 ttl=64 time=0.061 ms .......... --- 172.29.28.254 ping statistics --- 44 packets transmitted, 42 received, 4% packet loss, time 43009ms |
四、状态页面
在haproxy配置文件中提供了haproxy web,用来查看haproxy状态的。
访问:http://172.29.28.193:8080/haproxyadmin?stats
这个界面提供了很多信息,具体可以查询相关资料。
五、测试HAproxy对后端健康状态检查
在haproxy配置时,有这么两条记录。
1 2 |
server mysql_01 10.99.73.10:3306 check inter 3000 rise 1 maxconn 4000 fall 3 server mysql_02 10.99.73.10:3307 check inter 3000 rise 1 maxconn 4000 fall 3 |
将此server命名为mysql_01,每隔3000ms检测一个健康状态,如果检测3次都失败,将此server剔除,在离线的状态下,只要检测1次成功,就让其上线。
下面就来测试这些规则,首先找一台mysql客户端一直跑这个脚本,主要测试后端负载均衡。
1 2 3 |
while true;do mysql -h 172.29.28.253 -P3306 -uhaproxy -p123456 -e "show variables like 'port';" -Bn | grep port done |
然我们在后端(MySQL)主机上,添加一条iptables模拟3306端口故障。
1 2 3 4 5 |
# 添加拒绝访问3306端口的规则; $ iptables -A INPUT -p tcp --dport 3306 -j REJECT # 删除拒绝访问3306端口的规则; $ iptables -D INPUT -p tcp --dport 3306 -j REJECT |
查看状态页面,会发现haproxy已经剔除了3306端口,从状态页面可以看出Chk看到向后端检查了3次,Dwntme表示宕机的时间。
最后可以当一台后端MySQL故障后,看脚本执行情况。
六、为keepalived提供检测haproxy的脚本
通过前面的keepalived故障模拟可以看出,当keepalived挂掉之后,或者当主机宕机时,VIP是可以切换到备机工作。但是如果keepalived没有挂,并且主机也没有宕机,而是haproxy自身挂掉了呢?这个时候不会有任何切换动作,下面我们要做的就是为keepalived提供一个脚本用来检测haproxy是否正常工作,如果没有正常工作可以再次启动haproxy,或者关闭keepalived自身。这样一来,keepalived自身挂掉了,那么VIP就可以切换到备机上工作了。