一、 为什么需要“备胎”?理解高可用

想象一下,你运营着一个重要的在线服务,比如一个电商网站。如果承载这个网站的服务器突然宕机了,会发生什么?用户无法访问,订单无法处理,直接意味着经济损失和口碑下降。单台服务器就像独木桥,一旦出问题,整个服务就中断了。

“高可用”就是为了解决这个问题而生的。它的核心思想很简单:消除单点故障。通俗地说,就是给重要的服务器准备一个或多个“备胎”(备用服务器)。当正在工作的主服务器因为硬件故障、网络问题或需要维护而“歇菜”时,备胎能够立刻自动顶上去,接过所有工作,保证服务不间断。这个过程对用户来说几乎是感觉不到的,就像赛车进站换胎一样快速、无缝。

实现高可用的方案有很多,今天我们要聊的是一个非常经典且轻量级的工具——Keepalived。它就像一个智能的“故障切换协调员”,专门负责管理哪台服务器应该对外提供服务。

二、 Keepalived:你的虚拟IP“魔术师”

Keepalived本身是一个用C语言写的开源软件,它的工作原理非常巧妙。它不直接处理你的业务数据(比如网页、数据库),而是通过管理一个虚拟IP地址来实现高可用。

你可以这样理解:

  1. 你有一个重要的服务,比如网站,它需要被用户通过一个IP地址(例如 192.168.1.100)访问。
  2. 你准备了两台内容完全一样的服务器,一台叫 Server-A(真实IP: 192.168.1.10),一台叫 Server-B(真实IP: 192.168.1.20)。
  3. 正常情况下,你希望用户访问 192.168.1.100 这个地址时,请求由性能更好的 Server-A 来处理。
  4. Keepalived 会在这个场景中,让 Server-A 主动“霸占”这个 192.168.1.100 的虚拟IP。对于网络里的其他设备(用户、路由器等)来说,192.168.1.100 就是 Server-A
  5. Keepalived 会在 Server-AServer-B 之间建立一个“心跳”连接,互相确认对方是否还“活着”。
  6. 一旦 Server-A 故障,Server-B 上的 Keepalived 检测不到“心跳”了,它就会立刻启动,把虚拟IP 192.168.1.100 “抢”到自己身上。于是,用户访问 192.168.1.100 的请求,就自动转到了 Server-B

这个虚拟IP漂移的过程非常快,通常在几秒钟内完成。Keepalived 就是通过这种“抢IP”的机制,实现了服务的自动切换。

三、 手把手搭建Keepalived双机热备

光说原理可能有点抽象,我们直接动手配置一个最常见的双机热备场景。假设我们要为Nginx Web服务器提供高可用。

技术栈声明: 本文所有示例均基于 Linux (CentOS 7/8) 操作系统环境。

首先,在两台服务器上都执行以下步骤:

  1. 安装Keepalived:

    # 对于CentOS/RHEL系统,使用yum安装
    sudo yum install -y keepalived
    
    # 对于Ubuntu/Debian系统,使用apt安装
    sudo apt-get update
    sudo apt-get install -y keepalived
    
  2. 安装并启动Nginx(示例服务):

    sudo yum install -y nginx  # CentOS
    # sudo apt-get install -y nginx # Ubuntu
    sudo systemctl start nginx
    sudo systemctl enable nginx
    

    在两台服务器上分别创建一个简单的测试页面,以便区分:

    # 在 Server-A (192.168.1.10) 上执行
    echo "This is Primary Server - A" | sudo tee /usr/share/nginx/html/index.html
    
    # 在 Server-B (192.168.1.20) 上执行
    echo "This is Backup Server - B" | sudo tee /usr/share/nginx/html/index.html
    

接下来是核心配置。Keepalived的主配置文件是 /etc/keepalived/keepalived.conf。我们需要分别配置主备两台机器。

在 Server-A (主服务器) 上配置:

sudo vim /etc/keepalived/keepalived.conf

将内容清空,替换为以下配置:

# ==================== 全局定义部分 ====================
global_defs {
   # 设置Keepalived的标识,在通知邮件中会用到,可以随意命名
   router_id nginx_master
}

# ==================== VRRP实例定义部分 ====================
# 这是核心配置,定义了一个VRRP组(虚拟路由冗余协议组)
vrrp_instance VI_1 {
    # 指定本机在此VRRP组中的角色。MASTER表示主服务器
    state MASTER
    # 指定用于VRRP通信的网络接口,请根据你服务器的实际网卡名修改,常见的有ens33, eth0等
    # 使用 `ip addr` 命令查看你的网卡名称
    interface ens33
    # 虚拟路由ID。同一个VRRP组内的所有机器,这个ID必须完全相同,范围1-255
    virtual_router_id 51
    # 本机的优先级。MASTER的优先级应该比BACKUP高,范围1-254
    priority 100
    # VRRP通告间隔,单位秒。主备之间通过这个频率发送心跳包
    advert_int 1

    # ==================== 认证部分 ====================
    # 主备之间通信的认证,防止非法设备加入VRRP组
    authentication {
        # 认证方式,PASS表示简单密码认证
        auth_type PASS
        # 认证密码,同一个VRRP组内的所有机器密码必须相同
        auth_pass 1111
    }

    # ==================== 虚拟IP地址部分 ====================
    # 这是最关键的部分!定义需要被漂移的虚拟IP地址
    virtual_ipaddress {
        # 可以定义多个虚拟IP,每行一个。这里我们定义了一个 192.168.1.100
        # 注意:这个IP必须和你的物理IP在同一个网段,且未被其他设备占用
        192.168.1.100
    }
}

在 Server-B (备服务器) 上配置:

配置文件路径相同,内容大部分也相同,只有几个关键参数需要修改:

# ==================== 全局定义部分 ====================
global_defs {
   router_id nginx_backup  # 标识改为backup以示区分
}

# ==================== VRRP实例定义部分 ====================
vrrp_instance VI_1 {
    # 角色改为BACKUP
    state BACKUP
    interface ens33        # 网卡名,确保和主服务器一致或根据实际情况修改
    virtual_router_id 51   # 必须和主服务器相同!
    # 优先级设置为比主服务器低。当主服务器恢复时,优先级高的会重新抢占为MASTER
    priority 90
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111     # 密码必须和主服务器相同!
    }

    virtual_ipaddress {
        192.168.1.100      # 虚拟IP必须和主服务器相同!
    }
}

配置完成后,在两台服务器上启动Keepalived服务,并设置开机自启:

sudo systemctl start keepalived
sudo systemctl enable keepalived

检查服务状态和虚拟IP是否绑定成功:

# 查看Keepalived运行状态
sudo systemctl status keepalived

# 查看网卡信息,在MASTER服务器上应该能看到虚拟IP (192.168.1.100)
ip addr show ens33
# 你会看到类似这样的输出,除了物理IP,还会多出一个 `192.168.1.100` 的IP
# 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
#     link/ether 00:0c:29:xx:xx:xx brd ff:ff:ff:ff:ff:ff
#     inet 192.168.1.10/24 brd 192.168.1.255 scope global noprefixroute dynamic ens33
#        valid_lft 1234sec preferred_lft 1234sec
#     inet 192.168.1.100/32 scope global ens33  <-- 这就是漂移过来的虚拟IP!
#        valid_lft forever preferred_lft forever

现在,你可以打开浏览器,访问 http://192.168.1.100,应该会看到来自 Server-A 的页面 “This is Primary Server - A”。

进行故障模拟测试:

  1. 手动停止 Server-A 上的 Keepalived 服务:sudo systemctl stop keepalived
  2. 等待几秒钟(advert_int 设置的时间),然后在 Server-B 上执行 ip addr show ens33,你会发现虚拟IP 192.168.1.100 已经出现在 Server-B 的网卡上了。
  3. 此时再访问 http://192.168.1.100,页面会变成 Server-B 的 “This is Backup Server - B”。服务切换成功!
  4. 重新启动 Server-A 的 Keepalived:sudo systemctl start keepalived。由于 Server-A 的优先级 (100) 高于 Server-B (90),虚拟IP又会自动漂移回 Server-A

四、 进阶玩法:用脚本监控真实服务

上面的基础配置只监控了Keepalived进程本身和网络。如果服务器本身没宕机,但上面运行的关键服务(比如Nginx、MySQL)自己挂掉了怎么办?用户访问虚拟IP,请求到了服务器,但服务不响应,问题依然没解决。

这就需要用到Keepalived的另一个强大功能:自定义监控脚本。Keepalived可以定期执行我们写的脚本,通过脚本的返回值来判断服务器是否“健康”。如果脚本检测失败(返回非0),即使Keepalived进程还在,它也会主动降低本机优先级,或者直接执行故障切换。

让我们来增强配置,增加对Nginx进程的监控:

首先,在两台服务器上创建监控脚本:

sudo vim /etc/keepalived/check_nginx.sh

写入以下内容:

#!/bin/bash

# Nginx健康检查脚本
# 返回值:0 表示健康,1 表示不健康

# 检查Nginx主进程是否存在。`pgrep -x nginx` 会查找精确名为‘nginx’的进程
# 如果进程存在,该命令返回0(成功),否则返回非0
if pgrep -x "nginx" > /dev/null
then
    # 进程存在,脚本返回0,告诉Keepalived“我很健康”
    exit 0
else
    # 进程不存在,尝试重启一次Nginx(可选,根据你的策略决定)
    # systemctl restart nginx
    # 等待2秒再看是否启动成功
    # sleep 2
    # if pgrep -x "nginx" > /dev/null; then exit 0; fi

    # 这里我们选择简单处理:检测失败就直接返回1,触发Keepalived切换
    exit 1
fi

给脚本添加执行权限:

sudo chmod +x /etc/keepalived/check_nginx.sh

然后,修改两台服务器的 keepalived.conf 文件,在 vrrp_instance VI_1 { 配置块内部,virtual_ipaddress { 部分之前,添加以下配置:

    # ==================== 健康检查脚本部分 ====================
    # 定义追踪脚本,用于监控真实服务的状态
    track_script {
        # 引用下面定义的脚本块名称
        chk_nginx
    }

接着,在配置文件的最末尾(在 vrrp_instance 块的外面),添加新的配置块来定义这个脚本:

# ==================== 定义健康检查脚本 ====================
vrrp_script chk_nginx {
    # 指定要执行的脚本路径
    script "/etc/keepalived/check_nginx.sh"
    # 脚本执行的间隔时间,单位秒
    interval 2
    # 如果脚本连续失败多少次,才认为服务真的故障了(防止网络抖动误判)
    fall 2
    # 如果脚本连续成功多少次,才认为服务恢复
    rise 2
    # 脚本执行的超时时间
    timeout 2
    # 这个参数很重要!如果脚本执行失败(返回非0),本机的优先级会减去这个值
    # 比如主服务器 priority 100,减去20后变成80,就低于备机的90了,从而触发切换
    weight -20
}

现在,即使 Server-A 的Keepalived和系统都正常,但如果你手动停止Nginx服务(sudo systemctl stop nginx),等待几秒后,虚拟IP也会自动漂移到 Server-B。这就实现了对应用层服务的高可用保护。

五、 应用场景、优缺点与注意事项

应用场景:

  1. Web服务器高可用: 如本文示例,为Nginx、Apache等提供故障转移。
  2. 负载均衡器高可用: 常用于LVS、HAProxy等负载均衡软件的前端,确保流量入口不中断。
  3. 数据库高可用: 可以为MySQL主从复制中的“主库”提供一个虚拟IP,配合MHA等工具实现主库故障切换。
  4. 企业内网服务: 为内部DNS、DHCP、文件共享等关键基础设施提供冗余。

技术优点:

  1. 简单轻量: 配置相对简单,资源占用小。
  2. 稳定可靠: 项目成熟,在大量生产环境中得到验证。
  3. 切换快速: 基于VRRP协议,故障切换通常在秒级完成。
  4. 功能灵活: 支持自定义健康检查脚本,能与各种服务集成。

技术缺点与局限:

  1. 脑裂问题: 这是最需要注意的问题!如果主备服务器之间的“心跳”网络中断,但两台服务器本身都正常运行,它们会都认为对方挂了,从而都去抢占虚拟IP,导致出现两个“主服务器”,服务混乱。解决脑裂需要配置额外的检测线路(如串口线、多块网卡绑定不同网络)或使用第三方仲裁脚本。
  2. 资源浪费: 备机在平时不处理业务(除非你做成主主或负载均衡模式),存在资源闲置。
  3. 数据同步非其职责: Keepalived只负责IP漂移,不负责两台服务器之间业务数据的同步(如网页文件、数据库数据)。你必须自行通过Rsync、DRBD、数据库复制等技术保证数据一致性。
  4. 单活: 基础的主备模式是单活的,只有一台机器对外服务。

重要注意事项:

  1. 确保虚拟IP可用: 配置的虚拟IP必须和物理网络在同一网段,且未被其他设备静态占用。
  2. 防火墙配置: VRRP协议使用IP协议号112(或组播地址224.0.0.18)。务必在主备服务器的防火墙上放行相关通信,否则“心跳”无法传递。
    # 例如,使用firewalld
    sudo firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
    sudo firewall-cmd --reload
    
  3. 网络稳定性: 主备服务器之间的网络链路质量至关重要,不稳定的网络会引发频繁的切换或脑裂。
  4. 日志监控: 养成查看 /var/log/messagesjournalctl -u keepalived 日志的习惯,里面记录了状态切换、脚本执行结果等关键信息。

六、 总结

Keepalived是一个以“虚拟IP漂移”为核心思想的经典高可用工具。它就像一位忠诚的哨兵,守护着你的服务入口。通过简单的配置,就能为许多无状态或配合有数据同步方案的服务,搭建起一道可靠的高可用防线。

它的核心价值在于简单、高效地解决了网络层面的单点故障。对于刚接触高可用的朋友来说,从Keepalived入手是一个非常好的选择,它能帮你建立起高可用的基本概念。

当然,它并非银弹。面对复杂的应用、有状态的服务、大规模集群,你可能需要结合LVS、HAProxy、以及更高级的集群管理软件如Kubernetes等来构建更完善的架构。但无论如何,理解并掌握Keepalived,都是你运维和架构知识体系中坚实而有用的一块拼图。