ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LVS负载均衡原理与Keepalived高可用集群实战:四层转发扛住亿级流量

LVS负载均衡原理与Keepalived高可用集群实战:四层转发扛住亿级流量 看到LVS这个词我脑子里会先闪现两种完全不同的东西一种是我们今天要聊的 Linux Virtual Server另一种是芯片设计里的 Layout vs Schematic。如果你是因为跑芯片 DRC/LVS 摸进来的那这里要给你提个醒——走错片场了。我们这边聊的是负载均衡是那些日活千万、大促扛亿级 QPS 的系统里站在 Nginx 前面那台看起来很不起眼、但流量全靠它分发的老地基。在云原生架构满天飞的今天很多人觉得 LVS 是上古产物Service Mesh、网关、云负载均衡随便拉一个出来都比它高级。但真实情况是只要你的系统流量到了一定规模你会发现最底层那层四层转发、最扛压力、最不给你惹事的还得是 LVS 这套内核态方案。这篇文章我会把 LVS 的原理剥开讲透再带你把 Keepalived LVS 主备集群从零搭一遍最后聊聊我在线上踩过的那些坑以及它在云原生体系里到底处于什么位置。适合所有正在设计高并发入口架构、或者被怎么把入口层做得更稳困扰的人。1. 为什么说 LVS 是扛亿级流量最底层的老地基1.1 一次大促压测暴露的真相前两年我参与过一个电商平台的大促保障入口架构长这样客户端请求先到云负载均衡再到 Nginx 集群最后打到后端应用。当时所有人都盯着 Nginx 集群扩容觉得入口扛不住就加 Nginx 节点。结果压测到一定量级Nginx 的 connection 数飙得很快CPU 冲到 80% 以上但这还没到它的瓶颈——先崩的是云负载均衡的 SNAT 会话表和连接跟踪。后来我们把最外层换成了自建的 LVS Keepalived 集群用两台普通的 x86 服务器把原先分布在十台 Nginx 上的入口流量全部收进来。压测结果很有意思LVS 节点 CPU 占用几乎没超过 10%网卡吞吐跑满了连接数几十万级别稳稳的。Nginx 集群压力倒是降下来了因为四层转发不再经过它做无效的连接维持。这就是 LVS 的核心价值它在 Linux 内核态直接干活不需要把数据包拷贝到用户态做解析转发路径极其短。Nginx 是七层每个请求都要做 HTTP 协议解析、头处理、连接管理这些都要消耗 CPU。而 LVS 只管这个包该发给谁根本不关心里面装的是 HTTP 还是别的协议。1.2 LVS 和 Nginx 的分工边界很多刚接触架构的同学容易把这两个东西搞混觉得都是负载均衡选一个不就完了。但实际上它们的分工完全不同对比维度LVS四层Nginx七层工作位置Linux 内核态用户态进程处理内容IP TCP/UDP 端口HTTP 协议、URI、Header、Cookie转发能力极高接近网卡线速受用户态进程和协议解析限制连接处理转发连接不维持应用状态持有连接池、upstream 状态适用场景入口流量分发、数据库负载、TCP 服务HTTP 路由、安全过滤、静态资源、限流生产环境里最经典的做法是 LVS 做最外层入口Nginx 做中间层的七层路由两层各干各的事。LVS 负责把流量按照某种策略分给后面的 Nginx 集群Nginx 再根据 URI 把请求路由到具体的后端服务。这套组合我用了很多年简单、稳定、出问题也好排查。云原生时代也一样Kubernetes 里 Service 的 ClusterIP 在 ipvs 模式下本质上就是拿 LVS 的内核模块在做四层会话分发。这一点后面我会单独展开。2. 三种转发模式的血泪理解NAT、DR、TUN 的数据流差异LVS 有三大工作模式很多人背概念背得滚瓜烂熟但真正到了排障的时候就懵了。原因很简单——没把数据包到底是怎么走的想清楚。这一节我不用教科书式的那套话直接跟你说人话。2.1 VS/NAT 模式为什么扛大流量必挂NAT 模式下客户端请求到了 LVS 节点DirectorDirector 会把包的目的 IP 和端口改写为后端真实服务器RS的地址然后转发出去。后端处理完响应包要原路回到 DirectorDirector 再把源地址改回 VIP 回给客户端。这个模式最大的问题是请求和响应都必须穿过 Director双向流量全压在它身上。比如后端返回一个 100KB 的图片客户端发给 Director 的请求可能只有 1KB但响应 100KB 还是得经过 Director 转一手。这意味着 Director 的带宽吞吐要能扛住所有后端服务的出站流量总和这在实际业务里很难做到。NAT 模式还有一个隐藏问题由于 Director 要维护 TCP 连接的状态表conntrack在高并发下这个状态表会迅速膨胀。一旦超过 hash table 容量新连接就会丢包或者被拒绝。我见过有人拿 NAT 模式扛过线上流量结果就是高峰期 Director 频繁内存溢出。NAT 模式唯一的优势是后端 RS 可以使用私网 IP且不用做任何特殊配置不需要配置 VIP 到回环口也不需要 ARP 抑制很省事。所以我个人的建议是小规模场景、后端和 Director 跨网段、或者做实验环境用 NAT 没问题上生产扛大流量换 DR。2.2 VS/DR 模式生产环境的绝对主力DR 模式Direct Routing之所以能扛亿级流量核心思路是让响应流量不经过 Director。具体数据流转是这样的客户端请求到达 Director目标 IP 是 VIP。Director 通过调度算法选定一台 RS然后把数据链路层的目标 MAC 地址改为 RS 的 MAC 地址源 MAC 改成 Director 的 MAC直接把这个帧在二层网络里发出去。RS 收到这个包发现目标 IP 就是自己的 VIP因为我们在每台 RS 的 lo:0 上都配置了 VIP于是正常处理。RS 处理完直接把响应包源地址设为 VIP绕过 Director走自己的网关回给客户端。关键在于第 3、4 步RS 必须在回环口 lo 上绑定 VIP并且要抑制对这个 VIP 的 ARP 响应。否则整个局域网里的机器都会响应 VIP 的 ARP 请求VIP 就乱了。DR 模式里 Director 只处理入站方向的请求所以它的压力极小。一台普通服务器跑 DR 模式性能完全取决于网卡硬件和内核收包效率。我们之前用两台 2U 服务器做双主单节点实测 4 万 QPS 的 HTTPS 新建连接毫无压力长连接更是可以扛几十万。DR 模式的前提约束是Director 和 RS 必须处于同一个二层网络同一个广播域否则 Director 改完 MAC 帧发不出去。如果跨机房、跨 VLAN就得用下面说的 TUN 模式。2.3 VS/TUN 模式异地多活的备选TUN 模式是 Director 把原始 IP 包整个封装进一个新的 IP 包里通过 IPIP 隧道发给 RS。RS 解封装后看到原始包目标 IP 是 VIP然后在本地处理响应同样绕过 Director 直接回给客户端。这个模式最大的好处是Director 和 RS 可以不在同一个网段适合做异地机房的流量调度。但代价也不小每个数据包多了 20 字节的 IPIP 隧道头MTU 会受影响大包容易被分片。而且 RS 上需要加载 ipip 内核模块并配置隧道接口维护成本明显比 DR 高。我实际见过用 TUN 模式的场景多半是为了避开云厂商的访问控制策略或者做跨地域的服务入口统一调度。常规单机房集群我没太大必要用 TUN——DR 已经够用维护还简单。2.4 一张表把三种模式说清楚模式转发对象响应路径RS 前提典型瓶颈适用场景NATIP端口改写往返都过 DirectorRS 任意网段Director 带宽和 conntrack小规模、跨网段DR二层 MAC 改写响应直达客户端RS 与 Director 同二层lo 绑 VIP二层网络范围单机房大流量入口TUNIPIP 隧道封装响应直达客户端RS 支持隧道需 ipip 模块MTU、隧道开销跨机房、异地多活看到这里你应该理解了我标题里基石的意思DR 模式把转发压力控制到了最低让 Director 可以轻松成为亿级流量的分发节点。这也是为什么几乎所有大型互联网公司的四层入口最底层都是 DR 模式 LVS。3. 调度算法不是随便选的从 RR 到 WLC我的生产选型经验3.1 静态算法和动态算法的区别LVS 的调度算法分两大类静态算法不关心 RS 当前负载动态算法会根据连接数等实时指标做判断。静态算法常用的有RR轮询一个接一个轮流分最简单但没有差异化适合后端能力完全一致的场景。WRR加权轮询给不同 RS 配 weight权重高的分得多。适合后端机器配置不一的场景。SH源地址哈希根据客户端 IP 哈希去选 RS同一个源 IP 固定打到同一台机器。DH目标地址哈希根据目标地址哈希一般用于缓存场景把相同请求固定路由。动态算法常用的有LC最少连接看当前活跃连接数谁少发谁。WLC加权最少连接LC 的基础上叠加权重(当前连接数 1) / 权重最小的被选中。这是 LVS 的默认算法。SED最短期望延迟(连接数 1) / 权重对权重更敏感。NQ永不排队SED 变种优先给当前没有任何连接的 RS 派活。3.2 为什么默认是 WLC但你还得按场景换WLC 是默认算法说明它在大多数场景下表现确实不错特别是 RS 处理能力均衡、请求处理时长相近的时候。但我在生产里遇到过两个 WLC 不太灵光的场景第一个是长连接场景。比如数据库连接池、Redis 代理这类保持大量长连接的服务连接数这个指标根本反映不了真实负载——有的连接很闲有的连接一直在跑大查询。这时候用 WLC 看活跃连接数意义不大不如用 WRR 按机器规格定权重或者干脆让后端自己做连接池负载。第二个是后端能力不均衡的动态变化。比如某台 RS 因为 JVM GC 卡顿实际处理能力下降但 LVS 只看它连接数少反而给它派更多的新请求——这就是所谓的脑残式调度。这时候我会调低它的 weight或者用 SED/NQ 这种对权重更敏感的算法让它快速被边缘化。我自己的选型口诀是这样的后端同配置、处理时间均衡用 WRR后端有差异、线程池模型用 SED/NQ需要会话保持用 SH 而不是依赖 persistence_timeout缓存场景用 DH。3.3 会话保持到底靠什么HTTP 场景有个经典问题用户登录状态在 A 机器上下一次请求被分到 B 机器如果后端会话没有共享用户就会掉线。很多人的第一反应是在 LVS 上配置会话保持。LVS 确实有一个 persistence_timeout 参数可以让来自同一个源 IP 的连接在固定时间内都分发到同一台 RS。这个参数在 keepalived 配置里很常见默认值可以设成 600 或者按业务来。但它有一个先天缺陷基于源 IP 做保持如果客户端走了出口 NAT 或 IPv6 转换大量用户共享同一个源 IP就会造成严重的负载倾斜。所以我的建议是如果会话能放进 Cookie 或者 Redis 共享就不要依赖 LVS 的 persistence如果实在要依赖用 SH 算法 合理 persistence_timeout并且预估好 NAT 出口的份额不要把保持时间设太长。80 到 120 秒足够覆盖大多数跳转后马上回源的场景长保持时间的代价是流量分布极度不均。4. Keepalived LVS 主备集群搭建实录4.1 拓扑与架构规划我把这套配置在真实环境里跑了很多年下面的步骤完全可以抄作业。架构就是一个标准的 LVS-DR 主备模式客户端 | | VIP: 192.168.10.100 | ---------------- | | LVS主: 192.168.10.11 LVS备: 192.168.10.12 | | ---------------- | ------------------ | | | RS1: 192.168.10.21 RS2: 192.168.10.22 RS3: 192.168.10.23 (Nginx) (Nginx) (Nginx)两台 LVS 节点部署 Keepalived 形成 VRRP 主备组VIP 跑在主节点上。三台 RS 跑 Nginx每台 RS 的 lo:0 都绑定 VIP。整个集群加起来五台机器扛的入口 QPS 比前面十台 Nginx 直连还高这就是 LVS 的杠杆效应。4.2 主机初始化与配置操作系统我用的是 CentOS 7.9 / Rocky Linux 9都验证过。首先要装包yum install -y keepalived ipvsadm # RPM 系 # 或者 Debian/Ubuntu # apt install -y keepalived ipvsadm装完先把内核转发确认一下NAT 模式必需DR 模式其实用不到但开了无害echo net.ipv4.ip_forward 1 /etc/sysctl.conf sysctl -p然后是加载 LVS 相关的内核模块。这一步很多人忽略导致 keepalived 起来后ipvsadm -L -n一片空白modprobe ip_vs modprobe ip_vs_wrr modprobe ip_vs_wlc modprobe ip_vs_sh modprobe ip_vs_sed # 开机自动加载 echo -e ip_vs\nip_vs_wrr\nip_vs_wlc\nip_vs_sh\nip_vs_sed /etc/modules-load.d/ipvs.conf4.3 keepalived.conf 逐段解读主节点的配置文件/etc/keepalived/keepalived.conf完整版如下我拆开讲global_defs { router_id LVS_MASTER } vrrp_instance VI_1 { state MASTER # 主节点备节点写 BACKUP interface eth0 # VIP 绑定的网卡 virtual_router_id 51 # 同一个 VRRP 组必须一致 priority 100 # 主节点高于备节点 advert_int 1 # VRRP 心跳间隔 1 秒 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.10.100/24 dev eth0 } } virtual_server 192.168.10.100 80 { delay_loop 6 # 健康检查间隔 6 秒 lb_algo wrr # 调度算法我这次用加权轮询 lb_kind DR # 工作模式 persistence_timeout 0 # 不依赖 LVS 做会话保持 protocol TCP real_server 192.168.10.21 80 { weight 1 # 权重按 RS 规格设 TCP_CHECK { connect_timeout 3 nb_get_retry 3 # 重试次数默认是 nb_get_retry 但不同版本不同下面说 delay_before_retry 3 connect_port 80 } } real_server 192.168.10.22 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } real_server 192.168.10.23 80 { weight 2 # 新机器可以给更高权重 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }几个容易踩的细节vrrp_instance 里的 state 和 priority 的关系。传统做法是主节点 state 写 MASTER、priority 写 100备节点 state 写 BACKUP、priority 写 99。但实际 VRRP 选主只看 priority两个节点都写 BACKUP、用优先级区分也没问题。我更推荐后一种写法因为如果是抢占式主备主节点恢复后 VIP 会强制切回对于不那么需要强制回切的场景反而会带来一次不必要的闪断。可以在主节点配置里加nopreempt让主节点挂掉再恢复后不抢占。auth_pass 只能在同一个组里用不能跨组。我们之前两个业务共用一个 keepalived 进程结果 auth_pass 设成了同一个两台 LVS 的 VRRP 报文互相干扰VIP 在两者之间反复横跳。排查了很久才发现是认证密码冲突导致的。virtual_server 里的 lb_kind 大小写敏感。DR、NAT、TUN三个值必须严格大写写成dr直接起不来。4.4 后端 RS 的 ARP 抑制配置DR 模式下 RS 这一侧是重头戏。每台 RS 都要把 VIP 绑定到回环口同时抑制 ARP 响应。脚本如下VIP192.168.10.100 # 绑定 VIP 到 lo:0 ifconfig lo:0 $VIP netmask 255.255.255.255 up # 抑制本机所有接口对 VIP 的 ARP 响应 echo 1 /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 /proc/sys/net/ipv4/conf/all/arp_announce echo 1 /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 /proc/sys/net/ipv4/conf/lo/arp_announce这个配置的原理值得解释一下网上的教程大多只给命令不给原因。正常情况下Linux 收到一个目标 IP 是本机 IP 的 ARP 请求就会用自己的 MAC 地址回应。RS 的 lo:0 绑了 VIP如果不做任何抑制局域网里有人问谁是 192.168.10.100这台 RS 会抢答这样客户端发往 VIP 的包就可能被 RS 直接截走彻底绕过了 LVS整个负载均衡就失效了。arp_ignore 1的意思是只有目标 IP 精确匹配到本机某网卡配置的 IP 时才响应 ARP 请求。lo:0 配的是 255.255.255.255 的独立掩码常规情况下不会对外响应arp_announce 2的意思是对外响应的源地址尽量使用目标网卡的 IP避免出现 IP 匹配异常。配置完成后建议验证一下ip addr show lo cat /proc/sys/net/ipv4/conf/all/arp_ignore cat /proc/sys/net/ipv4/conf/all/arp_announce然后在客户端机器上观察 ARP 表arp -a | grep 192.168.10.100应该看到 VIP 对应的 MAC 是主 LVS 节点 eth0 的 MAC而不是任何一台 RS 的。4.5 验证命令和切换演练LVS 集群搭完验证不能只看网页能打开。我每次上线前固定会做四件事# 1. 确认虚拟服务和 RS 状态 ipvsadm -L -n # 输出里看到每条 real_server 的 ActiveConn/InActConn 在涨说明流量真的在分发 # 2. 看各 RS 的连接分布 ipvsadm -L -n --stats # 3. 确认准备节点状态 systemctl status keepalived第三步尤其重要很多人搭完只盯着主节点。备节点 keepalived 起来后它会持续监听 VRRP 报文但不会配置任何 LVS 规则。只有主节点挂掉或者优先级变化备节点才会接管 VIP 并把自己的 ipvsadm 规则加进去。所以验证备节点要主动做一次故障切换演练# 在主节点上停掉 keepalived systemctl stop keepalived # 观察备节点等待 2~3 秒 ip addr show eth0 | grep 192.168.10.100 # 应该能看到 VIP 出现在备节点上 ipvsadm -L -n # 备节点的规则已经接管 # 从客户端再次访问 VIP业务正常演练完记得恢复systemctl start keepalived需要提醒的是如果配置了 nopreempt主节点恢复后 VIP 不会自动切回可能长时间停留在备节点上。这本身不是故障但要有感知别在第二天的监控里看到咦VIP 怎么在备机上就慌。5. 故障转移里那些看不见的细节ARP、裂脑与连接跟踪5.1 VIP 漂移时到底发生了什么Keepalived 的 VRRP 协议本质上就是主备两台机器在同一个虚拟路由器 ID 下互发心跳报文。备节点连续几个advert_int周期没收到主节点的心跳就判定主节点故障开始接管 VIP。接管过程不是简单地把 IP 配置到网卡上关键动作是发送免费 ARPGratuitous ARP。这个免费 ARP 的作用是告诉整个二层网络192.168.10.100 这个 IP 的 MAC 地址变了你们赶紧把 ARP 缓存更新掉。 交换机、路由器、客户端收到这个通告后新的流量才会被引到新主节点上。这里就有一个实战中很常见的坑免费 ARP 只发一次但下游设备的 ARP 缓存老化时间可能远超这个周期。如果交换机或者客户端没及时收下这个通告流量就会继续往已经挂掉的老主节点上送表现就是切换了但业务还是在断。解决方法是把 keepalived 配置里vrrp_notify脚本接到切主事件上脚本里强制发几轮免费 ARP#!/bin/bash # /etc/keepalived/master.sh VIP192.168.10.100 INTERFACEeth0 for i in $(seq 1 5); do arping -I $INTERFACE -c 1 -U $VIP sleep 0.2 done然后在这个脚本被调用的时机上做配置一般用 notify 或者 smtp_alert 相关的钩子。不同 keepalived 版本的钩子名有差异要对着自己版本查。5.2 裂脑的成因与防护裂脑Split Brain是主备高可用里最怕的事主备两台机器都认为我才是主于是都绑定了 VIP。结果客户端 ARP 表在两套 MAC 之间反复横跳流量被打到两台机器上会话乱七八糟业务表现就是时好时坏异常连接满天飞。裂脑的常见成因是心跳链路断了但业务网络还通比如两台机器之间的 VRRP 报文被防火墙丢弃、交换机端口做了隔离、或者网卡链路抖动。我在线上遇到过最隐蔽的一次是服务器上跑了一个安全软件把 VRRP 用的组播报文当异常流量拦了导致备节点误判主节点故障直接抢占 VIP。防护手段没有银弹只能多管齐下优先用单播模式替代组播keepalived 配置里指定对方 IP减少组播报文被交换机丢弃的概率。在 VIP 绑定网卡上用 iptables 限制只放行同一个 VRRP 组的来源。写一个裂脑检测脚本每几秒看一次本机是否持有 VIP 对方 keepalived 是否存活两边都对就报警必要时强制关闭本机 keepalived。5.3 conntrack 在转发链路中的作用这个话题我希望每个用 LVS 的人都能重视。DR 模式下主节点为每个经过的 TCP 连接建立对应的 ip_vs 会话状态这个状态存的是四元组 → 转给哪台 RS。故障切换后新主节点的连接跟踪表是空的所有老连接在新主节点看来都是陌生连接。结果就是切换瞬间已有的 TCP 长连接会被打断。TCP 客户端会感知到 RST 或者连接超时然后重连。对 HTTP 短连接业务来说重连开销可接受但如果是数据库代理、消息队列这类长连接业务一次切换可能导致成千上万个连接同时重建后端会瞬间被打爆。这个问题的缓解措施有几种用 conntrackd 做连接跟踪表同步在主备之间实时同步状态切换后新主节点能继承老连接代价是配置复杂、同步本身也消耗资源。接受重连给客户端配置合理的重试策略然后靠 RS 的承载能力撑过切换瞬间。大多数互联网业务够用。在架构上把长连接收敛到更上层避免直接挂在 LVS 后面。我个人的判断是如果业务对切换瞬间断连接完全不能接受应该优先考虑在 RS 侧做重连保护或者用云厂商提供的会话保持能力而不是在 LVS 层硬扛 conntrack 同步的复杂度。6. 生产环境踩坑清单每一条都是真金白银换来的6.1 keepalived 版本差异带来的配置假成功keepalived 的配置语法在不同大版本之间有变化尤其是健康检查相关的参数。我踩过一个很典型的坑在 1.3 版本下用nb_get_retry和delay_before_retry没问题但升到 2.x 后部分写法被标记为 deprecated甚至有些字段解析直接报错。报错还好最怕的是配置解析静默失败keepalived 起来了虚拟服务也配了但健康检查根本没生效RS 挂了一台它还往里面转发。所以每次升级 keepalived我的固定动作是跑一遍keepalived -t -f /etc/keepalived/keepalived.conf做配置语法校验然后看日志/var/log/messages里有没有 WARNING 级别的解析提示。别嫌麻烦这条能救大命。6.2 健康检查误判导致的雪崩健康检查的connect_timeout设得太短是我见过最危险的操作。比如后端 RS 处理本身要 200ms你设了 100ms 的 connect_timeoutLVS 会判定这台机器不健康然后把它移出调度列表。大量请求瞬间转移到其他 RS其他 RS 压力升高、响应变慢又被更严格的健康检查误判下线——雪崩就来了。正确做法是健康检查超时时间要大于后端 P99 响应时间同时配合多次重试判活。宁可让一台慢机器多活一会儿也别把它过早摘掉导致整个集群连环崩。RS 的判断逻辑我建议连续 2 次成功才算恢复连续 2 次失败才摘除避免单次抖动引起频繁上下线。这也是为什么我在配置里习惯写上delay_before_retry和重试次数。6.3 权重不合理引发的流量倾斜LVS 的权重调整是动态生效的但很多人调整得太激进。我曾经为了给一台新机器引流把新机器 weight 从 1 调到 5然后在监控上看到它连接数瞬间冲破阈值。原因很简单WLC 算法里权重是个加速器权重差距过大时低权重的机器几乎被忽略新连接全往高权重的机器灌。正确的做法是分阶段调整权重比如从 1 → 2 → 3每阶段观察至少一个业务周期。尤其是在流量高峰期权重突变比机器宕机还可怕。6.4 后端 RS 的 sysctl 模板长期使用 LVS 之后我整理了一套 RS 侧的 sysctl 基线专门给挂在 LVS 后面的机器用# 提高文件句柄和连接队列 fs.file-max 1000000 net.core.somaxconn 65535 net.ipv4.tcp_max_syn_backlog 65535 # 快速回收 TIME_WAIT 连接 net.ipv4.tcp_tw_reuse 1 net.ipv4.ip_local_port_range 1024 65535 # 加大 backlog避免瞬时高并发丢连接 net.core.netdev_max_backlog 65536这里特别说一下tcp_tw_reuse它是跟 LVS 联动的一个关键参数。LVS 转发请求到 RS 后源 IP 是 VIP 或 Director 的地址RS 回包时会产生大量 TIME_WAIT 连接。如果本地端口范围太小、TIME_WAIT 回收太慢RS 会陷入端口耗尽的假死状态表现是大量连接建立失败但 CPU 内存都正常。调大本地端口范围 开启 reuse是 RS 挂在高流量 LVS 后面最基础的自保手段。7. 云原生时代LVS 的位置在哪里7.1 kube-proxy 的 ipvs 模式就是在复用 LVS 的底子聊到云原生很多人会误以为 LVS 只属于传统机房。但你只要拆开 Kubernetes 的底层就会发现kube-proxy 支持 iptables 和 ipvs 两种模式而 ipvs 模式用的就是 LVS 的内核能力。在 ipvs 模式下kube-proxy 把 Service 的 ClusterIP 建成一个虚拟服务Pod 的 Endpoint 作为 real server由内核态的 ipvs 直接做四层分派。相比于老式的 iptables 模式ipvs 的规则更少、转发更快、支持更丰富的调度算法。一个几千个 Service 的集群iptables 规则表能达到几万条CPU 消耗明显换成 ipvs 后规则量级大幅下降新建连接性能也更好。所以你可以这样理解你在经典机房用 LVS 的经验到了 K8s 集群里依然有效只是从手动配 keepalived变成了声明式 API 自动管理。7.2 裸金属 K8s 里怎么借 LVS 的能力如果没有云厂商的负载均衡裸金属 K8s 集群想暴露一个四层端口常见的方案是 MetalLB。MetalLB 在 L2 模式下会选出一个节点承载 Service 的对外 VIP本质上也是 ARP 抢占的思路。如果集群规模大、节点多MetalLB 的性能瓶颈会暴露这时候一部分团队会选择在集群前面放一个独立 LVS 集群把集群节点当作 real server 挂进去。我自己做过的一个典型架构是三层入口LVS四层→ Ingress Controller Nginx七层→ 业务 Pod。这套架构迁移到 K8s 几乎无缝LVS 层完全不需要跟着集群折腾Ingress Controller 扩容只在 LVS 后面加 real server 就行。这也是很多人忽略的一点云原生并不是要把经典方案全都推翻而是让 LVS 继续在最底层发光上层换成更灵活的编排。7.3 从 LVS 到四层网关的演进思路LVS 之后业界其实一直在演进四层网关技术比如基于 DPDK 的用户态转发、基于 eBPF/XDP 的内核旁路、以及各种云厂商自研的四层 LB。它们解决的问题和 LVS 一样只是换了一种更吃硬件红利的实现方式。但 LVS 并没有过时反而因为简单、稳定、内核自带这三个特点依然是最值得优先考虑的四层入口方案。eBPF 和 DPDK 虽好但对团队的技术储备和运维能力要求高了不少一个 bug 可能影响整个集群转发面。对于大多数业务来说用 Keepalived LVS 搭出来的入口十年如一日地稳定这本身就是最大的价值。我个人的建议是如果你的流量还没有大到需要专项优化四层转发的程度就老老实实用 LVS把省下来的精力花在业务和后端服务治理上。等哪一天你发现 LVS 节点网卡打满了、单机吞吐成为瓶颈再去研究 DPDK 和 XDP 也不迟——而且那时候你会更理解它们解决的是什么问题。回到开头那个话题为什么总说 LVS 是亿级流量的基石原因其实很朴素——它在最靠近硬件的内核层做最纯粹的分发把复杂留给了上层的 Nginx 和业务。我每次排障到入口层最后发现最稳的还是那两台不起眼的 LVS 节点。这套方案我会一直用下去也希望这篇拆解能让你在搭建自己的入口架构时少走点弯路。
返回列表