ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

LVS负载均衡核心原理与生产实践:从三种模式到内核调优

LVS负载均衡核心原理与生产实践:从三种模式到内核调优 之前给人做内部技术分享时我经常被问到同一个问题Nginx 都已经能做负载均衡了为什么还要折腾 LVS这个问题很有代表性也正好是 LVS 学习路线上最容易卡住的地方。LVSLinux Virtual Server是工作在 Linux 内核态的四层负载均衡方案它不解析 HTTP 内容只处理 IP 层和 TCP/UDP 层的报文转发所以在转发性能、连接处理能力和系统资源占用上和 Nginx、HAProxy 这类七层负载均衡完全不是一个量级。这篇总结是我从接触 LVS 到把它真正用进生产环境的完整记录包括三种工作模式的原理、调度算法怎么选、内核参数怎么调、以及我踩过的那些坑。适合刚入门负载均衡的运维、后端开发和架构师参考希望对你有实际帮助。1. 先想清楚LVS 到底解决什么问题1.1 LVS 是什么为什么我转了一圈还是选它LVS 是章文嵩博士在 1998 年发起的开源项目后来被合入 Linux 内核成为内核自带的一项能力。它的核心思路很简单在 Linux 内核的 netfilter 框架之上做 IP 层的负载均衡。客户端访问的是一个虚拟 IPVIPLVS 的调度器Director收到请求后根据预设的调度算法把请求转发到后端的真实服务器RealServer上。客户端感知不到后端服务器的存在整个集群就像一台高性能服务器。我最初对它不以为然觉得 Nginx 就够了。后来做了一次压力测试同样一台 4 核虚机跑 Nginx 做七层转发长连接压测下 CPU 直接飙到 60% 以上换成 LVS 做四层转发CPU 占用几乎可以忽略不计。原因就在于 LVS 的转发逻辑在内核态完成不需要像 Nginx 那样把每个请求从内核态拷贝到用户态、解析完 HTTP 头再拷贝回去。省掉这两次拷贝和上下文切换性能差异自然就拉开了。在做架构选型时我给 LVS 的定位是流量入口的守门员它负责把海量并发连接快速、稳定地分发下去至于 SSL 卸载、路由规则、请求改写这些精细活交给后面的 Nginx 或应用网关去做。各司其职系统才不容易出问题。1.2 一套 LVS 集群里都有什么角色理解 LVS 前得先把几个角色搞清楚。整套体系里有三类节点Director调度器整个集群的入口持有 VIP。它运行 ipvsadm 工具来配置内核里的 IPVS 规则不实际处理业务请求的具体内容。RealServer真实服务器真正跑业务服务的节点IP 叫 RIPReal IP。它接收 Director 转发过来的请求并处理响应再由不同模式决定是否经过 Director。VIPVirtual IP对外暴露的虚拟 IP客户端只访问这个地址。VIP 通过 VRRP 协议在多个 Director 之间漂移保证高可用。刚开始我容易把 VIP 和业务 IP 混在一起导致配置混乱。后面我习惯用一张表把这些地址理清楚VIP 是逻辑上的对外地址RIP 是物理上的业务地址Director 和 RealServer 都必须能访问到彼此但 VIP 只有 Director以及用于容灾的备用 Director才应该绑定在对外网卡上。把角色划分清楚后面无论是配 keepalived 还是排查问题思路都会顺很多。2. 三种工作模式选错等于白装2.1 NAT 模式省事但不适合大流量VS/NATVirtual Server via Network Address Translation模式的工作原理是Director 收到客户端请求后通过 DNAT 把目标地址从 VIP 改写为选中的 RealServer 的 RIP同时把源地址改写为 Director 的内网地址RealServer 处理完请求把响应回给 DirectorDirector 再通过 SNAT 把源地址改回 VIP把响应返回给客户端。这个模式最大的优点是配置简单RealServer 不需要绑定 VIP后端服务器只需要把网关指向 Director 即可所以它对后端网络环境的要求很低。但缺点也很致命所有进出流量都要经过 Director。请求要过一遍响应还要过一遍Director 的网卡带宽和 CPU 就变成了整个集群的瓶颈。我建议 NAT 模式只在后端服务器数量比较少比如 10 台以内、单机流量不大的场景使用比如小型的数据库读写分离入口、内网测试环境。2.2 DR 模式生产环境主力VS/DRDirect Routing模式是生产环境最常用的一种。它的原理很巧妙Director 收到请求后并不修改 IP 包的目标 IP而是把数据帧的目标 MAC 地址改写成选中的 RealServer 的 MAC 地址再在同一二层网络里直接把帧发出去。RealServer 收到后会发现目标 IP 就是自己绑定的 VIP于是正常处理请求响应则直接通过自身的网关返回给客户端完全不经过 Director。这个方案把响应的流量从 Director 身上释放掉了所以 Director 只需要处理请求方向的流量承载能力大幅提升。我做过一个简单的估算假设请求和响应比例大约是 1:5NAT 模式下 Director 要承接近 6 份流量DR 模式下只承载 1 份请求流量性能差距接近数量级。DR 模式有几个前提条件需要记住Director 和 RealServer 必须在同一个二层网络同一广播域RealServer 必须在内核里抑制对 VIP 的 ARP 响应否则客户端的 ARP 请求会把 RealServer 的真实 MAC 回出去导致整个调度逻辑失效。这两点也是后续实操里最容易出问题的地方。2.3 TUN 模式与模式横向对比VS/TUNIP Tunneling模式是把原始 IP 包再封装一层 IP 隧道通过隧道发给可以跨网段的 RealServer。RealServer 解封装后处理请求同样直接回包给客户端。它的好处是突破二层网络的限制可以实现跨机房、跨地域的调度代价是 IP 封装本身会带来额外开销同时要求 RealServer 支持隧道协议。日常业务里如果集群没有跨地域的需求我一般不会优先选 TUN毕竟多一层封装就多一分排障难度。三种模式对比如下对比项NAT 模式DR 模式TUN 模式请求是否经过 Director是是是响应是否经过 Director是否直接返回否直接返回后端网络要求后端可跨网段必须同一二层网络可跨网段RealServer 是否绑定 VIP不需要需要绑定到 lo 接口需要接受隧道包Director 瓶颈进出双向流量仅请求流量仅请求流量加封装开销推荐场景小规模集群绝大多数互联网业务跨地域部署从我自己的实践看单机房高并发场景选 DR 基本没有悬念。只有当你明确需要跨机房扩展、数据面又不能通过专线打通时才值得考虑 TUN。3. 调度算法与连接管理LVS 的灵魂所在3.1 十种调度算法怎么选LVS 内置了多种调度算法很多初学者直接懵了。我把它们按使用频率分三类说。第一类是轮询类包括 rr轮询和 wrr加权轮询。轮询把所有请求轮流分给后端适合后端服务器性能基本一致的场景加权轮询则允许给不同配置的服务器分配不同权重。这是最直观的算法也是我日常用得最多的。第二类是连接数类包括 lc最少连接、wlc加权最少连接、sed最短预期延迟、nq永不排队。这类算法会看每台后端当前的活动连接数把新请求分给连接数最少的那台。wlc 是 LVS 的默认算法也是大多数场景下比较稳妥的选择因为它同时兼顾了后端性能和当前负载。第三类是目标/源地址哈希类包括 dh目标地址哈希和 sh源地址哈希。这类算法的核心是用哈希函数把同一目标或源 IP 固定映射到同一台后端服务器上天然实现了会话保持。比如在接入层做四层负载均衡时用 sh 可以让同一个客户端的请求始终坚持打到同一台后端避免登录态丢失。选择算法时我一般会问业务三个问题请求是什么类型的连接后端机器能力是否一致需不需要会话保持短连接、机器配置一致直接 wrr 或 wlc视频、下载这类长连接场景优先看连接数而不是请求数需要按客户端 IP 粘滞的考虑 sh 配合持久连接。3.2 关于 lvs soft connect 和 TCP 连接状态机优化这里单独说一下搜索热度比较高的lvs soft connect。从内核实现看LVS 的每个连接在ip_vs_conn结构里都维护了一套 TCP 状态机的跟踪SYN、SYN-ACK、ESTABLISHED、FIN、TIME_WAIT 等状态会被精确记录调度器据此判断一个连接什么时候算活动连接什么时候可以回收。所谓 soft connect软连接常见的理解是指对 TCP 握手阶段做更宽泛或更高效的处理允许在连接还没完全建立时就提前完成调度映射从而降低握手延迟与之对应的还有一组内核参数用来控制连接跟踪的宽松程度谁是关键关键是/proc/sys/net/ipv4/vs/下的几个开关。我实际调过的两个参数值得分享sloppy_tcp默认是 0表示严格跟踪 TCP 状态。如果把它设为 1LVS 在收到非 SYN 首包时也会尽量匹配连接而不是直接丢弃这在某些非标准 TCP 栈或中间设备环境下能减少连接被误杀的问题。conn_reuse_mode默认是 1限制连接重用。当客户端的源端口和地址在短时间内复用时如果 LVS 里还残留上一次的 TIME_WAIT 状态记录新连接可能被错误匹配到旧后端。生产环境我建议结合业务看如果频繁出现连接建立异常可以把它设为 0 来放行重用。还有一个参数是expire_nodest_conn表示后端不可用时是否立刻过期已有连接。我建议在生产里打开避免某台 RealServer 已经宕机但调度器还残留一堆指向它的连接条目新请求只能白白等待超时。把连接状态机的参数理解了很多莫名其妙的连接失败都能找到根因。3.3 连接超时参数的调整心得LVS 对 TCP、TCP FIN、UDP 分别有一套超时时间默认值是 900 秒、120 秒和 300 秒。可以用ipvsadm -L --timeout查看ipvsadm -L --timeout # TCP : 900s # TCP FIN : 120s # UDP : 300s这个默认值不是所有场景都合适。比如一个短连接接口平均请求耗时不到 1 秒但 TCP 超时缺省是 900 秒意味着客户端长时间不复用连接时LVS 仍然要为这些早已不活跃的连接维护状态。连接一多内核内存和连接跟踪表的压力都会上来。我常用的调整方式如下ipvsadm --set 120 10 60这行命令把 TCP 超时改为 120 秒TCP FIN 改为 10 秒UDP 改为 60 秒。调整依据是业务接口的 P99 耗时把超时时间设置为业务最长耗时的 10 倍左右既不会误杀慢请求又不会让陈旧连接占用太多资源。这个思路比盲目套用任何默认值都靠谱。4. 从搭建到上线一份可复现的实操记录4.1 环境规划与内核参数准备这里我用一个最经典的 DR 模式集群做演示。规划三台机器操作系统都是 CentOS 7.9网络都在同一台交换机下角色IP 地址说明VIP192.168.1.100对外虚拟 IP绑定在 Director 上Director192.168.1.5LVS 调度器运行 keepalivedRealServer1192.168.1.10Nginx 业务节点RealServer2192.168.1.11Nginx 业务节点首先检查内核是否已经加载 IPVS 相关模块。大多数 Linux 发行版都编译了这些模块但不一定默认加载modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh lsmod | grep ip_vs如果lsmod看不到输出说明模块加载失败需要检查内核版本和模块路径。加载完模块后顺手开启内核转发虽然 DR 模式对 IP 转发的依赖不像 NAT 模式那么强但保持开启没坏处sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.conf4.2 Director 端配置 VIP 并启动转发Director 上第一步是绑定 VIP。需要把这个地址配置在对外网卡上我这里网卡名是 eth0绑定一个 VIP 别名ifconfig eth0:0 192.168.1.100 netmask 255.255.255.255 broadcast 192.168.1.100注意这里我把掩码写成 255.255.255.255广播地址也写成 VIP 本身。这样做是为了避免内核把 VIP 当作普通子网地址进而产生额外的 ARP 响应。接着用 ipvsadm 配置调度虚拟服务。创建 VIP:80 的转发规则算法用 wrr模式用 DRipvsadm -A -t 192.168.1.100:80 -s wrr ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.10:80 -g -w 1 ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g -w 2参数说明-A表示添加虚拟服务-a表示添加真实服务器-r指定后端 RIP-g表示使用 DR 模式gateway-w设置权重。我希望性能更好的 11 号机多承担一点流量所以把它的权重调成 2。配置完成后用ipvsadm -L -n查看当前规则ipvsadm -L -n # IP Virtual Server version 1.2.1 # Prot LocalAddress:Port Scheduler Flags # - RemoteAddress:Port Forward Weight ActiveConn InActConn # TCP 192.168.1.100:80 wrr # - 192.168.1.10:80 Route 1 0 0 # - 192.168.1.11:80 Route 2 0 0看到 Forward 列是 Route就说明规则已经生效。到此 Director 端的最小配置就完成了剩下的事情交给 keepalived。4.3 RealServer 端 ARP 抑制与 VIP 配置DR 模式下RealServer 也必须把 VIP 绑定到本机这样才能处理目标 IP 是 VIP 的请求。但要绑定在一个特殊的接口上常见做法是绑定到 lo 的回环别名ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 broadcast 192.168.1.100如果不做任何 ARP 抑制问题就来了客户端或者交换机在二层广播询问谁是 192.168.1.100时RealServer 会直接应答客户端可能把请求帧发给 RealServer 而不是 Director调度直接失效。所以必须在 RealServer 上做 ARP 抑制让 RealServer 不对外应答 VIP 的 ARP 请求。配置方法如下sysctl -w net.ipv4.conf.all.arp_ignore1 sysctl -w net.ipv4.conf.all.arp_announce2 sysctl -w net.ipv4.conf.lo.arp_ignore1 sysctl -w net.ipv4.conf.lo.arp_announce2arp_ignore1的含义是只应答目标 IP 是本接口 IP 的 ARP 请求。VIP 虽然绑在 lo:0 上但它属于 lo 接口对外网卡 eth0 的 ARP 请求不会响应。arp_announce2的含义是发送 ARP 请求时使用路由表里最合适的本地 IP 作为源地址而不是使用 lo 上的 VIP。这两个参数一起作用才能保证 RealServer 只收请求、不应答 VIP。配置完记得写入/etc/sysctl.conf否则重启机器后就丢了。这也是很多网友说配置完当时能通一重启就不行的根本原因。4.4 联调验证与压测记录到这一步可以在客户端用 VIP 发起请求验证集群是否正常curl http://192.168.1.100/多请求几次观察返回内容。如果两个 RealServer 上的页面内容不同很容易确认请求是否被轮流分发。如果每次都只打到同一台先检查权重和调度算法再观察是否命中持久连接。我习惯同时打开两个终端一个跑请求一个看调度统计watch -n 1 ipvsadm -L -n --rate这个命令会实时显示每个真实服务器的连接数和速率方便判断流量分配是否符合预期。压测时我用 wrk 做了 5 万并发、持续 10 分钟的测试Director 的 CPU 始终压在 10% 以内连接建立速度非常稳定。相对于之前 Nginx 在相同压力下 CPU 跑满的情况这个对比足以说明 LVS 在内核态转发的优势。5. 生产环境常见坑与排查技巧5.1 问题时序排查的三个习惯生产环境出了问题最忌讳的是头痛医头。我养成了一套固定的排查顺序分享给大家第一看内核模块和 keepalived 状态。lsmod | grep ip_vs确认模块正常ps aux | grep keepalived确认高可用程序没挂。很多时候问题根本不是配置写错而是模块或服务没起来。第二抓包看报文路径。强烈推荐在客户端、Director、RealServer 三个点分别抓包对比同一连接的报文走向。DR 模式下最容易出现的问题就是客户端直连了 RealServer一抓包立即现形客户端发的 ARP 请求直接被 RealServer 响应了Director 完全不知情。第三看连接跟踪和统计。ipvsadm -L -n --stats能看到每个后端的请求数、连接数、字节数再配合ipvsadm -L -n -c查看当前连接跟踪表判断连接是否堆积。连接跟踪表里全是 TIME_WAIT 状态且指向某台已下线机器基本就是expire_nodest_conn没开。5.2 高频问题速查表下面这张表是我这几年处理 LVS 问题时积累的速查表涵盖我自己遇到的和帮别人排查过的典型问题现象常见原因解决办法客户端能 ping 通 VIP但无法建立 TCP 连接IPVS 模块未加载或 keepalived 未正常管理 VIPmodprobe 加载 ip_vs 系列模块检查 keepalived 日志访问 VIP 时流量全部打到某一台服务器调度算法为持久连接后端权重差异过大检查算法和权重确认sh/-p参数是否按预期配置RealServer 状态显示不可用健康检查 TCP_CHECK 路径或端口错误检查 RealServer 端口、健康检查地址、防火墙规则重启后 LVS 配置全部丢失ipvsadm 规则和 sysctl 参数没写入持久化文件写入/etc/sysconfig/ipvsadm和/etc/sysctl.confDirector 和 RealServer 的 VIP 冲突导致丢包ARP 抑制未配置在两台 RealServer 上设置 arp_ignore1、arp_announce2高峰期新连接间歇性失败连接跟踪表满或超时时间设置过长调小 tcp/tcpfin/udp 超时增大哈希表大小keepalived 主备频繁切换VRRP 通告间隔过短或网络抖动调整 advert_int检查交换机对组播/多播包的支持这些问题其实都有共性大多不是 LVS 本身的问题而是周边参数、网络环境或服务状态导致的。养成先定位再动手的习惯能省下很多不必要的重启时间。5.3 用 LVS 和 Nginx 配合的经典架构最后聊聊 LVS 在完整架构里的位置。我现在的标准做法是两层负载均衡最外层用 LVS 做四层接入负责海量 TCP 连接的分发和高可用下一层用 Nginx 做七层业务路由负责域名转发、SSL 卸载、URL 匹配这些精细逻辑再往后才是应用服务器和数据库。三层结构看起来多了个 Nginx 层似乎很冗余但实际上每一层都在干自己最擅长的事。LVS 不解析 HTTP 头转发效率高Nginx 不做海量 TCP 堆叠专注协议级路由。两者配合既拿到了性能又保留了灵活性。比如后面想加灰度发布直接在 Nginx 层按 Header 或 Cookie 分流LVS 那边完全不用动。这种架构在 Kubernetes 场景里也有对应版本kube-proxy 的 ipvs 模式本质上就是利用 IPVS 做 Service 的四层负载均衡原理和传统 LVS 一脉相承。学会了 LVS再去看 Kubernetes 的网络模型会感觉很多东西都通了。最后再分享一个细节LVS 配置完之后一定要记得把所有 ipvsadm 规则导出保存我习惯写成/etc/sysconfig/ipvsadm这样重启后可以自动恢复。另外每次改完内核参数别急着上生产先在一台测试机上跑一轮连接验证。我一开始图快直接改生产机结果 ARP 配置顺序写错整层 VIP 服务中断了十几秒被值班电话打爆。从那以后LVS 这类网络层的改动我再也不敢跳过小流量验证了。希望这篇总结能帮你少踩几个坑把 LVS 真正用出价值来。
返回列表