基于 keepalived 实现两台机器服务(主备)故障自动切换

前言

本文要说的是基于 keepalived 实现两台服务器之间的主备切换 。当一台机器的 Java 进程异常关闭,另一台机器能够自动监测到并启动本机的 Java 进程。

keepalived 的工作机制及原理不多做介绍,自行搜索了解,keepalived 的安装部署请参考 keepalived 的安装及使用 。

个人觉得动手实践安装下 keepalived,然后结合 keepalived 的配置文件会有助于理解 keepalived 的工作机制。

需要部署的服务

部署在服务器的项目不是一个 web 程序,是一个普通的 Java 应用。主要功能是定时从文件服务器下载文件,然后做一些处理,最终把处理过的文件放到本地。

部署要求

当一台服务器部署的服务出现故障时,能够有 备用机器 继续提供服务,尽量避免人工介入去恢复系统。注意跟负载均衡的区别!初步方案只提供一台备用机。

方案

1. 实现原理

keepalived 的配置文件中有 权重STATE 两个配置项,两台机器上的 keepalived 通过 虚拟IP 绑定之后,它们之间就可以通过上述的配置项来进行 ”选举“ ,区分 MASTERBACKUP

然后配合 keepalived 中另外的两个功能,检测脚本通知脚本 实现我们的主备切换的需求。

到底如何决定 MASTER 和 BACKUP ?

STATE 的值可以是 MASTERBACKUP,当 两台机器配置的 STATE 的值相同,并且权重相同时,谁先启动谁是 MASTER,当两台机器的配置的 权重 相同时,state 为 MASTER 的那台机器最终会成为 MASTER(哪怕这台机器启动的时间比另一台晚)

检测脚本的作用

对我们的使用场景来说,检测脚本的作用有两个,一是检测我们的 java 进程是否存在,二是对 keepalived 的权重进行加减。比如: 检测到我们的 java 进程关闭了,我们就可以降低这台机器的权重。

权重改变是永久生效的吗?

否, 权重的增加或者降低只对当前一轮的检测有效!下次检测开始还会恢复到配置的默认值。

通知脚本的作用

通知脚本有两种,分别根据 keepalived 的状态去触发。对我们的使用场景来说,这两种分别是: **一个是当这台机器是 MASTER 时需要触发的脚本,二是当这台机器是 BACKUP 的时候需要触发的脚本。**比如: 当我们的机器变成 MASTER 时,去启动我们的 java 进程。

2. 具体配置

keepalived 的配置文件

! Configuration File for keepalived
# 全局配置
global_defs {
   router_id LVS_MS
   vrrp_skip_check_adv_addr
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

# 配置检测脚本,脚本名称随意
vrrp_script chk {
   script "/etc/keepalived/chk.sh" # 检测脚本的位置
   interval 3 # 每隔 3 秒执行一次
   weight -20 # 权重 -20 ,根据检测脚本的返回值去判断是否要减掉
}
# vrrp 实例
vrrp_instance VI_1 {
    state BACKUP # 主备配置一样,并且权重也一样,这样谁先启动谁就是 MASTER
    interface eth0
    virtual_router_id 90
    priority 100 # 默认权重
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass keepalived_ms
    }
    virtual_ipaddress {
        172.16.10.90 # 虚拟 ip
    }
    # 引用检测脚本,因为可以配置多个 vrrp 实例,每个实例都可以使用同一个检测脚本
    track_script {
        chk
    }
    # 配置通知脚本的路径,脚本名称随意
    # 1. 当 keepalived 的状态为 MASTER 时,会触发这个通知脚本
    notify_master "/etc/keepalived/notify.sh master"
    # 2. 与 1 相反
    notify_backup "/etc/keepalived/notify.sh backup"
}

检测脚本

#!/bin/bash

# 查找java服务进程个数
count=`ps aux | grep -v grep | grep 进程名称 | wc -l`

# master.flag 就是一个标记文件,如果文件存在,表示为 master 

# 如果 MASTER 上的服务down 掉,降低权重
# 如果 MASTER 上的服务没有问题,权重不变
# 如果是BACKUP ,权重保持不变
if [ -f master.flag ] && [ $count -eq 0 ]; then
    exit 1 # 结合 keepalived.conf 配置文件,这里返回 1 表示当前机器权重 -20
else 
    exit 0 # 返回 0 ,什么也不做
fi

检测脚本什么时候执行?

检测脚本时定时执行的,时间可以配置,而且主备两台机器都会同时执行。

通知脚本

#!/bin/bash

# 接收参数, master 或者 backup 或者 ""
function=$1

# 如果触发的是 master 的通知脚本
if [ "x"$function = "xmaster" ] ; then

    # 1. 新建标记文件,标志本机为 MASTER
    touch master.flag

    # 2. 启动 java 进程
    # TODO 
    
    # 3. 启动文件同步服务
    # TODO 这里是因为我的项目需要,所以要开启这样一个服务
    
else
    
    # 1. 删除 MASTER 标记,标记为 BACKUP
    rm -f master.flag

    # 2. 关闭 java 进程
    # TODO 为了保险一点,再关闭一次
 
    # 3. 关闭文件同步服务
    # TODO
    
fi

通知脚本什么时候执行?

只有当状态发生切换时(包括 keepalived 启动时),才会触发对应的通知脚本。

执行流程

  1. 首先是准备两台机器比如 Server A 和 Server B,分别部署我们的 java 应用keepalived,甚至其他可能用到的服务,比如我们项目中用的文件同步。

  2. 分别启动两台机器的 keepalived 进程,顺序无所谓,配置文件都一样,谁先启动谁就是 master。

  3. 比如 Server A 是 MASTER,keepalived 就会去触发我们的通知脚本(notify_master),通知脚本就会创建一个文件标记这台机器是 master,同时启动我们的 java 进程。Server B 的 keepalived 启动后,触发 notify_slave, 结合脚本所做的事情,我们发现,第一次触发并不会造成什么影响,甚至后续我们可以优化一下,减少这些无用功。

  4. 当我们关闭 Server A 的 java进程,检测脚本检测到 java 进程关闭了,并且当前主机是 MASTER (因为检测到 master.flag 文件存在),检测脚本就会返回 1,致使 Server A 的权重降低 20,也就是比 Server B 低20,此时会在此进行 “选举”,Server A 就变成了 backup,同时去触发notify_slave脚本,Server B 就变成了 master, 同时触发 notify_master脚本。

  5. 根据两个脚本做的事情,我们最终发现,两台机器不仅发生了身份切换,并且做的事情也对换了一下。

几个问题

  • keepalived 的日志存放位置 : /var/log/messages
  • 如果发现两边都能检测到虚拟ip,请检查下 防火墙是否没有关闭!
  • 检测脚本和通知脚本的执行顺序: 同时执行! 这也是我为什么加了 master.flag 的原因。 请仔细体会!

总结

上述仅仅是一个 demo 方案,并未经过生产环境的考验,需要打磨的地方很多。另外就是网上做此类方案的案例很少,可能是应用不到吧,其他大多方案都是,kill 掉 keepalived 从而完成主备切换。写这篇文章的主要原因是自己在做的过程中,有很多疑惑,网上没直接给出答案,其实正常操作的话不会有我这些疑惑,我是因为脚本写错了,在我坚定脚本没问题的时候,去怀疑一些问题,比如权重改变后就永久生效了,通知脚本是根据你的状态一直在执行的!

最后欢迎大家指出其中的问题,或者做一些补充!! 谢谢

你可能感兴趣的:(linux)