做运维这些年,亲手搭过不下十套 Web 集群,但每次给团队讲高可用架构,我仍然会把 LVS+Keepalived+NFS 这套组合拿出来当第一课。原因很简单:它没有 Kubernetes 那么重,也没有单台 Nginx 那么脆,而且一旦把这三样东西吃透,后面再去理解任何负载均衡、会话保持、共享存储方案都会顺很多。这套方案的最终形态是——一组 Web 服务器共同对外提供服务,用户访问同一个虚拟 IP;前端节点异常时,心跳机制自动把虚拟 IP 切走;后端文件不落在任何一台服务器的本地磁盘,而是统一放在 NFS 共享目录上。对大多数企业内部系统、门户网站、中小规模应用来说,这个组合的性价比和可控性都相当高,也是面试和方案评审里出现频率极高的一套底层架构。
接下来我按自己的实际部署经验,从方案选型、环境规划、LVS 配置、Keepalived 冗余、NFS 共享存储到故障演练,完整走一遍过程。全程用最小可复现的虚拟机组演示,每一步都写清原因和参数来源,尤其是那些手册里不会写、但你上线后一定会踩的坑。
1. 为什么我会选 LVS+Keepalived+NFS 这套组合
1.1 高可用方案不止一种,先捋清楚需求
很多人一提高可用就想到 Kubernetes,但真实业务里并不是所有场景都需要容器编排。我见过太多团队为了追新,把一套每天几千访问的内部系统硬塞进 K8s,结果运维成本和故障率双双上升。如果你的需求是"Web 服务不能因为单台机器宕机而中断""文件需要多台服务器共享""团队运维能力有限,需要方案简单可见",那 LVS+Keepalived+NFS 几乎是量身定做的。
这套架构实际上解决的是三个不同层面问题:接入高可用、服务高可用、数据一致性。LVS 负责流量分发,Keepalived 负责检测和切换,NFS 负责让每台 Web 服务器读到同一份文件。三层各管一件事,互不干扰,出了问题也能快速定位。
1.2 LVS、Keepalived、NFS 各自承担什么角色
先给完全没接触过的读者把三个角色拆开讲。
LVS(Linux Virtual Server)跑在 Linux 内核里,工作在第四层,也就是传输层。它能把到达虚拟 IP 的 TCP/UDP 流量按调度算法转发给后端真实服务器。跟 Nginx 的七层负载均衡相比,LVS 不解析 HTTP 内容,只处理 IP+端口级别的转发,所以性能极高,转发延迟很小,吞吐量可以做到几十万并发也没有太大压力。
Keepalived 最初就是为 LVS 设计的,它通过 VRRP 协议实现虚拟 IP 的漂移。简单说,集群里有一台主节点和若干台备用节点,正常情况下虚拟 IP 绑在主节点上,主节点心跳丢失后备用节点抢占这个 IP,继续对外提供服务。它还会定期执行健康检查脚本,如果发现某台后端服务器已经不可用,就把它从 LVS 转发列表里摘掉。
NFS(Network File System)解决的是 Web 集群最常见的痛点:用户上传的图片、程序部署代码、Session 文件、日志文件,如果落在每台服务器本地,负载均衡请求分散到不同机器后就会出现"文件在这台上传的,另外一台读不到"的诡异问题。NFS 把一台存储服务器上的目录通过网络挂载到所有 Web 服务器上,大家读写同一份文件,这些问题自然消失。
1.3 为什么不直接用 Nginx 负载均衡就够了
这是我在方案评审时被问最多的问题。Nginx 做负载均衡当然可以,而且配置很简洁:
upstream backend { server 192.168.10.11 weight=2; server 192.168.10.12 weight=1; } server { listen 80; location / { proxy_pass http://backend; } }但这里有几个现实问题。首先,Nginx 工作在七层,需要解析 HTTP 报文,CPU 开销明显高于纯内核态的 LVS。其次,Nginx 本身也是一个单点,你依然需要再为 Nginx 做 Keepalived 或别的冗余方案。更重要的是,如果后端有 WebSocket、TCP 长连接这类业务,Nginx 的配置复杂度会迅速上升。而 LVS 天然支持四层协议,什么 TCP 业务都能转发,无需关心应用层细节。
Nginx 不是不能用,它更适合做网关、做 SSL 终结、做基于 URL 的精细分发。但在"高可用 + 高性能 + 高稳定"这个组合要求下,LVS 作为入口,Nginx 作为 Web 服务进程,是更合理的分工。我后来很多生产环境就是 LVS 在前、Nginx 在后,只在需要特殊路由规则时才加一层 Nginx 网关。
2. 动手前的环境规划:IP、软件版本、拓扑
2.1 规划一个最小可复现的集群
我经常跟学员强调一句话:任何高可用架构,先画 IP 表,再动手装系统。很多部署问题最后都演变成 IP 混乱问题。下面是最小化的三节点架构,一共五台虚机,但在验证阶段可以先只上三台核心节点,把 NFS 和备用 Director 放在同一台机器上先跑通流程。
这次演示我准备了四台机器,全部使用 Rocky Linux 9,内核自带 LVS 和 NFS 相关模块,不需要额外编译。
| 角色 | 主机名 | IP 地址 | 说明 |
|---|---|---|---|
| LVS 主节点 | lvs-master | 192.168.10.10 | 绑定 VIP 192.168.10.100 |
| LVS 备用节点 | lvs-backup | 192.168.10.20 | 主节点故障时接管 VIP |
| Web 节点 1 | web01 | 192.168.10.11 | 运行 Nginx,挂载 NFS |
| Web 节点 2 | web02 | 192.168.10.12 | 运行 Nginx,挂载 NFS |
| NFS 存储节点 | nfs-server | 192.168.10.30 | 提供共享目录 /data/www |
这里需要说明为什么 VIP 选择 192.168.10.100 而不是直接用某个节点的 IP。VIP 是逻辑地址,它不属于任何一台物理服务器,由 Keepalived 动态绑定到当前活跃的 Director 上。客户端和 Web 服务器都只认识这个 IP,切换过程对两端透明。
2.2 三台虚机怎么分角色
很多人会把所有组件装在同一台机器上测试,这没有问题,但生产至少需要把 NFS 独立出来,因为 NFS 的磁盘 IO 和网络 IO 都比较重,跟 LVS 混跑会互相影响。
建议的部署顺序是:先装 NFS,再装两台 Web,最后装 LVS 主备节点。原因很直接——LVS 的转发目标是 Web 节点,Web 节点需要挂载 NFS 目录才能读写数据,依赖方向是从后往前。如果把 LVS 先装好,后端还没准备好,Keepalived 健康检查会一直报警,干扰排查。
全部节点系统装好后,第一步不是配置任何服务,而是确认基础环境三件事:时间同步、防火墙放行、SELinux 状态。
2.3 开始前的坑:时间同步、防火墙、SELinux
时间同步被很多人忽略,但对高可用集群来说非常关键。Keepalived 的日志时间戳、LVS 的连接跟踪、NFS 文件的时间戳,全部依赖系统时间。如果两台 Director 时间差超过几秒,主备切换时可能出现"两边都认为自己是主"的脑裂窗口。统一用 chrony 同步:
dnf install -y chrony systemctl enable --now chronyd chronyc sources -v防火墙方面,LVS 的 VIP 和 VRRP 协议需要放行。VRRP 默认使用组播地址 224.0.0.18,协议号是 112。Rocky Linux 9 默认 firewalld 比较严格,最少要放行这些:
firewall-cmd --permanent --add-protocol=vrrp firewall-cmd --permanent --add-port=80/tcp firewall-cmd --permanent --add-port=2049/tcp firewall-cmd --reloadSELinux 建议先临时设为 Permissive,排除它对 NFS 挂载和 LVS 转发的干扰。当然我不建议直接 disabled,因为生产环境还是需要 SELinux 兜底的。等整套架构跑通后,再针对 NFS 和 httpd 放开对应布尔值:
setsebool -P httpd_use_nfs 1 setsebool -P httpd_read_user_content 1这一步很多人不做,结果 Nginx 能启动但读不了 NFS 上的文件,日志里全是 Permission denied,排查半天泪流满面。
3. LVS 核心配置:DR 模式的完整落地
3.1 为什么生产环境我默认选 DR 而不是 NAT/TUN
LVS 有三种转发模式:NAT、TUN、DR。NAT 模式下,请求和响应都经过 Director,后端服务器的网关要指到 Director;TUN 模式需要后端支持 IP 隧道;DR 模式下,Director 只处理入站请求,响应由各 Web 节点直接回给客户端。
大多数生产环境我推荐 DR 模式,核心原因是响应流量不进 Director。Web 场景里响应体往往远大于请求体,比如一个页面几百 KB,请求只有几 KB。如果用 NAT,Director 要承担全部双向流量,很快成为瓶颈。DR 模式下 Director 的负载非常轻,只做 TCP 层的转发决策。代价是后端 Web 节点必须和 Director 在同一二层网络,且要处理 VIP 的 ARP 响应问题,稍后再展开。
TUN 模式理论上可以跨网段,但 IP 隧道封装有额外开销,而且很多云厂商网络环境会过滤 IPIP 协议,所以除非特殊场景,我基本不碰。
3.2 Director 上配置 LVS 的完整步骤
Rocky Linux 9 没有像 CentOS 7 那样的 ipvsadm 服务脚本,手动配置或者用 Keepalived 托管都可以。既然最终要上 Keepalived,我建议生产环境把 LVS 规则直接写进 Keepalived 配置里,由它负责加载。但为了先验证 LVS 本身,我们先用手动命令把转发链路打通。
第一步,装上 ipvsadm 管理工具:
dnf install -y ipvsadm第二步,在 Director 上配置虚拟 IP。DR 模式下 VIP 绑定在 lo 接口的别名上,但这里先不手动绑定,因为下一步 Keepalived 会自动配置。如果只用手动方式测试,可以用:
ip addr add 192.168.10.100/32 dev eth0注意掩码是 32,不能写成 24,否则会改变接口的路由行为,产生诡异网络问题。
第三步,添加 LVS 转发规则:
ipvsadm -A -t 192.168.10.100:80 -s rr ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.11:80 -g ipvsadm -a -t 192.168.10.100:80 -r 192.168.10.12:80 -g-s rr表示轮询调度,-g表示 DR 模式。先手动验证时我常用 rr,够直观;生产环境我会换-s wrr或者lc(最少连接),因为后端机器性能不一定完全相同。看配置:
ipvsadm -Ln你会看到 VIP 下挂了两台后端服务器,状态全是 Active。如果此时从客户端curl http://192.168.10.100,后端还没配置好 ARP 抑制和 VIP 响应,大概率是不通的,所以下一步必须做。
3.3 后端 Web 服务器上的 ARP 抑制设置
这是整套架构里最容易失败的一步。DR 模式下,VIP 同时配置在 Director 和所有 Web 节点的 lo 接口上,但对外必须只有 Director 响应 VIP 的 ARP 请求。如果不做抑制,Web 节点也宣称自己拥有 VIP,客户端 ARP 表会混乱,直接导致负载均衡失效,甚至整个网段网络抖动。
先说 VIP 在 Web 节点上的配置。在 web01 和 web02 上执行:
ip addr add 192.168.10.100/32 dev lo然后修改 ARP 内核参数。新建/etc/sysctl.d/99-lvs-dr.conf:
net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2 net.ipv4.conf.lo.arp_ignore = 1 net.ipv4.conf.lo.arp_announce = 2立即生效:
sysctl -p /etc/sysctl.d/99-lvs-dr.conf这两个参数的含义:arp_ignore=1表示只有目标 IP 是本机接口上的 IP 时才响应 ARP 请求;arp_announce=2表示不主动通告那些不属于本接口的 IP 地址。简单理解就是:Web 节点对 VIP 的请求一律闭嘴,但收到发往 VIP 的数据包时仍然正常处理。
如果不做这步,现象非常典型:客户端 curl VIP 有时通、有时不通,arp -n看到 VIP 对应多个 MAC 地址,流量随机跑到后端但后端又没绑 VIP 的 socket,连接直接 reset。我见过很多人在这一步卡了一整天,最后定位到是 ARP 问题。
3.4 手动测试转发链路:先别急着上 Keepalived
配置完 ARP 抑制后,在客户端访问 VIP:
curl -I http://192.168.10.100正常情况下会看到 Nginx 的响应头。因为是轮询模式,连续访问多次会把请求交替打到 web01 和 web02。看后端日志确认:
tail -f /var/log/nginx/access.log如果能看到 192.168.10.10 的地址代表访问来自 Director。手动验证通过后,ipvsadm -Ln --stats可以看到总连接数和每个后端的转发包统计。这里有个小技巧:访问一次后立刻看ipvsadm -Ln --stats,转发包数为 0 说明数据包根本没到 Director,多半是 VIP 或路由问题;转发包数正常但后端日志没记录,多半是 ARP 抑制或后端防火墙问题。
4. Keepalived 接管 VIP 漂移与健康检查
4.1 Keepalived 的作用不是"高可用",而是"探测 + 漂移"
很多人以为装了 Keepalived 就等于高可用,这是误解。Keepalived 只负责三件事:定期间发 VRRP 心跳、根据优先级决定谁持有 VIP、调用健康检查脚本决定是否摘除故障后端或切换主备。真正的高可用效果是这三件事组合出来的。
在实际架构里,我让 Keepalived 同时管理 VIP 和 LVS 规则。这样当主节点故障时,备用节点不光漂移 VIP,还会自动加载完整的 ipvsadm 规则,保证后端转发配置一致。
4.2 主备配置文件的差异与同步项
在 lvs-master 和 lvs-backup 上都安装 Keepalived:
dnf install -y keepalived主节点配置文件/etc/keepalived/keepalived.conf如下:
global_defs { router_id LVS_MASTER vrrp_skip_check_adv_addr script_user root enable_script_security } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 192.168.10.100/24 dev eth0 label eth0:1 } } virtual_server 192.168.10.100 80 { delay_loop 10 lb_algo wrr lb_kind DR protocol TCP real_server 192.168.10.11 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 2 } } real_server 192.168.10.12 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 2 } } }备用节点只需要改三处:router_id改为LVS_BACKUP,state改为BACKUP,priority改为 100,其他完全一致。这里要说明virtual_router_id必须是唯一的,同一网段里如果有多套 Keepalived 集群,这个 ID 不能冲突,否则 VRRP 消息会互相干扰。
4.3 健康检查脚本怎么写才靠谱
Keepalived 自带的 TCP_CHECK 只能判断后端 80 端口是否可连接,但对 Web 应用来说,端口通不代表服务正常。比如 Nginx 进程卡死、PHP-FPM 假死、连接积压到不响应新请求,端口检查全部通过,用户却已经无法访问了。
所以我通常不用内置 TCP_CHECK,而是写一个脚本来做应用层探测:
#!/bin/bash # /etc/keepalived/check_web.sh curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 10 http://127.0.0.1/ 2>/dev/null | grep -E '200|301|302'脚本返回值是 0 表示服务正常,非 0 表示异常。然后在 real_server 里用 MISC_CHECK 调用:
real_server 192.168.10.11 80 { weight 1 MISC_CHECK { misc_path "/etc/keepalived/check_web.sh" misc_timeout 10 misc_dynamic } }健康检查脚本还有个容易被忽略的细节点:脚本里访问的是 127.0.0.1 还是 VIP。在 DR 模式下,后端节点上虽然绑定着 VIP,但通常只有 Nginx 监听 80 端口,没有特别绑定 VIP,访问 127.0.0.1 即可准确反映本机服务状态。如果写curl http://192.168.10.100反而可能因为 ARP 抑制而路径不清晰,造成误判。
4.4 故障切换触发条件:别只检查端口
只检测 Web 服务是否正常是不够的。如果 Director 本身网卡故障、内核模块异常、或者到后端的路由出了问题,Keepalived 不会自动切换,因为 VRRP 心跳还在走。生产环境我建议在健康检查脚本里增加一个额外的"自检能力"——比如检查 ipvsadm 规则是否还在:
if ! ipvsadm -Ln | grep -q '192.168.10.100:80'; then exit 1 fi当脚本返回非 0 时,Keeplaived 不仅会摘除这台 real_server,还可以触发自身降优先级,把 VIP 让给备用节点。实现方式是在脚本异常时主动停止 keepalived 或者执行:
killall keepalived这样备用 Director 会立即抢占 VIP,整个集群入口完成切换。这个设计听起来简单,但没有做过故障演练的人很难想象它的价值——我遇到过真实事故,网卡物理故障导致 VRRP 还在跑,但转发已经断了,用户访问全部超时,急救时才发现切换条件设计得太窄。
5. NFS 共享存储:让每台 Web 都看到同一份文件
5.1 Web 集群为什么要共享存储
先描述一个没有 NFS 的典型问题。用户上传了一张头像,请求被 LVS 分配到 web01,文件写在 web01 本地。下一次刷新,请求被分到 web02,web02 的站点目录里没有这张头像,直接 404。这类问题在单机环境下不存在,但一旦做负载均衡就必然暴露。
更严重的是程序部署的不一致。你更新代码时只 push 到一台服务器,另一台还是旧版本,用户在不同请求之间体验完全不一致。用 NFS 把整个 Web 根目录共享出去后,所有节点读同一份文件,部署一次全部生效,这也顺带省去了每次发布后同步文件的操作。
5.2 exports 配置与权限设计
NFS 安装在 nfs-server 上:
dnf install -y nfs-utils systemctl enable --now nfs-server共享目录选择/data/www,注意这个目录的属主要是 nfsnobody 或者某个固定 UID,否则 Web 节点写文件时权限会错乱。推荐做法是统一使用一个 UID,比如用 nginx:
mkdir -p /data/www chown nginx:nginx /data/www编辑/etc/exports:
/data/www 192.168.10.0/24(rw,sync,no_root_squash,no_subtree_check)导出并查看:
exportfs -rav showmount -e localhost几个参数里最要紧的是sync。很多教程建议用async提升性能,但这是拿可靠性换的。async模式下 NFS 先响应写请求再异步落盘,服务器突然断电时,客户端告诉用户"写入成功"但实际数据丢了。对业务数据,我坚决用sync。no_root_squash允许 root 保留权限,如果你没有特殊需求可以不加,默认的 root_squash 更安全;但 Web 程序如果需要以 root 身份操作共享文件,就会遇到权限问题,需要在安全和便利之间权衡。
5.3 客户端挂载与开机自动挂载
两台 Web 节点安装客户端:
dnf install -y nfs-utils mount -t nfs 192.168.10.30:/data/www /usr/share/nginx/html查看是否挂载成功:
df -h | grep nfs这里注意,Nginx 的默认站点目录在/usr/share/nginx/html,直接把它作为挂载点是很多人的选择,但其实生产环境我建议把 Nginx 站点目录独立出来,比如/data/webroot,别和 RPM 包默认目录混在一起,否则升级 Nginx 时容易误清数据。
开机自动挂载需要写进/etc/fstab:
192.168.10.30:/data/www /usr/share/nginx/html nfs defaults,_netdev,noatime,nolock 0 0_netdev表示网络设备在 network 就绪后再挂载,防止开机时网络没起来导致挂载失败卡住启动流程。nolock用于兼容部分场景,如果你确认不需要文件锁服务可以加上;有些环境不加反而有 lockd 服务冲突的问题。
5.4 NFS 性能与稳定性:sync、no_root_squash 的权衡
NFS 最大的争议点在于性能。我见过不少团队因为 NFS 太慢而质疑整套架构。真实情况是,大部分慢的问题出在默认参数上,尤其是 mount 选项里没加noatime。文件系统每次读都会更新访问时间戳,NFS 的每次更新都是一次网络往返,在高频读的场景下延迟被放大得非常明显。所以noatime几乎是必加的。
另外要确认 NFS 服务端开启了足够数量的线程。在高并发写入场景下,默认的 8 个 nfsd 线程可能不够,可以调大/etc/nfs.conf里的rpc-nfsd-count到 16 或 32,然后重启:
systemctl restart nfs-server最后还要提醒一句,连接跟踪和端口问题。NFSv4 只需要 2049 端口,如果 NFSv3 需要额外开 111、20048 等端口,写防火墙规则时容易漏,我统一建议只用 NFSv4,配置里加上:
/data/www 192.168.10.0/24(rw,sync,no_root_squash,no_subtree_check,vers=4)加上vers=4可以避免客户端自动协商到旧版本,减少开放端口数量,安全性和稳定性都有提升。
6. 高可用验证:从简单 ping 到模拟故障切换
6.1 第一步验证:VIP、LVS 转发、NFS 挂载
整套架构配置完成后,先别急着上压力,按照从下到上的顺序做基础验证。
- 在客户端机器上
ping 192.168.10.100,确认 VIP 能通。 - 在 lvs-master 上执行
ip addr show eth0:1,确认 VIP 绑在 eth0 上。 - 查看
ipvsadm -Ln,确认转发规则已经由 Keepalived 写入了内核。 - 在 web01 和 web02 上
df -h,确认 NFS 挂载点都在。 - 在 nfs-server 上
/data/www下创建测试文件echo hi > /data/www/test.html,两台 Web 节点都能通过curl http://127.0.0.1/test.html访问到。
这一步最容易发现的问题是"VIP 通了但 curl 80 端口不通"。先别怀疑 iptables,多半是 Web 节点没监听 0.0.0.0:80,或者 Nginx 配置文件里 root 指向的目录因为 NFS 挂载失败变成了空目录,访问直接 403。
6.2 第二步验证:手动杀掉 keepalived 主节点
高可用切换验证是核心中的核心。在 lvs-master 上停掉 Keepalived:
systemctl stop keepalived此时观察 lvs-backup 上的日志:
tail -f /var/log/messages正常情况下几秒内会出现类似 "Entering MASTER STATE" 的日志,然后在 backup 节点上查看 IP:
ip addr show eth0:1看到 VIP 已经漂移到 backup 上之后,马上从客户端访问:
curl -I http://192.168.10.100业务不断,这是最基本的标准。同时确认ipvsadm -Ln里的转发规则也存在,因为 Keepalived 配置里的 virtual_server 段会自动重构规则。
这个流程我建议至少演练三次,包括优雅停止、kill -9、直接拔虚拟网卡三种方式。拔网卡的测试最真实,因为 VRRP 心跳会先丢失,备用节点抢占 VIP,但 LVS 规则能否正确加载取决于配置里的健康检查状态,如果你的健康检查脚本有问题,这个场景一定会暴露。
6.3 第三步验证:停掉 Nginx 服务
主备切换验证完,还要验证 Keepalived 能否感知后端节点故障。在 web01 上:
systemctl stop nginx然后在 lvs-master 上观察:
ipvsadm -Ln等待健康检查周期(配置里 delay_loop 是 10 秒)内,web01 的状态会从 Active 变成 Failed,并从后端列表里摘除。此时从客户端持续访问,所有流量都落到 web02,用户侧无感知。
要注意一个细节:Keepalived 摘除的是后端节点,不是 VIP 漂移。也就是说,只要 Director 节点健康,即使只剩一台 Web 存活,访问依然有响应。把 Nginx 恢复后,web01 会在下一个健康检查周期被自动加回来。
6.4 第四步验证:压测与连接状态检查
基础功能和切换验证都通过后,我习惯再用 ab 或 wrk 跑一轮短压测,同时盯三个指标:
- 请求失败率。ab 的 failed requests 必须为 0。
- 各后端连接数是否均匀。看
ipvsadm -Ln --stats -n每个 real server 的 ActiveConn 差额。 - NFS 服务端的 IO 是否异常偏高。
iostat -x 1关注 util 是否持续接近 100%。
举个例子,压测命令:
wrk -t4 -c200 -d60s http://192.168.10.100/跑完后看:
ipvsadm -Ln --stats如果 web01 和 web02 的转发包数量几乎一样,说明 rr/wrr 调度正常。如果某一台数量明显偏多,检查健康检查脚本是不是把另一台误判成故障了,或者 weight 设置不对。压测阶段我经常发现 TCP_CHECK 会把慢响应误判为超时,导致所有流量倒到另外一台,改用 MISC_CHECK 后恢复正常,这也是压测才能看出来的隐性坑。
7. 运行半年之后的一些总结
这套架构投入生产之后,我最大的体会是:高可用不是"装完就完事",而是持续维护的结果。Keepalived 的日志要看、健康检查脚本要定期测试、NFS 剩余空间要监控,尤其是 NFS 挂载断开的场景——网络抖动时 Web 节点可能变成"哑状态",TCP 连接正常但文件全部读不到。我当时加了一个监控脚本,每隔一分钟在挂载点目录写入一个心跳文件然后删除,一旦失败立即告警,这个思路分享给大家。
另一个真实经验是,不要把 VIP 的掩码配成 24。Keeplaived 配置里我写的是192.168.10.100/24 dev eth0 label eth0:1,这个 24 与普通接口的掩码含义不同,直接决定 VIP 是否参与 ARP 通告。如果你写成 32,某些网络环境下客户端路由表会认为 VIP 不可达,表现为外部能 ping 通但 TCP 连接超时。这种边界参数的问题,只有实际搭建时才会记住,所以我建议所有想掌握这套架构的人都亲手完整建一遍。
最后再分享一个小技巧:把所有配置文件和安装命令写成一个简单的自动化脚本,用 Ansible 或者 bash 都行。这样不仅方便复现环境,更重要的是,当故障出现在两年后时,你还能精准知道当初每一步到底做了什么。高可用系统的终极目标不是预防所有故障,而是当故障发生时,你能够快速、准确地把它切换掉,并且在事后找到根因。LVS+Keepalived+NFS 这套组合之所以经典,就是因为它把所有关键路径都暴露在你能看见、能控制的位置,而不是封装在黑盒里。