Keepalived 高可用服务

一、Keepalived 详解配置

1、Keepalived 软件介绍:
Keeplived 软件起初就是专为 LVS 负载均衡软件设计的,用来管理并监控 LVS 集群系统中各个服务器节点的状态,后来又加入了可以实现高可用的 VRRP 功能。因此 Keepalived 除了能够管理 LVS 软件外,还可以作为其他服务(Nginx、Haproxy、MySQL 等)的高可用解决方案软件。
Keeplived 软件主要是通过 VRRP 协议实现高可用功能的,VRRP 出现的目的就是为了解决静态路由单点故障问题的,它能够保证当个别节点宕机时,整个网络可以不间断的运行,所以 Keepalived 一方面具有配置管理 LVS 的功能,同时还具有对 LVS 下面节点进行健康检查的功能,另一方面也可实现系统网络服务的高可用性。
Keeplived 软件的官方网站是 http://www.keepalived.org
2、Keeplived 高可用故障切换转移原理:
Keeplived 高可用服务对之间的故障切换转移,是通过 VRRP 协议(Virtual Router Redundancy Protocol,中文意思:虚拟路由器冗余协议)来实现的。
在 Keepailved 服务正常工作时,主 Master 节点会不断地向备节点发送(多播的方式)心跳消息,用以告诉备 Backup 节点自己还活着,当主 Master 节点发生故障时,就无法发送心跳信息了,备节点也就因此无法继续监测到来自主 Master 节点的心跳了,进而调用自身的接管程序,接管主 Master 节点的 IP 资源及服务。而当主 Master 节点恢复时,备 Bacckup 节点又会释放主节点故障时自身接管的 IP 资源及服务,恢复到原来的备用角色。
3、企业面试题:简要回答 Keeplived 的工作原理:
Keeplived 软件高可用对之间是通过 VRRP 协议通信的,因此,我从 VRRP 协议介绍开始:
① VRRP 协议全称 Virtual Router Redundancy Protocol,中文意思:虚拟路由器冗余协议。它的出现是为了解决静态路由的单点故障;
② VRRP 协议是通过一种竞选协议机制来将路由任务交给某台 VRRP 路由器的;
③ VRRP 协议是通过 IP 多播方式(默认多播地址 224.0.0.18)实现高可用对之间通信的;
④ 工作主节点发包,备节点接包,当备节点接收不到主节点发的数据包的时候,就启动接管程序接管主节点的资源,备节点可以有多个,通过优先级竞选,但一般 Keepalived 系统运维工作中都是用一对。
⑤ VRRP 使用了加密协议加密数据,但 Keepalived 官方目前还是推荐用明文的方式配置认证类型和密码。
介绍完了 VRRP 协议,接下来介绍 Keepalived 服务的工作原理:
Keepalived 高可用对之间是通过 VRRP 协议进行通信的,VRRP 协议是通过竞选机制来确定主备的,主优先级高于备,因此工作时主会优先获得所有的资源,备节点处于等待状态,当主挂了的时候,备节点就会接管主节点的资源,然后顶替主节点对外提供服务。
在 Keepalived 服务对之间,只有作为主的服务器会一直发送 VRRP 广播包,告诉备它还活着,此时备不会抢占主,当主不可用时,即备监听不到主发送的广播包时就会启动相关服务接管资源,保证业务的连续性,接管速度最快可以小于 1 秒。
4、keepalived 高可用服务搭建:
1)、搭建环境准备:
Keepalived 高可用服务
2)、Keepalived 软件安装:
a、在两台负载均衡服务器安装 Keepalived 软件:

[root@lb01 ~]# yum install keepalived -y
[root@lb01 ~]# rpm -qa keepalived
keepalived-1.2.13-5.el6_6.x86_64

b、在两台负载均衡服务器启动 Keepalived 软件:

[root@lb01 ~]# /etc/init.d/keepalived start
Starting keepalived:         [  OK  ]
[root@lb01 ~]# ps -ef|grep keep|grep -v grep        # 有三个进程表示正常
root      1186     1  0 Jul26 ?        00:00:03 /usr/sbin/keepalived -D
root      1187  1186  0 Jul26 ?        00:00:03 /usr/sbin/keepalived -D
root      1188  1186  0 Jul26 ?        00:00:12 /usr/sbin/keepalived -D

c、添加虚拟 IP 的两种方式:

        ① ifconfig eth0:0 192.168.153.100/24 up
        ② ip addr add 192.168.153.100/24 dev eth0 label eth0:1  #  这种给添加的 IP 加标签的方式可以用 ifconfig 命令查到添加的 IP,否则只能用 ip add 查看添加的 IP。
        提示:Keepalived 默认使用第二种方式添加的虚拟 IP 。早期的 Heartbeat 使用第一种方式添加虚拟 IP,在 Heartbeat 3.0 版本以后也使用第二种方式添加虚拟 IP 了。
[root@lb01 ~]# ip addr add 192.168.153.100/24 dev eth0 label eth0:1
[root@lb01 ~]# ip add|grep 153.100         
    inet 192.168.153.100/24 scope global secondary eth0:1

d、编辑 Keepalived 配置文件:

[root@lb01 ~]# man keepalived.conf   # Keepalived 配置文件有三个部分。
TOP HIERACHY
       GLOBAL CONFIGURATION # 全局配置

       VRRPD CONFIGURATION  # VRRP 的配置

       LVS CONFIGURATION        # 结合 LVS 的配置
[root@lb01 ~]# vim /etc/keepalived/keepalived.conf 
  1 ! Configuration File for keepalived    #  这里井号叹号都为注释。
  2 
  3 global_defs {       #  全局配置。
  4    notification_email {
  5      [email protected]          ##############
  6      [email protected]            # 这三行是接收邮件的收件人(没什么用)。
  7      [email protected]        ##############
  8    }
  9    notification_email_from [email protected]    #  发件人。
 10    smtp_server 192.168.200.1        #  邮件服务器。
 11    smtp_connect_timeout 30           #  邮件服务器。
 12    router_id LVS_DEVEL    #  路由 ID,不同机器之间不能重复。
 13 }
 14 
 15 vrrp_instance VI_1 {    #  VRRP 实例【VI_1 是实例名字,可以配多个(VI_2等)】。
 16     state MASTER        #  角色(主),傀儡、不决定主备。
 17     interface eth0          #  通信的接口。
18     virtual_router_id 51  #  该实例的 ID,不同的实例 ID 要不同。
19     priority 150               #  优先级,竞选看优先级(决定主备的参数)。
 20     advert_int 1             #  通信检查间隔时间为 1 s,发广播的间隔时间内从 Backup 服务器没有接收到广播就接替工作。
 21     authentication {       #  主备通信方式。
 22         auth_type PASS  #  认证机制,明文的密码方式。
 23         auth_pass 1111   #  认证的密码。
 24     }
 25     virtual_ipaddress {   #  VIP 虚拟 IP,可以是一组也可以是一个。  
 26         192.168.153.100/24 dev eth0 label eth0:1
 27     }
 28 }
  上面为主服务器的配置文件,绿色的部分都是备服务器需要修改的:
12    router_id LVS_DEVEL1
16     state BACKUP
19     priority 100

e、Master 节点和 Backup 节点特殊参数的不同:
Keepalived 高可用服务
3)、此时查看两台服务器上面的虚拟 IP:

      在主节点查看虚拟 IP 的存在:
[root@lb01 ~]# ip add|grep 153.100                 #  主 Master 节点有添加的虚拟 IP(优先级高)。
    inet 192.168.153.100/24 scope global secondary eth0:1
      在备节点查看虚拟 IP 的存在:
[root@lb02 ~]# ip add |grep 153.100         #  备 Backup 节点没有(主正常,备等待)。

4)、以 Windows为客户端测试主备节点的高可用:
① 通过 Windows 客户端连续 ping 虚拟 IP:
Keepalived 高可用服务
② 此时在主节点可以看到虚拟 IP :

[root@lb01 ~]# ip add|grep 192.168.136.100
    inet 192.168.136.100/24 scope global secondary eth0:1

③ 关掉主节点的 Keepalived 服务:

[root@lb01 ~]# /etc/init.d/keepalived stop
Stopping keepalived:          [  OK  ] 

④ 查看备节点的虚拟 IP(备接管主的工作):

[root@lb02 ~]# ip add|grep 192.168.136.100
    inet 192.168.136.100/24 scope global secondary eth0:1

⑤ 启动主节点的 Keepalived 服务并查看虚拟 IP :

[root@lb01 ~]# /etc/init.d/keepalived start
Starting keepalived:           [  OK  ]
[root@lb01 ~]# ip add|grep 192.168.136.100      #  略有延迟,编译安装快?
    inet 192.168.136.100/24 scope global secondary eth0:1

5)、Keepalived 多实例的配置及实现:
首先添加另一个虚拟 IP :
[root@lb01 ~]# ip addr add 192.168.153.200/24 dev eth0 label eth0:2
修改两台负载均衡器的 keepalived.conf 配置文件:
① 在 lb 01 的 keepalived.conf 配置文件添加如下内容:

vrrp_instance VI_2 {    # 表示第二个实例名字。(与第一个实例不同)
    state BACKUP        #  第二个实例的备 Backup 节点。
    interface eth0
    virtual_router_id 52    #  虚拟路由 id,不同实例要不同,同一实例主备相同。
    priority 100            #  优先级。
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1112  #  主备通信的密码,同一实例主备相同(不同实例最好区分,非必须)。
    }
    virtual_ipaddress {
        192.168.153.200/24 dev eth0 label eth0:2    #  添加的虚拟 IP 不同实例不同,网卡标签不同。
    }
}

② 在 lb 02 的 keepalived.conf 配置文件添加如下内容:

vrrp_instance VI_2 {    # 表示第二个实例名字。(与第一个实例不同)
    state MASTER        #  第二个实例的主 MASTER 节点。
    interface eth0
    virtual_router_id 52    #  虚拟路由 id,不同实例要不同,同一实例主备相同。
    priority 150            #  优先级。
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1112  #  主备通信的密码,同一实例主备相同(不同实例最好区分,非必须)。
    }
    virtual_ipaddress {
        192.168.153.200/24 dev eth0 label eth0:2·   #  添加的虚拟 IP 不同实例不同,网卡标签不同。
    }
}

③ 重启两台服务器使配置生效:

[root@lb01 ~]# /etc/init.d/keepalived restart 
Stopping keepalived:              [  OK  ]
Starting keepalived:                [  OK  ]   
[root@lb02 ~]# /etc/init.d/keepalived restart 
Stopping keepalived:              [  OK  ]
Starting keepalived:                [  OK  ]

④ 通过查看虚拟 IP 测试多实例的生效:

[root@lb01 ~]# ip add|egrep "153.100|153.200"   # 实例一优先级高的是 lb01,所以 VIP 100存在。
    inet 192.168.153.100/24 scope global secondary eth0:1
[root@lb02 ~]# ip add |egrep "153.100|153.200"     # 实例二优先级高的是 lb02,所以 VIP 200存在。
    inet 192.168.153.200/24 scope global secondary eth0:2

关闭 lb01 服务器的 Keepalived 服务:

[root@lb01 ~]# /etc/init.d/keepalived stop
Stopping keepalived:              [  OK  ]
[root@lb01 ~]# ip add |egrep "153.100|153.200"  #  此时该服务器没有 VIP 在工作了。
[root@lb02 ~]# ip add|egrep "153.100|153.200"   #  lb02 服务器接管了两个 VIP 的工作。
    inet 192.168.153.100/24 scope global secondary eth0:1
    inet 192.168.153.200/24 scope global secondary eth0:2

启动 lb01 服务器的 Keepalived 服务:

[root@lb01 ~]# /etc/init.d/keepalived start
Starting keepalived:               [  OK  ]
[root@lb01 ~]# ip add|egrep "153.100|153.200"   # 实例一优先级高的是 lb01,所以 VIP 100存在。
    inet 192.168.153.100/24 scope global secondary eth0:1
[root@lb02 ~]# ip add |egrep "153.100|153.200"  # 实例二优先级高的是 lb02,所以 VIP 200存在。
    inet 192.168.153.200/24 scope global secondary eth0:2

关闭 lb02 服务器的 Keepalived 服务:

[root@lb02 ~]# /etc/init.d/keepalived stop
Stopping keepalived:                                       [  OK  ]
[root@lb02 ~]# ip add |egrep "153.100|153.200"  #  此时该服务器没有 VIP 在工作了。
[root@lb01 ~]# ip add|egrep "153.100|153.200"   #  lb01 服务器接管了两个 VIP 的工作。
    inet 192.168.153.100/24 scope global secondary eth0:1
    inet 192.168.153.200/24 scope global secondary eth0:2

5、Keepalived 配合 Nginx 负载均衡实现高可用:
Keepalived 高可用服务
方案一:两台负载同时启动 Nginx 代理,Keepalived 负责 VIP 漂移,VIP 漂移到哪个机器哪个就提供访问:
① 检查环境:
两台 Nginx 负载均衡器的 Keepalived 服务和 Nginx 服务都是开启状态:

[root@lb01 ~]# /etc/init.d/keepalived status  
keepalived (pid  2622) is running...
[root@lb02 ~]# /etc/init.d/keepalived status
keepalived (pid  2622) is running...
[root@lnmp01 conf]# ps -ef|grep nginx|grep -v grep
root       2045      1  0 Jun22 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx      2137   2045  0 Jun22 ?        00:00:00 nginx: worker process
[root@lnmp02 conf]# ps -ef|grep nginx|grep -v grep
root       2045      1  0 Jun22 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx      2137   2045  0 Jun22 ?        00:00:00 nginx: worker process    

② 备份并编辑 Web 服务器的配置文件:

[root@lb01 conf]# pwd
/application/nginx/conf
[root@lb01 conf]# vim nginx.conf
[root@lb01 conf]# cat nginx.conf
worker_processes  1;
events {
        worker_connections  1024;
}
http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
   upstream www_server_pools{
   # ip_hash;
   server 192.168.136.150:80  weight=1;
   server 192.168.136.151:80  weight=1;
}
server {
        listen       80;
        server_name  www.etiantian.org;
        location / {
          proxy_pass http://www_server_pools;  
 }
   }    
}

③ 检查 Web01 和 Web02 服务器 www 站点首页文件:

[root@lnmp01 ~]# cat /application/nginx/html/www/index.html
www.etiantian.org 150
[root@lnmp02 ~]# cat /application/nginx/html/www/index.html
www.etiantian.org 151

④ 修改负载均衡服务器 hosts 并 curl 访问 Web 服务器:

[root@lb01 conf]# vim /etc/hosts
[root@lb01 conf]# cat /etc/hosts
192.168.153.100 www.etiantian.org    #  将域名解析到虚拟 IP。
[root@lb01 conf]# for n in `seq 10`;do curl www.etiantian.org;done   # 实现。
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151

⑤ 实现两台负载均衡器的高可用,要让它们的 Nginx 配置文件一致:

[root@lb02 conf]# cd /application/nginx/conf/
[root@lb02 conf]# vim nginx.conf   # 跟以上配置一致。
[root@lb02 conf]# ../sbin/nginx -t
nginx: the configuration file /application/nginx-1.6.3/conf/nginx.conf syntax is ok
nginx: configuration file /application/nginx-1.6.3/conf/nginx.conf test is successful
[root@lb02 conf]# ../sbin/nginx -s reload

测试 lb02 负载均衡器的工作是否正常:

[root@lb02 conf]# tail -1 /etc/hosts
192.168.136.162 www.etiantian.org   #  备节点没有 VIP,所以解析到自己的 IP 测试。
[root@lb02 conf]# for n in `seq 10`;do curl www.etiantian.org;done                  
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151
www.etiantian.org 150
www.etiantian.org 151

⑥ 在 Windows 做域名对应 VIP 的解析并通过浏览器访问:
徽标键 + R 运行窗口 drivers 命令修改 hosts如下:
192.168.136.100 www.etiantian.org
通过浏览器访问域名 www.etiantian.org:
访问到 Web 01 的首页文件:
Keepalived 高可用服务
刷新后访问到 Web 02 的首页文件:
Keepalived 高可用服务
⑦ 此时让 LB01 宕机,再访问,业务不受影响:
原因:VIP 飘到 LB 02 服务器了,lb 02 接管工作,如下:

[root@lb02 conf]# ip add|egrep 136.100
    inet 192.168.136.100/24 scope global secondary eth0:1

⑧ 开启 LB01 服务器,再访问,业务不受影响,VIP 重新飘回LB01:

[root@lb01 conf]# ip add|egrep 136.100
    inet 192.168.136.100/24 scope global secondary eth0:1
[root@lb02 conf]# ip add|egrep 136.100    #  lb02 没有 VIP 100 了。

方案二:通过 Keepalived 多实例配合 Nginx 实现双主:
www.etiantian.org 的 VIP 为 192.168.136.100 ,在 lb01 上是主。
blog.etiantian.org 的 VIP 为 192.168.136.200 ,在 lb02 上是主。
① 编辑 lb01 的 Nginx 配置文件:

[root@lb01 conf]# vim nginx.conf          
[root@lb01 conf]# cat nginx.conf                
worker_processes  1;
events {
        worker_connections  1024;
}
http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
   upstream www_server_pools{
   # ip_hash;
   server 192.168.136.150:80  weight=1;
   server 192.168.136.151:80  weight=1;
}
server {
        listen      192.168.136.100:80;
        server_name  www.etiantian.org;
        location / {
          proxy_pass http://www_server_pools;  
     }
}
server {
        listen      192.168.136.200:80;
        server_name  blog.etiantian.org;
        location / {
          proxy_pass http://www_server_pools;
   }
  }    
}

② Nginx 无法启动的问题:

[root@lb01 conf]# pkill nginx
[root@lb01 conf]# /application/nginx/sbin/nginx
nginx: [emerg] bind() to 192.168.136.200:80 failed (99: Cannot assign requested address)
[root@lb01 conf]# lsof -i :80   #  Nginx 无法启动。
[root@lb01 conf]# ifconfig|egrep 136.200    #  原因:配置文件监听了网卡上不存在的 IP。
[root@lb01 conf]# echo 'net.ipv4.ip_nonlocal_bind = 1' >>/etc/sysctl.conf   # 添加内核参数。
[root@lb01 conf]# sysctl -p|grep net.ipv4.ip_nonlocal_bind
net.ipv4.ip_nonlocal_bind = 1   # 启动 Nginx 时忽略配置中监听的 VIP 是否存在。
[root@lb01 conf]# /application/nginx/sbin/nginx   #  启动成功。
[root@lb01 conf]# lsof -i :80
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   3040  root    6u  IPv4  15768      0t0  TCP www.etiantian.org:http (LISTEN)
nginx   3040  root    7u  IPv4  15769      0t0  TCP 192.168.136.200:http (LISTEN)
nginx   3041 nginx    6u  IPv4  15768      0t0  TCP www.etiantian.org:http (LISTEN)
nginx   3041 nginx    7u  IPv4  15769      0t0  TCP 192.168.136.200:http (LISTEN)     

③ 让 lb02 服务器的 Nginx 配置文件和 lb01 相同:

[root@lb02 conf]# vim nginx.conf
[root@lb02 conf]# echo 'net.ipv4.ip_nonlocal_bind = 1' >>/etc/sysctl.conf
[root@lb02 conf]# sysctl -p|grep net.ipv4.ip_nonlocal_bind
net.ipv4.ip_nonlocal_bind = 1
[root@lb02 conf]# pkill nginx
[root@lb02 conf]# ../sbin/nginx -t
[root@lb02 conf]# ../sbin/nginx

④ 查看 Keepalilved 配置文件(多实例):
说明:192.168.136.100 这个 VIP 在 lb01 上是 MASTER,在 lb02 上是 BACKUP;
192.168.136.200 这个 VIP 在 lb02 上是 MASTER,在 lb01 上是 BACKUP;

[root@lb01 conf]# cat /etc/keepalived/keepalived.conf   #  lb01 配置。(lb02 略)
   router_id LVS_DEVEL_1
}
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.136.100/24 dev eth0 label eth0:1
    }
}
vrrp_instance VI_2 {
    state BACKUP
    interface eth0
    virtual_router_id 5
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1112
    }
    virtual_ipaddress {
        192.168.136.200/24 dev eth0 label eth0:2
    }
}

⑤ 查看两边运行的 VIP 及Web 服务器 blog 站点首页文件:

[root@lb01 conf]# ip add|egrep "136.100|136.200"   #  lb01 提供服务的 VIP 是 100。
    inet 192.168.136.100/24 scope global secondary eth0:1
[root@lb02 conf]# ip add|egrep "136.100|136.200"   #  lb02 提供服务的 VIP 是 200。
    inet 192.168.136.200/24 scope global secondary eth0:2
[root@lnmp01 ~]# cat /application/nginx/html/blog/index.html
blog.etiantian.org 150
[root@lnmp02 ~]# cat /application/nginx/html/blog/index.html
blog.etiantian.org 151

⑥ 在负载均衡器测试访问 blog 站点:

[root@lb02 conf]# vim /etc/hosts    # lb02 上面提供服务的 VIP 为 200。
192.168.136.200 blog.etiantian.org
[root@lb02 conf]# for n in `seq 10`;do curl blog.etiantian.org;done
blog.etiantian.org 150
blog.etiantian.org 151
blog.etiantian.org 150
blog.etiantian.org 151
blog.etiantian.org 150
blog.etiantian.org 151
blog.etiantian.org 150
blog.etiantian.org 151
blog.etiantian.org 150
blog.etiantian.org 151     

⑦ 在 WINDOWS 上做 hosts 解析并通过浏览器测试:
Windows 上的 hosts 解析:

192.168.136.100 www.etiantian.org
192.168.136.200 blog.etiantian.org

通过 ping 域名确保配置可用:

C:\Users\admin>ping blog.etiantian.org -t
正在 Ping blog.etiantian.org [192.168.136.200] 具有 32 字节的数据
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
C:\Users\admin>ping www.etiantian.org -t
正在 Ping www.etiantian.org [192.168.136.100] 具有 32 字节的数据:
来自 192.168.136.100 的回复: 字节=32 时间=38ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64

通过浏览器访问域名测试:
首先访问 www.etiantian.org 结果如下:
Keepalived 高可用服务
刷新后实现负载均衡:
Keepalived 高可用服务
通过访问 blog.etiantian.org 结果如下:
Keepalived 高可用服务
刷新后实现负载均衡:
Keepalived 高可用服务
⑧ 把 lb01 停掉,查看业务运行情况:
关掉后 ping 两个域名都是能通的:

 C:\Users\admin>ping blog.etiantian.org -t
正在 Ping blog.etiantian.org [192.168.136.200] 具有 32 字节的数据
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
C:\Users\admin>ping www.etiantian.org -t
正在 Ping www.etiantian.org [192.168.136.100] 具有 32 字节的数据:
来自 192.168.136.100 的回复: 字节=32 时间=38ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64

查看 lb02 负载均衡器提供服务的 VIP:

[root@lb02 conf]# ifconfig|egrep "136.100|36.200"
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0  # 该 VIP 飘到 lb02 了。
inet addr:192.168.136.200  Bcast:0.0.0.0  Mask:255.255.255.0

此时通过浏览器访问两个域名,业务是正常的(结果略)。
⑨ 重新把负载均衡器 lb01 启动,检查业务情况:
通过 ping 两个域名都能 ping 通:

C:\Users\admin>ping blog.etiantian.org -t
正在 Ping blog.etiantian.org [192.168.136.200] 具有 32 字节的数据
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.200 的回复: 字节=32 时间<1ms TTL=64
C:\Users\admin>ping www.etiantian.org -t
正在 Ping www.etiantian.org [192.168.136.100] 具有 32 字节的数据:
来自 192.168.136.100 的回复: 字节=32 时间=38ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64
来自 192.168.136.100 的回复: 字节=32 时间<1ms TTL=64

此时通过浏览器访问两个域名,业务是正常的(结果略)。
查看两个负载均衡器 VIP 的工作情况:

[root@lb01 conf]# ifconfig|egrep "136.100|36.200"  # VIP 100 重新飘回。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0
[root@lb02 conf]# ifconfig|egrep "136.100|36.200"   # VIP 200 正常。
inet addr:192.168.136.200  Bcast:0.0.0.0  Mask:255.255.255.0

⑩ 把 lb02 停掉,查看业务运行情况(同上,略)。
注意:Web 服务可以来回切换,但是数据库千万不能用该方式切换,因为把数据库从主切到备,用户在备上写数据,再切回主会导致主从数据库数据不一致的情况(一般数据库通过手动切换)。

二、Keepalived 常见故障解决:

服务器网线松动等网络故障;
服务器硬件故障发生损坏现象而崩溃;
Nginx 服务死掉。
提示:keepalived 是服务器级别的切换(基于系统的,不是基于软件的)。

1、问题描述:负载均衡服务器没宕机,但 Nginx 服务宕了,如何保证高可用正常切换?
思路:监控 Nginx 服务状态,如果不正常就停掉 Keepalived 或 halt 关机。
模拟问题场景如下:

[root@lb01 conf]# pkill nginx
[root@lb01 conf]# lsof -i :80
[root@lb01 conf]# ifconfig|egrep "136.100|136.200"
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0

此时 www.etiantian.org 域名无法访问:
Keepalived 高可用服务
方法一:通过守护进程脚本实现:

[root@lb01 scripts]# ps -C nginx
   PID TTY          TIME CMD
  3436 ?        00:00:00 nginx
  3437 ?        00:00:00 nginx
[root@lb01 scripts]# ps -C nginx --no-header
  3482 ?        00:00:00 nginx
  3483 ?        00:00:00 nginx
[root@lb01 scripts]# ps -C nginx --no-header|wc -l
2
[root@lb01 scripts]# pkill nginx
[root@lb01 scripts]# ps -C nginx --no-header
[root@lb01 scripts]# ps -C nginx --no-header|wc -l
0
[root@lb01 scripts]# /application/nginx/sbin/nginx
[root@lb01 conf]# mkdir -p /server/scripts/
[root@lb01 conf]# cd /server/scripts/      
[root@lb01 scripts]# vim check_w_proxy.sh
[root@lb01 scripts]# cat check_w_proxy.sh
#!/bin/sh
while true
do
nginxpid=`ps -C nginx --no-header|wc -l`
if [ $nginxpid -eq 0 ];then
   /application/nginx/sbin/nginx
   sleep 5
nginxpid=`ps -C nginx --no-header|wc -l`
if [ $nginxpid -eq 0 ];then
   /etc/init.d/keepalived stop
   exit 1
   fi
fi
   sleep 5
done
[root@lb01 scripts]# yum install dos2unix -y
[root@lb01 scripts]# dos2unix check_w_proxy.sh
[root@lb01 scripts]# sh check_w_proxy.sh &   #  让脚本后台运行。
[1] 3510

测试过程:

[root@lb01 scripts]# ps -ef|grep nginx   #  Nginx 服务正常。
root     3482   1  0 23:54 ?    00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx   3483   3482  0 23:54 ?        00:00:00 nginx: worker process
[root@lb01 scripts]# ps -ef|grep keepalived  #  Keepalived 服务正常。
root       2622      1  0 18:16 ?        00:00:01 /usr/sbin/keepalived -D
root       2624   2622  0 18:16 ?        00:00:01 /usr/sbin/keepalived -D
root       2625   2622  0 18:16 ?        00:00:12 /usr/sbin/keepalived -D
root       3618   3087  0 23:59 pts/1    00:00:00 grep keepalived
[root@lb01 scripts]# ifconfig|egrep "136.100|136.200"   #  VIP 100 工作正常。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0
[root@lb01 scripts]# pkill nginx   #  杀掉 Nginx 服务进程。
[root@lb01 scripts]# ifconfig|egrep "136.100|136.200"   #  VIP 没有飘移。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0
[root@lb01 scripts]# ps -ef|grep nginx  #  查看 Nginx 服务进程(脚本里启动了 Nginx)。              
root       3772      1  0 00:02 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx      3774   3772  0 00:02 ?        00:00:00 nginx: worker process        
root       3786   3087  0 00:02 pts/1    00:00:00 grep nginx

编辑上面的脚本让 Nginx 不尝试启动:

[root@lb01 scripts]# vim check_w_proxy.sh
[root@lb01 scripts]# cat check_w_proxy.sh    #  注释掉启动 Nginx 的内容。
#!/bin/sh
while true
do
nginxpid=`ps -C nginx --no-header|wc -l`
if [ $nginxpid -eq 0 ];then
#   /application/nginx/sbin/nginx
#   sleep 5
# nginxpid=`ps -C nginx --no-header|wc -l`
# if [ $nginxpid -eq 0 ];then
   /etc/init.d/keepalived stop
   exit 1
   fi
# fi
   sleep 5
done

重新执行该脚本:

[root@lb01 scripts]# ps -ef|grep check  #  查看该守护进程。
root       3510   3087  0 Jun23 pts/1    00:00:00 sh check_w_proxy.sh
[root@lb01 scripts]# jobs   #  查看后台执行的程序。
[1]+  Running      sh check_w_proxy.sh &
[root@lb01 scripts]# fg   #  拿到前台执行。
sh check_w_proxy.sh   
^C    #  通过 Ctrl + c 停止该程序的运行。
[root@lb01 scripts]# sh check_w_proxy.sh &  # 再让脚本后台运行。
[1] 4178
[root@lb01 scripts]# ps -ef|grep nginx|grep -v grep  #  Nginx 是运行状态。
root       3772      1  0 00:02 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx      3774   3772  0 00:02 ?        00:00:00 nginx: worker process  
[root@lb01 scripts]# ifconfig|egrep "136.100|136.200"   #  VIP 工作正常。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0
[root@lb01 scripts]# pkill nginx   #  杀掉 Nginx 进程。
[root@lb01 scripts]# Stopping keepalived:     [  OK  ]   #  守护进程自动关闭 Keepalived。
[1]+  Exit 1                  sh check_w_proxy.sh
[root@lb01 scripts]# ps -ef|grep nginx   #  查看 Nginx 进程(没有了)。
root       4374   3087  0 00:16 pts/1    00:00:00 grep nginx
[root@lb01 scripts]# ps -ef|grep nginx|grep -v grep
[root@lb01 scripts]# ifconfig|egrep "136.100|136.200"   #  VIP 没有了。

到 lb02 查看 VIP 漂移的情况:

[root@lb02 conf]# ifconfig|egrep "136.100|136.200"  #  VIP 飘到了 lb02 上提供服务。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0
inet addr:192.168.136.200  Bcast:0.0.0.0  Mask:255.255.255.0

此时业务也回归正常了:
Keepalived 高可用服务
Keepalived 高可用服务
方法二:Keepalived 配置触发:
① 修改 Keepalived 配置文件:

[root@lb01 scripts]# cat /etc/keepalived/keepalived.conf    
! Configuration File for keepalived
global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL_1
}

vrrp_script check_w_proxy {   # 定义 VRRP 脚本检查 Nginx 进程号。
script "/server/scripts/check_w_proxy.sh"   #  当 Nginx 有问题就执行脚本停掉 Keepailved。
interval 2   #  间隔时间 2s 。
weight 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.136.100/24 dev eth0 label eth0:1
    }
    track_script {    #  放到哪个实例哪个实例就进行触发。
     check_w_proxy  #  触发检查。
       }
  }

vrrp_instance VI_2 {
    state BACKUP
    interface eth0
    virtual_router_id 5
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1112
    }
    virtual_ipaddress {
        192.168.136.200/24 dev eth0 label eth0:2
    }
}

② 重启并测试配置结果:

[root@lb01 scripts]# /application/nginx/sbin/nginx    #  启动 Nginx。
[root@lb01 scripts]# /etc/init.d/keepalived stop   # 关闭 Keepalived 服务。
Stopping keepalived:           [  OK  ]
[root@lb01 scripts]# /etc/init.d/keepalived start   # 启动 Keepalived 服务。
Starting keepalived:             [  OK  ]
[root@lb01 scripts]# chmod +x check_w_proxy.sh   #  给脚本加执行权限。
[root@lb01 scripts]# ps -ef|grep nginx|grep -v grep  #  Nginx 服务正常。
root       4485      1  0 00:40 ?        00:00:00 nginx: master process /application/nginx/sbin/nginx
nginx      4486   4485  0 00:40 ?        00:00:00 nginx: worker process  
[root@lb01 scripts]# ifconfig|egrep "136.100|136.200"  #  VIP 工作正常。
inet addr:192.168.136.100  Bcast:0.0.0.0  Mask:255.255.255.0

③ 正常情况下杀掉 Nginx 后 Keepalived 会停掉,VIP 飘移到 lb02上面:

[root@lb01 ~]# ip add|grep 136.100    #  lb01 上的 VIP 正常工作。       
    inet 192.168.136.100/24 scope global secondary eth0:1
[root@lb01 ~]# pkill nginx     #  杀掉 Nginx 进程。                 
[root@lb01 ~]# ps -ef|grep keepalived|grep -v grep   #  触发脚本关掉了 Keepalived 服务。    
[root@lb01 ~]# ip add|grep 136.100    #  lb01 上的 VIP 没有了(漂移到 lb02 了)。       
[root@lb02 scripts]# ip add|egrep "136.100|136.200"   #  LB02 接替 lb01 的工作,VIP 飘过来。                               
inet 192.168.136.200/24 scope global secondary eth0:2
inet 192.168.136.100/24 scope global secondary eth0:1
[root@lb01 ~]# /application/nginx/sbin/nginx   #  重新启动 Nginx 服务。
[root@lb01 ~]# /etc/init.d/keepalived start       #  重新启动 Keepalived 服务。
Starting keepalived:                     [  OK  ]
[root@lb01 ~]# ip add|grep 136.100      #  lb01 上的 VIP 恢复了正常工作。        
    inet 192.168.136.100/24 scope global secondary eth0:1
[root@lb02 scripts]# ip add|egrep "136.100|136.200"  #  lb02 恢复正常工作状态。   
    inet 192.168.136.200/24 scope global secondary eth0:2

2、多组 Keepalived 服务器在一个局域网的冲突问题:
当在同一个局域网内部署了多组 Keepalived 服务器对,而又未使用专门的心跳线通信时,可能会发生高可用接管的严重故障问题。Keepalived 高可用功能是通过 VRRP 协议实现的,VRRP 协议默认通过 IP 多播的形式实现高可用对之间的通信,如果同一个局域网内存在多组 Keepalived 服务器对,就会造成 IP 多播地址冲突问题,导致接管错乱,不同组的 Keepalived 都会使用默认的 224.0.0.
18 作为多播地址。此时的解决办法是在同组的 Keepalived 服务器所有的配置文件里指定独一无二的多播地址,配置如下:

global_defs  {
   route_id LVS_19
   vrrp_mcast_group4 224.0.0.19      #  这个就是指定多播地址的配置。
}

3、配置指定文件接收 Keepalived 服务日志:
默认情况下 Keepalived 服务日志会输出到系统日志 /var/log/message,和其他日志信息混合在一起很不方便,可以将其调整成独立的文件记录 Keepalived 服务日志。

[root@lb01 scripts]# tailf /var/log/messages
Jun 24 01:01:32 lb01 Keepalived[5896]: Stopping Keepalived v1.2.13 (03/19,2015)
Jun 24 01:01:32 lb01 Keepalived_vrrp[5899]: VRRP_Instance(VI_1) sending 0 priority
Jun 24 01:01:32 lb01 Keepalived_vrrp[5899]: VRRP_Instance(VI_1) removing protocol VIPs.
Jun 24 01:01:32 lb01 Keepalived_healthcheckers[5898]: Netlink reflector reports IP 192.168.136.100 removed

配置指定文件记录 Keepalived 服务日志操作步骤:
① 编辑文件 /etc/sysconfig/keepalived 如下:

KEEPALIVED_OPTIONS="-D -d -S 0"
[root@lb01 scripts]# less /etc/sysconfig/keepalived   #  查看配置参数的详细信息。
# --vrrp               -P    Only run with VRRP subsystem.
# --check              -C    Only run with Health-checker subsystem.
# --dont-release-vrrp  -V    Dont remove VRRP VIPs & VROUTEs on daemon stop.
# --dont-release-ipvs  -I    Dont remove IPVS topology on daemon stop.
# --dump-conf          -d    Dump the configuration data.   #  导出数据。
# --log-detail         -D    Detailed log messages.    #  详细日志。
# --log-facility       -S    0-7 Set local syslog facility (default=LOG_DAEMON)   #  指定设备。
KEEPALIVED_OPTIONS="-D -d -S 0"
[root@lb01 scripts]# sed -i '14 s#KEEPALIVED_OPTIONS="-D"#KEEPALIVED_OPTIONS="-D -d -S 0"#g' /etc/sysconfig/keepalived   #  修改内容。
[root@lb01 scripts]# sed -n '14p' /etc/sysconfig/keepalived
KEEPALIVED_OPTIONS="-D -d -S 0"

② 修改 /etc/rsyslog.conf 文件添加如下内容:

[root@lb01 scripts]# tail -3  /etc/rsyslog.conf
# keepalived
local0.*          /var/log/keepalived.log
# ### end of the forwarding rule ###
[root@lb01 scripts]# /etc/init.d/rsyslog restart   # 重启 rsyslog。
Shutting down system logger:                [  OK  ]
Starting system logger:                          [  OK  ]
[root@lb01 scripts]# cat /var/log/keepalived.log
[root@lb01 scripts]# /etc/init.d/keepalived restart
Stopping keepalived:                             [FAILED]
Starting keepalived:                               [  OK  ]
[root@lb01 scripts]# cat /var/log/keepalived.log   #  生成 Keepalived 日志内容。
Jun 24 01:49:27 lb01 Keepalived[6057]: Starting Keepalived v1.2.13 (03/19,2015)
Jun 24 01:49:27 lb01 Keepalived[6058]: Starting Healthcheck child process, pid=6060
Jun 24 01:49:27 lb01 Keepalived[6058]: Starting VRRP child process, pid=6061
 。。。。。。。。。。。。省略若干内容。。。。。。。。。。。。。

③ 让 /var/log/message 不记录 Keepalived 日志:【local0.none】

[root@lb01 scripts]# vim /etc/rsyslog.conf
[root@lb01 scripts]# sed -n '42p' /etc/rsyslog.conf
*.info;mail.none;authpriv.none;cron.none;local0.none       /var/log/messages
[root@lb01 scripts]# /etc/init.d/rsyslog restart   
Shutting down system logger:              [  OK  ]
Starting system logger:                        [  OK  ]
[root@lb01 scripts]# > /var/log/messages   #  清空系统日志。
[root@lb01 scripts]# > /var/log/keepalived.log    #  清空 Keepalived 日志。
[root@lb01 scripts]# /etc/init.d/keepalived restart
Stopping keepalived:                           [  OK  ]
Starting keepalived:                             [  OK  ]
[root@lb01 scripts]# cat /var/log/messages   #  系统日志为空(不再记录 Keepalived 日志)。
[root@lb01 scripts]# cat /var/log/keepalived.log    
# 只有配置的 Keepalived 日志文件记录 Keepalived 的日志。
Jun 24 02:00:47 lb01 Keepalived[6058]: Stopping Keepalived v1.2.13 (03/19,2015)
Jun 24 02:00:47 lb01 Keepalived_vrrp[6061]: VRRP_Instance(VI_1) sending 0 priority
Jun 24 02:00:47 lb01 Keepalived_vrrp[6061]: VRRP_Instance(VI_1) removing protocol VIPs
```.
**4、Keepalived 高可用服务器对裂脑问题:**      
**什么是裂脑:**
        由于某些原因,导致两台高可用服务器对在指定时间内,无法检测到对方的心跳信息,各自取得资源及服务的所有权,而此时的两台高可用服务器对都还活着并在正常运行,这样就会导致同一个 IP 或服务在两端同时存在而发生冲突,最严重的是两台主机占用同一个 VIP 地址,每当用户写入数据时可能会分别写入到两端,这可能会导致服务器两端的数据不一致或数据丢失,这种情况被称为裂脑。
**列脑发生的原因:**
① 高可用服务器对之间心跳线链路故障,导致无法正常通信:
        心跳线坏了(断掉、老化);
        网卡及相关驱动坏了,IP 配置及冲突问题(网卡直连);
        心跳间连接的设备故障(网卡及交换机);
        仲裁的机器出问题(采用仲裁的方案)。
② 高可用服务器对上开启了 iptables 防火墙阻挡了心跳消息传输:
③  高可用服务器对上心跳网卡地址等信息配置不正确,导致发送心跳失败:
④ 其他服务配置不当等原因,如心跳方式不同,心跳广播冲突、软件 Bug 等。
提示:Keepalived 配置统一 VRRP 实例,如果 virtual_route_id 参数两端配置不一致也会导致裂脑。 
**避免裂脑问题的常见方法:**
① 同时使用串行电缆和以太网电缆连接,同时用两条心跳线路,这样一条线路坏了,另一个还是好的,依然能传送心跳信息;
② 当检测到裂脑时强行关闭一个心跳节点(这个功能需要特殊设备,如 Stonith、Fence)。相当于设备节点接收不到心跳信息,发送关机命令通过单独的线路关闭主节点的电源;【Stonith:Shoot the other node in the head(爆头,关掉另一个节点)】。
③ 做好对裂脑的监控报警(如邮件及手机短信等或值班),在问题发生时人为第一时间介入仲裁,降低损失。例如:百度的监控报警短信就有上行和下行的区别。报警信息报到管理员手机上,管理员可以通过手机回复对应数字或简单的字符串操作返回给服务器,让服务器根据指令自动处理相应故障,这样解决故障的时间更短。
        当然,在实施高可用方案时,要根据实际业务确定是否能容忍这样的损失,根据不同的需求选择不同的解决方案(一般网站的常规业务,这个损失是可容忍的)。
**常见的解决裂脑的方案:**
        作为互联网应用服务器的高可用,特别是前端 Web 负载均衡器的高可用,裂脑的问题对普通业务的影响是可以忍受的,如果是数据库或者存储的业务,一般出现裂脑问题就非常严重了。因此可以通过增加冗余心跳线路来避免裂脑问题的发生,同时加强对系统的监控,以便裂脑发生时人为快速介入解决问题。
① 如果开启 iptables 防火墙,一定要让心跳消息通过,一般通过允许 IP 段的方式解决;
② 可以拉一条以太网网线或者串口线作为主备节点心跳线路的冗余;
③ 开发检测程序通过监控软件(例如 Nagios)监控裂脑。
生产场景检测裂脑的思路:
① 简单判断的思想:只要备节点出现 VIP 就报警,这个报警有两种情况,一是主机宕机备机接管了;二十主机没宕,裂脑了,无论哪种情况,都进行报警,然后由人工查看判断及解决。
② 比较严禁的判断:备节点出现对应 VIP,并且主节点及对应服务(如果远程连接主节点看是否有 VIP 就更好了)还活着,就说明裂脑了。
在备节点开发脚本测试是否发生裂脑问题:

[root@lb01 conf]# cd /server/scripts/
[root@lb01 scripts]# vim check_split_brain.sh
[root@lb01 scripts]# cat check_split_brain.sh
#!/bin/sh
lb01_vip=192.168.136.100
lb01_ip=192.168.136.161
while true
do
ping -c 2 -W 3 $lb01_ip &>/dev/null
if [ $? -eq 0 -a ip add|grep "$lb01_vip"|wc -l -eq 1 ]
then
echo "Ha is split brain.Warning."
else
echo "Ha is OK"
fi
sleep 5
done
[root@lb02 scripts]# sh check_split_brain.sh # 执行脚本检查结果。
Ha is OK
Ha is OK

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章