1. 项目缘起为什么单台Nginx不够用在线上业务部署的初期我们通常会把Nginx作为反向代理和负载均衡器部署在一台服务器上。这套架构简单明了配置也快对于流量不大的项目来说完全够用。但做过运维或者后端开发的朋友都知道这种单点架构有一个致命的弱点一旦这台Nginx服务器因为硬件故障、网络中断、或者仅仅是系统需要重启维护整个网站或服务的入口就彻底断了。用户会看到“连接失败”或“502 Bad Gateway”的页面这对于任何需要保证可用性的业务来说都是不可接受的灾难。为了解决这个问题高可用High Availability, HA架构就成了必选项。其核心思想很简单别把鸡蛋放在一个篮子里。我们需要至少两台Nginx服务器让它们互为备份。当主服务器Master宕机时备份服务器Backup能够立刻顶上接管流量对用户而言这个切换过程最好是感知不到的或者中断时间极短。这就引出了两个关键问题第一如何让多台服务器共享同一个服务入口IP地址第二如何自动、快速地检测故障并完成切换“虚拟IP”Virtual IP, VIP就是解决第一个问题的答案。它不是任何一台物理服务器的真实网卡地址而是一个“浮动”的IP。在正常情况下这个VIP绑定在主服务器的网卡上当主服务器故障时这个VIP会“漂移”到备份服务器的网卡上。对于客户端来说它始终访问同一个VIP地址背后的服务器切换对它透明。而解决第二个问题的经典工具就是keepalived。它基于VRRPVirtual Router Redemption Protocol虚拟路由冗余协议协议工作可以理解为一组服务器之间通过“选举”决定谁持有VIP。主节点会定期向备份节点发送“心跳”报文宣告自己还活着。一旦备份节点收不到心跳就会认为主节点“阵亡”从而发起选举自己晋升为主节点并接管VIP。所以“Nginx使用keepalived配置VIP”这个标题本质上是在构建一个最经典、最基础的Nginx高可用集群方案。它不涉及复杂的负载均衡算法调优而是先解决“有”和“稳”的问题是保障服务连续性的第一道坚实防线。接下来我将以一个从零开始的实战视角带你完整走过规划、部署、配置、测试的全过程并分享几个只有踩过坑才知道的关键细节。2. 集群规划与基础环境搭建在动手敲命令之前合理的规划能避免后续很多混乱。我们以最常见的双节点主备Active-Standby模式为例。2.1 服务器规划与网络准备假设我们有两台CentOS 7服务器其他Linux发行版原理类似Nginx-Master: 192.168.1.101Nginx-Backup: 192.168.1.102虚拟IP (VIP): 192.168.1.100关键准备步骤主机名与Hosts文件为每台服务器设置清晰的主机名如nginx-master,nginx-backup并在两者的/etc/hosts文件中相互解析。这不是keepalived必须的但对于日常运维和日志查看非常友好。# 在192.168.1.101上执行 hostnamectl set-hostname nginx-master # 在192.168.1.102上执行 hostnamectl set-hostname nginx-backup # 在两台服务器的 /etc/hosts 文件中均添加 192.168.1.101 nginx-master 192.168.1.102 nginx-backup时间同步集群内服务器时间必须同步否则日志时间错乱会影响故障排查。使用NTP或Chrony服务。yum install -y chrony systemctl start chronyd systemctl enable chronyd chronyc sources -v # 查看同步状态防火墙与SELinux确保两台服务器之间的VRRP协议报文默认使用IP协议号112和后续Nginx的检测端口能够互通。最简单的方式是在测试环境关闭防火墙和SELinux生产环境则需要配置精确规则。# 临时关闭防火墙重启失效 systemctl stop firewalld systemctl disable firewalld # 临时关闭SELinux重启失效 setenforce 0 # 永久关闭需修改 /etc/selinux/config将SELINUXenforcing改为disabledSSH互信可选但推荐配置双机互信方便批量执行命令和同步配置文件。使用ssh-keygen生成密钥并通过ssh-copy-id将公钥拷贝到对端。2.2 Nginx的安装与基础配置keepalived负责IP漂移但最终提供服务的还是Nginx。因此需要先在两台服务器上安装并启动Nginx。安装Nginx对于CentOS 7可以先配置EPEL仓库然后yum安装。这是最快捷稳定的方式。yum install -y epel-release yum install -y nginx基础配置为了后续测试时能清晰区分哪台服务器在提供服务我们可以先简单修改一下默认的欢迎页面。在nginx-master (192.168.1.101)上echo This is Nginx Master Server - 192.168.1.101 /usr/share/nginx/html/index.html在nginx-backup (192.168.1.102)上echo This is Nginx Backup Server - 192.168.1.102 /usr/share/nginx/html/index.html启动并设置开机自启systemctl start nginx systemctl enable nginx此时分别访问http://192.168.1.101和http://192.168.1.102应该能看到各自不同的欢迎页面。这证明Nginx本身工作正常。注意生产环境中两台Nginx服务器的配置/etc/nginx/nginx.conf及conf.d/下的文件应该保持完全一致。可以使用rsync、Ansible等工具进行配置同步确保无论VIP漂移到哪台用户访问到的服务都是一致的。这是一个非常重要的运维规范。3. Keepalived的核心配置与状态切换机制安装keepalived非常简单yum install -y keepalived。它的核心在于配置文件/etc/keepalived/keepalived.conf。这个文件定义了VRRP实例、优先级、认证、虚拟IP以及最重要的——健康检查脚本。3.1 主备节点配置详解我们需要为两台服务器编写略有不同的配置文件。关键参数解析如下vrrp_instance VI_1: 定义一个VRRP实例名字可以自定义。state: 初始状态。MASTER表示启动时试图成为主节点BACKUP表示启动时为备份节点。在优先级决定胜负的机制下两者都可以设为BACKUP但设MASTER可以让主节点在恢复后更快地抢回VIP。interface: VIP需要绑定的物理网卡名称使用ip addr或ifconfig命令查看通常是eth0或ens33。virtual_router_id: 虚拟路由器ID同一个VRRP组内的所有节点必须完全相同范围是0-255。这个ID用于区分同一网段内多个不同的keepalived集群。priority: 优先级决定谁成为MASTER。值越大优先级越高。主节点应比备节点高例如主设100备设90。advert_int: 心跳广播间隔单位秒。authentication: VRRP报文认证防止非法节点加入。生产环境建议使用。virtual_ipaddress: 需要漂移的虚拟IP地址可以配置多个。track_script: 调用下面定义的vrrp_script块将脚本执行结果与节点健康状态绑定。主节点 (nginx-master) 配置示例cat /etc/keepalived/keepalived.conf EOF ! Configuration File for keepalived global_defs { router_id nginx_master_101 # 本机标识通常用主机名 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh # 健康检查脚本路径 interval 2 # 检查间隔秒 weight -20 # 如果脚本执行失败返回非0优先级降低20 fall 2 # 连续失败2次才认为节点不健康 rise 1 # 成功1次就认为节点恢复健康 } vrrp_instance VI_1 { state MASTER interface ens33 # 请根据实际情况修改网卡名 virtual_router_id 51 # 集群ID必须一致 priority 100 # 主节点优先级更高 advert_int 1 authentication { auth_type PASS auth_pass 1111 # 密码同一集群内需相同 } virtual_ipaddress { 192.168.1.100/24 # VIP注意子网掩码 } track_script { chk_nginx # 关联上面定义的检查脚本 } } EOF备节点 (nginx-backup) 配置示例与主节点配置基本相同只需修改router_id、state和priority。cat /etc/keepalived/keepalived.conf EOF global_defs { router_id nginx_backup_102 } vrrp_script chk_nginx { script /etc/keepalived/check_nginx.sh interval 2 weight -20 fall 2 rise 1 } vrrp_instance VI_1 { state BACKUP # 初始状态为备份 interface ens33 virtual_router_id 51 # 必须与主节点相同 priority 90 # 优先级低于主节点 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100/24 } track_script { chk_nginx } } EOF3.2 编写Nginx健康检查脚本上面配置中引用的/etc/keepalived/check_nginx.sh脚本至关重要。它的作用是告诉keepalived“Nginx服务本身是否还健康” 如果脚本检测到Nginx挂掉即使服务器网络是通的keepalived也会降低本机优先级触发VIP漂移。一个简单可靠的检查脚本如下cat /etc/keepalived/check_nginx.sh EOF #!/bin/bash # 检查Nginx进程是否存在 if ! pgrep -x nginx /dev/null 21; then # 尝试重启一次Nginx systemctl restart nginx /dev/null 21 sleep 2 # 重启后再次检查 if ! pgrep -x nginx /dev/null 21; then # 重启失败返回1keepalived会执行weight -20的操作 exit 1 fi fi exit 0 EOF给脚本添加执行权限chmod x /etc/keepalived/check_nginx.sh这个脚本的逻辑是首先检查Nginx进程是否存在。如果不存在则尝试自动重启一次。如果重启后仍然失败才返回非0状态码宣告本节点Nginx服务故障。这样做的好处是可以应对Nginx进程偶然崩溃的情况避免不必要的VIP切换切换本身也有微小代价和风险。实操心得检查脚本不要写得太复杂或耗时过长。interval是2秒如果脚本执行超过2秒可能会影响心跳发送导致误判。另外脚本的日志可以重定向到文件便于后期排查问题例如script /etc/keepalived/check_nginx.sh /var/log/keepalived-check.log 21。3.3 启动服务与查看状态在两台服务器上分别启动keepalived并设置开机自启systemctl start keepalived systemctl enable keepalived使用ip addr命令查看网卡信息你应该能在主节点nginx-master的ens33网卡上看到新增的VIP192.168.1.100。# 在主节点上执行 ip addr show ens33 # 输出中应包含类似inet 192.168.1.100/24 scope global secondary ens33在备节点上则不应该看到这个VIP。查看keepalived的运行状态和日志确认没有报错systemctl status keepalived journalctl -u keepalived -f # 动态查看日志日志中应该能看到Entering MASTER STATE或Entering BACKUP STATE的关键信息。4. 功能验证与故障模拟测试配置完成后绝不能假设它已经正常工作。必须进行完整的测试验证“故障转移”和“故障恢复”两个核心流程。4.1 基础连通性测试首先从集群外的一台客户端机器或者就在服务器上使用curl持续访问VIP。# 在另一台机器上执行或在本机开另一个终端 while true; do curl -s http://192.168.1.100; sleep 1; done正常情况下你会持续看到主节点101的欢迎信息 “This is Nginx Master Server - 192.168.1.101”。这说明VIP配置成功且流量正确指向了主节点。4.2 模拟主节点Nginx服务故障这是最常见的故障场景。在主节点上手动停止Nginx服务# 在 nginx-master (192.168.1.101) 上执行 systemctl stop nginx等待大约2-4秒interval*fall的时间再次观察客户端持续访问VIP的输出。你会发现输出内容变成了备节点102的欢迎信息 “This is Nginx Backup Server - 192.168.1.102”。此时立刻在主节点上执行ip addr show ens33会发现VIP已经消失了。而在备节点上执行同样的命令会发现VIP已经绑定上来了。这个过程就是自动故障转移Failover。深入理解切换过程主节点的check_nginx.sh脚本检测到Nginx进程消失。脚本尝试重启Nginx失败返回状态码1。keepalived根据weight -20的配置将主节点的有效优先级从100降为80 (100 - 20)。备节点的优先级是90高于主节点当前的80。备节点在收心跳的同时发现自己的优先级更高于是发起选举成为新的MASTER并将VIP绑定到自己的网卡上。客户端访问VIP的ARP表需要更新这个更新通常由新的MASTER发送GARP免费ARP报文来完成速度很快。4.3 模拟主节点网络故障或宕机更极端的场景是主服务器整个宕机或网络完全中断。我们可以直接关闭主服务器的电源或者在主服务器上断开网络ifdown ens33。观察客户端访问同样会在短暂中断后默认约3倍advert_int时间即3秒左右切换到备节点。这是因为备节点在连续多个心跳周期deadtime内收不到主节点的心跳报文会认为主节点失效自己晋升为主并接管VIP。4.4 测试故障恢复Failback现在恢复主节点。启动它的Nginx服务并恢复网络如果之前断开了。# 在 nginx-master (192.168.1.101) 上执行 systemctl start nginx # ifup ens33 (如果之前断开了网络)观察客户端访问和VIP绑定情况。你会发现流量不会自动切回主节点VIP仍然留在备节点上。这是为什么因为我们的备节点现在状态是MASTER优先级是90。主节点恢复后状态是BACKUP优先级是100。在默认的nopreempt非抢占模式下即使备份节点的优先级更高也不会去抢占当前MASTER的VIP除非当前MASTER再次故障。这种模式有利于保持服务的稳定性避免VIP在短时间内来回漂移。如果你希望主节点恢复后能自动抢回VIP需要在主节点的vrrp_instance配置中添加nopreempt参数并将其设为nopreempt off或者直接删除该参数因为默认是抢占模式。但更常见的生产实践是保持nopreempt模式或者将两台机器的初始状态都设为BACKUP让优先级决定初始MASTER故障切换后不自动回切。等下一次维护窗口时再手动或通过脚本将VIP切回性能更好的主机。这需要根据你的业务容忍度和运维策略来决定。5. 生产环境进阶配置与排坑指南上面的基础配置能跑通但要在生产环境稳定运行还需要考虑更多细节。5.1 增强健康检查脚本基础的进程检查有时不够。Nginx进程可能在但已经无法响应HTTP请求例如worker进程全部卡死。更健壮的检查应该直接请求Nginx的本机服务。cat /etc/keepalived/check_nginx_adv.sh EOF #!/bin/bash # 使用curl检查本地Nginx的HTTP状态 if ! curl -s -o /dev/null -w %{http_code} http://localhost:80/nginx_status 2/dev/null | grep -q 200; then # 如果检查失败尝试重启 systemctl restart nginx sleep 3 # 重启后再次检查 if ! curl -s -o /dev/null -w %{http_code} http://localhost:80/nginx_status 2/dev/null | grep -q 200; then exit 1 fi fi exit 0 EOF这个脚本尝试访问nginx_status页面需要在Nginx中配置此状态页通过HTTP状态码来判断Nginx是否真正健康。你可以替换为任何一个你知道一定会返回200的业务接口。5.2 防止“脑裂”问题“脑裂”是指集群中两个节点都认为自己是MASTER都绑定了VIP导致网络上出现两个相同的IP地址造成混乱。虽然VRRP协议本身通过优先级和心跳机制尽量避免但在网络抖动或配置不当时仍可能发生。防护措施使用单播VRRPUnicast VRRP在复杂的网络环境如云平台中组播报文可能被过滤或无法正常传输。此时可以配置keepalived使用单播进行心跳通信直接指定对端IP。# 在 /etc/keepalived/keepalived.conf 的 vrrp_instance 段中 unicast_src_ip 192.168.1.101 # 本机IP unicast_peer { 192.168.1.102 # 对端IP }注意单播模式需要双方互相配置对方的IP。添加第三方仲裁除了双方互相心跳还可以引入一个第三方检测点。例如通过一个脚本定期ping网关或者一个稳定的外部IP。如果本机连不上网关但能和对端通信则自己主动放弃MASTER身份。这通常需要更复杂的脚本逻辑来实现。合理配置advert_int和deadtimedeadtime通常是advert_int的3倍。适当调小advert_int如1秒可以加快故障检测但会增加网络负担。需要根据网络质量权衡。5.3 日志管理与问题排查keepalived的日志默认在系统日志journalctl -u keepalived中信息可能不够详细。可以修改/etc/sysconfig/keepalived文件增加日志级别和指定日志文件。# 在 /etc/sysconfig/keepalived 中修改或添加 KEEPALIVED_OPTIONS-D -S 0 -d-D表示输出详细日志-S 0指定syslog的facility-d表示前台运行模式配合systemctl时可能不适用。更常见的做法是配置syslog将keepalived的日志单独记录到一个文件。在/etc/rsyslog.conf中添加local0.* /var/log/keepalived.log然后重启rsyslog和keepalived服务。当遇到VIP不漂移、频繁漂移等问题时按以下顺序排查查日志首先查看journalctl -u keepalived或自定义的日志文件看是否有权限错误、配置解析错误、网络错误等。查网络使用tcpdump抓包在备节点上抓取VRRP协议报文协议号112看是否能收到主节点发出的心跳。tcpdump -i ens33 vrrp -n查防火墙确认防火墙是否放行了VRRP协议IP协议112和组播地址224.0.0.18。查脚本手动执行健康检查脚本/etc/keepalived/check_nginx.sh观察其返回值是否符合预期。查状态使用ip addr确认VIP绑定情况使用systemctl status keepalived查看服务状态。5.4 与云平台环境的特殊适配在AWS、阿里云、腾讯云等云服务器上部署keepalived时会遇到一个经典问题普通云服务器不允许在网卡上配置一个不属于自己子网的IP即VIP。云平台通常有自己的高可用解决方案如负载均衡器SLB。如果一定要在云服务器上用keepalived通常需要使用“虚拟IP”或“辅助IP”功能部分云厂商允许你申请一个“弹性IP”或“辅助私网IP”然后将其绑定到云服务器实例上。此时的keepalived配置VIP应填写这个允许绑定的辅助IP。使用单播模式云平台的底层网络往往不支持组播必须使用上述的unicast_peer单播配置。修改ARP响应限制在云服务器的网络配置中可能需要修改内核参数允许接口响应VIP的ARP请求。例如在/etc/sysctl.conf中添加net.ipv4.ip_nonlocal_bind1然后执行sysctl -p。这些操作因云厂商而异具体步骤需要查阅对应云平台的文档并且通常需要提工单开通相关权限。