Like
Like Love Haha Wow Sad Angry

一、架构

二、基础概念

  高可用,通俗的来说就是一台服务器宕机了,另一台马上接替,对于用户而言毫无感知的。专业的来说,就是尽可能减少服务的宕机时间。
  keepalived作为这么一种高可用解决方案的软件,主要就是通过VRRP协议(虚拟路由器冗余协议)来实现高可用功能的,VRRP协议的主要目的就是为了解决路由单点故障问题的。
  这么说keepalived其实就是将一组服务器组成一个热备组,这个组通过共享一个虚拟IP地址和MAC地址,来维护一个虚拟路由器。在任一时刻,该组中只有一个服务器是活跃的,这个虚拟IP也是处在活跃服务器上,其他处于备用模式。如果活跃服务器发生故障,那么这个虚拟IP会立刻漂移到备用服务器,备用服务器将会立刻接替其工作,这个接替对于访问的用户来说无感知的,因为虚拟IP是始终没有改变,所以仍能保持连接,不受故障影响。
  keepalived是利用优先级来决定那个服务器成为活跃服务器,那个服务器的优先级高,则那个为活跃服务器。如果活跃服务器发生故障,备用服务器没有收到活跃服务器发出的VRRP 广播报文,则备用服务器就会成为新的活跃服务器。

三、配置keepalived服实现高可用

  环境搭建:一台nginx四层负载均衡,两台nginx七层负载均衡,两个后端web节点,都提前部署好,这里不再赘述如何搭建。

(1)抢占模式

[root@lb02 ~]# yum install -y keepalived
[root@lb02 ~]# vim /etc/keepalived/keepalived.conf
global_defs {               # 全局配置段
   router_id lb02           # 路由标识,同一个局域网内唯一的。
}

vrrp_instance VI_1 {        # VRRP协议配置端,这里定义一个名为VI_1的VRRP实例,用于配置一个VRRP服务。
    state MASTER            # 当前实例VI_1的角色状态,这个状态分MASTER和BACKUP两种状态。
    interface ens33         # 绑定的对外提供服务的网络接口,虚拟机IP会配置到这个网卡上。
    virtual_router_id 50    # 虚拟路由标识,同一个VRRP实例使用相同的唯一标识。
    priority 100            # 优先级
    advert_int 1            # 发送VRRP广播报文的时间间隔,单位为秒。
    authentication {        # 验证相关
        auth_type PASS      # 验证类型为密码,类型主要有PASS和AH两种。
        auth_pass 0000      # 验证密码,其为明文,同一VRRP实例MASTER与BACKUP使用相同的密码才能正常通信。
    }
    virtual_ipaddress {     #虚拟IP地址,即VIP
        10.0.0.3
    }   
}

[root@lb03 ~]# yum install -y keepalived
[root@lb03 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
    router_id lb03
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 50
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 0000
    }
    virtual_ipaddress {
        10.0.0.3
    }
}

测试:

[root@lb02 ~]# systemctl start keepalived       //我们启动keepalived主节点
[root@lb02 ~]# ip a show ens33                  //可以发现在ens33网卡下,多了一个VIP地址
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:72:d9:a3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.3/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::3bc6:290a:7d47:706/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@lb03 ~]# systemctl start keepalived       //我们启动keepalived备节点
[root@lb03 ~]# ip a show ens33                  //没有变化
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:27:27:71 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.6/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::aef:b68a:d2e7:4e3f/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

此时我们模拟lb02服务器宕机,可以发现VIP立即从lb02服务器漂移到了lb03服务器上。

[root@lb02 ~]# systemctl stop keepalived
[root@lb02 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:72:d9:a3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::3bc6:290a:7d47:706/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@lb03 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:27:27:71 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.6/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.3/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::aef:b68a:d2e7:4e3f/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

(2)非抢占模式

  通过上面我们可以发现,当主节点重新恢复正常,那么因为优先级会抢占VIP,VIP又会重新漂移到主节点,这样就发生了两次VIP地址漂移,其中第二次其实是不必要的VIP地址漂移。
  为了避免这个情况,我们可以配置非抢占模式,即主节点故障,备节点接管,但主节点恢复了不会抢占VIP,除非备节点故障,主节点才会再次接管VIP。
  配置非抢占模式主要有两个点:一是两个节点的状态都必须配置为BACKUP;二就是两个节点都在vrrp_instance中添加nopreempt参数即可。

[root@lb02 ~]# vim /etc/keepalived/keepalived.conf      //修改添加以下参数
...
vrrp_instance VI_1 {
    state BACKUP
    nopreempt
    ...
}
[root@lb02 ~]# systemctl restart  keepalived

[root@lb03 ~]# vim /etc/keepalived/keepalived.conf      //修改添加以下参数
... ...
vrrp_instance VI_1 {
    state BACKUP
    nopreempt
    ......
}
[root@lb03 ~]# systemctl restart  keepalived

  测试:模拟lb02宕机,可以发现VIP立即从lb02漂移到了lb03上。重新恢复lb02服务,发现VIP没有发生漂移,还在lb03上。

[root@lb02 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:72:d9:a3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.3/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::3bc6:290a:7d47:706/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
[root@lb02 ~]# systemctl stop keepalived

[root@lb03 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:27:27:71 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.6/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.3/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::aef:b68a:d2e7:4e3f/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@lb02 ~]# systemctl restart keepalived
[root@lb02 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:72:d9:a3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.5/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::3bc6:290a:7d47:706/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@lb03 ~]# ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:27:27:71 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.6/24 brd 10.0.0.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet 10.0.0.3/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::aef:b68a:d2e7:4e3f/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

四、扩展

(1)定义keepalived服务日志路径

keepalived服务日志默认会记录在/var/log/message下,观测起来不直观。

[root@lb02 ~]# vim /etc/sysconfig/keepalived        //参数含义,配置文件中有解释
KEEPALIVED_OPTIONS="-D -d -S 0"

[root@lb02 ~]# vim /etc/rsyslog.conf        // 配置rsyslog,定义服务日志存放路径
local0.*               /var/log/keepalived.log

[root@lb02 ~]# systemctl restart keepalived rsyslog
[root@lb02 ~]# tailf /var/log/keepalived.log 
...
Sep  9 07:02:19 lb02 Keepalived_vrrp[7619]: VRRP_Instance(VI_1) Sending/queueing gratuitous ARPs on ens33 for 10.0.0.3
Sep  9 07:02:19 lb02 Keepalived_vrrp[7619]: Sending gratuitous ARP on ens33 for 10.0.0.3
Sep  9 07:02:19 lb02 Keepalived_vrrp[7619]: Sending gratuitous ARP on ens33 for 10.0.0.3
...

(2)地址漂移问题

  我们有没有想过VIP是什么时候才会漂移呢,一是 keepalived服务停止了,二就是服务器出问题了关机或者重启了。
  那么问题来了,作为提供负载均衡的nginx服务如果出现故障了,而VIP却没有漂移,这就会导致网站服务访问失败。所以我们就需要编写一个脚本,用来探测Nginx是否存活,如果不存活则尝试启动,如果还没有存活,则强制停止keepalived服务,让VIP地址漂移。

#!/bin/bash

# 检测nginx进程是否存在,-C按名称匹配进程,--no-headers不显示列名。
nginx_pid=$(ps -C nginx --no-headers|wc -l)

# 判断Nginx是否存活,如果不存活则尝试启动Nginx。
if [ $nginx_pid -eq 0 ];then
    systemctl start nginx
    sleep 2

    # 等待2秒后再次获取一次Nginx状态。
    nginx_pid=$(ps -C nginx --no-header|wc -l) 

    # 再次进行判断, 如果Nginx还不存活则停止Keepalived服务,让地址进行漂移。 
    if [ $nginx_pid -eq 0 ];then
        systemctl stop keepalived
   fi
fi

keepalived调用脚本

[root@lb02 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
    router_id lb02
}

vrrp_script check_web {              #定义脚本路径,定义脚本多久执行一次,定义名称check_web
    script "/root/check.sh"
    interval 5
}

vrrp_instance VI_1 {
    state BACKUP
    nopreempt
    interface ens33
    virtual_router_id 50
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 0000
    }
    virtual_ipaddress {
        10.0.0.3
    }   
    track_script {      #调用脚本
        check_web
    }
}

测试:

[root@lb02 ~]# systemctl stop nginx
[root@lb02 ~]# netstat -ntlp | grep nginx
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:22              0.0.0.0:*               LISTEN      6890/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      6976/master         
tcp6       0      0 :::22                   :::*                    LISTEN      6890/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      6976/master         
[root@lb02 ~]# netstat -ntlp
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:80              0.0.0.0:*               LISTEN      8064/nginx: master  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      6890/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      6976/master         
tcp6       0      0 :::22                   :::*                    LISTEN      6890/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      6976/master 

(3)脑裂问题

  当两个节点同时认为自己是唯一处于活动状态的时候,从而出现了VIP抢占,双方都在抢占资源的情况下,称为脑裂。
  出现脑裂问题原因,主要就是VRRP广播报文因为某些原因导致发送或者接收问题(例如网络原因、防火墙原因等),导致双方接收不到报文,都认为对方故障,自身是唯一存活的,从而出现脑裂。

Like
Like Love Haha Wow Sad Angry

发表评论