0%

LVS

LVS 四层负载均衡

LVS 工作原理

理解 LVS 工作原理,理解 Netfilter 是前提条件

Netfilter

Netfilter 是 Linux 内核中一个的网络数据包处理框架,是 LVS 实现的底层引擎。

Netfilter 在网络层设下了5个 hook,IPVS、iptables 这些 Linux 内核模块通过向这些 hook 注册回调函数来处理数据包。

Netfilter hook:

  1. PREROUTING
    • 时机:数据包刚进入网络层,在进行路由决策之前,所有接收的数据包到达的第一个 hook
    • 作用:通常在这里进行目标地址转换(DNAT),决定数据包是发给本机,还是需转发
  2. INPUT (LOCAL_IN)
    • 时机:数据包经过路由判断,发现其目标地址是本机
    • 作用:控制外部对本机的访问,是入站防火墙规则的核心位置
  3. FORWARD
    • 时机:数据包经过路由判断,发现其目标地址不是本机,而是需要本机进行转发(例如,本机作为路由器或网关)
    • 作用:控制流经本机的数据包,是转发防火墙规则的核心位置
  4. OUTPUT (LOCAL_OUT)
    • 时机:由本机进程产生的数据包,准备发送出去
    • 作用:控制本机程序对外部网络的访问,是出站防火墙规则的核心位置
  5. POSTROUTING
    • 时机:数据包即将离开本机,通过物理网络设备发送出去之前
    • 作用:通常在这里进行源地址转换(SNAT),比如让内网机器通过网关的公网IP访问互联网

IPVS 工作原理

IPVS(LVS 的内核模块)在 Netfilter 注册了 3 个核心 hook 函数

ip_vs_in() —— 核心入口函数

  • 挂载点:通常在 LOCAL_IN
  • 触发时机:当客户端的请求数据包到达 LVS 服务器,且目标地址是虚拟 IP(VIP)时触发
  • 核心作用
    1. 检查连接(Connection Lookup)
      • 它会先查表(哈希表),看这个请求是否属于一个已经建立的连接
      • 如果是老请求(比如 TCP 握手后的数据包),直接按之前的路径转发,不重新调度
    2. 新建连接与调度(Scheduling)
      • 如果是新请求(如 TCP SYN 包),它会调用调度算法(如轮询 rr、最少连接 lc)从后端真实服务器池中挑选一台服务器
    3. 建立连接记录
      • 在内存中创建一个 ip_vs_conn 结构体,记录“客户端 <-> LVS <-> 真实服务器”的映射关系
    4. 修改数据包(DNAT/MAC)
      • 根据工作模式(NAT、DR、TUN),修改数据包的目标 IP 或 MAC 地址,将其指向选中的真实服务器
    5. 重定向
      • 修改完后,它通常返回 NF_STOLEN,告诉内核“这个包我接管了,别再往下传了”,并将其推向转发流程

ip_vs_out() —— 响应处理函数

  • 挂载点NF_INET_FORWARD
  • 触发时机:当真实服务器处理完请求,返回响应包,且该数据包流经 LVS 时触发
    • 注意:在 DR 模式下,响应包直接回客户端,不经过此函数;此函数主要在 NAT 模式下起作用。
  • 核心作用
    1. 查找连接
      • 根据响应包的五元组(源 IP、源端口、目标 IP、目标端口、协议),在连接表中找到对应的 ip_vs_conn 记录
    2. 源地址转换(SNAT)
      • 这是最关键的一步。它会将响应包的源 IP(真实服务器 IP)修改为虚拟 IP(VIP)
      • 这样,客户端收到的包看起来就是 VIP 发回来的,从而实现了负载均衡的透明性
    3. 状态更新
      • 更新连接的状态(如 TCP 序列号),确保连接跟踪的准确性

ip_vs_post_routing() —— 最后的关卡

  • 挂载点NF_INET_POST_ROUTING
  • 触发时机:数据包即将离开网卡,发送到物理网络之前的最后一刻
  • 核心作用
    1. 防止规则冲突
      • 它的主要任务是确保经过 IPVS 处理过的数据包,不再被 iptables 的 NAT 规则重复处理
      • 如果没有这个函数,iptables 可能会再次修改已经被 IPVS 修改过的地址,导致网络错乱
    2. 快速放行
      • 它会检查数据包是否带有 IPVS 的标记。如果有,直接返回 NF_ACCEPTNF_STOLEN,让数据包迅速通过,不再进行复杂的防火墙规则匹配,提高转发效率

请求包流程(CIP -> VIP -> RS)

1. PREROUTING 链:入场

  • 动作:数据包从网卡进入,到达 PREROUTING
  • Netfilter 行为:此时数据包的目标 IP 是 VIP。内核进行路由查找(Routing Decision)。
  • 判断:因为 VIP 配置在 LVS 的网卡上,内核认为“这个包是发给本机的”
  • 流向:数据包被送往 INPUT 链。

2. INPUT 链:LVS 的核心拦截点 (ip_vs_in)

这是 LVS 最关键的“魔法”发生地。

  • Hook 函数ip_vs_in()
  • 动作
    1. 拦截:IPVS 模块在 INPUT 链上注册了钩子,它比普通的 TCP/IP 协议栈更早拿到数据包。
    2. 匹配:检查数据包的目标 IP:Port(VIP:80)是否在 IPVS 的服务列表中。
    3. 调度:如果是新连接,根据算法(如轮询)选一台真实服务器(RS)。
    4. 修改(关键)
      • NAT 模式:修改目标 IP 为 RS 的 IP(DNAT)。
      • DR 模式:修改目标 MAC 地址为 RS 的 MAC。
    5. 连接跟踪:在 Conntrack 表中建立一条记录,标记这个连接将来需要怎么处理回包。
    6. 重定向:IPVS 修改完包后,会告诉内核“这个包我处理了”,并将其强制转发POSTROUTING 链,而不是交给本机的应用程序(如 Nginx/Apache)。

3. POSTROUTING 链:离场

  • Hook 函数ip_vs_post_routing()
  • 动作
    • 数据包此时已经变成了发往 RS 的样子(目标 IP 或 MAC 已变)。
    • ip_vs_post_routing() 的作用是“放行”。它给数据包打上标记,告诉后续的 iptables 规则:“这个包是 LVS 转发的,不要再做 SNAT/Masquerade 处理了,直接发走吧。”
  • 流向:数据包通过物理网卡发出,到达真实服务器(RS)。

NAT 响应包流程(RS -> LVS -> CIP)

1. PREROUTING 链:入场

  • 动作:响应包从网卡进入 LVS。
  • Netfilter 行为:内核进行路由查找。
  • 判断:目标 IP 是 CIP(外网 IP),不是本机。
  • 流向:数据包被送往 FORWARD 链。

2. FORWARD 链:LVS 的还原点 (ip_vs_out)

  • Hook 函数ip_vs_out()
  • 动作
    1. 识别:IPVS 检查数据包的五元组,发现这个包属于之前建立的那个连接(通过 Conntrack 表匹配)。
    2. 还原(SNAT):IPVS 将数据包的源 IP 从 RS 的 IP(RIP)修改回 VIP
      • 目的:让客户端觉得是 VIP 给它回的包,而不是 RS。
    3. 流向:修改完成后,数据包继续向前,进入 POSTROUTING

3. POSTROUTING 链:离场

  • Hook 函数ip_vs_post_routing()
  • 动作
    • 同样,这里的作用是防止被 iptables 的其他规则干扰。
    • 确认数据包已经完成 SNAT,允许其离开网卡。
  • 流向:数据包发往互联网,最终回到客户端(CIP)。

LVS 组成

  • LVS (Linux Virtual Server)
    • 本质:它是运行在 Linux 操作系统内核中的一个模块(具体称为 IPVS,IP Virtual Server)。
    • 作用:它是真正干活的“搬运工”,负责在操作系统底层(第四层)拦截网络数据包,并根据预设的算法将流量转发给后端的真实服务器(Real Server)。没有独立的进程。
  • ipvsadm
    • 本质:它是一个运行在用户空间的命令行管理工具。
    • 作用:它是管理员与 LVS 内核模块沟通的“传声筒”。管理员通过 ipvsadm 命令来添加、删除或查看 LVS 的转发规则(例如:设置 VIP、添加后端服务器、指定轮询算法等)。
  • Keepalived
    • 本质:它是一个运行在用户空间的系统守护进程(服务)。
    • 作用:它是 LVS 的“大管家”和“保镖”。它不仅能自动调用 ipvsadm 的功能来配置 LVS 规则,还能监控后端服务器的健康状态,并通过 VRRP 协议实现 LVS 调度器自身的高可用(主备切换)。

LVS 工作模式

DR(直接路由)

请求经过负载均衡器,响应直接返回给客户端

前提条件:

  • LVS 和 RS 在同一物理网段内(可以通过修改 MAC 下一跳直达的前提)
  • LVS 和 RS 同时配置 VIP(RS 可以接收目的 IP 为 VIP 包的前提)

转发流程:

  • 请求阶段
    1. 源/目的 IP 保持不变,源 IP 为客户端 IP(CIP),目的 IP 为 VIP
    2. 通过修改目的 MAC 地址,将下一跳规定为同一物理网段内的 RS 节点
  • 响应阶段
    1. 不返回 LVS,直接返回到客户端
    2. 源 IP 为 VIP,目的 IP 为 客户端 IP(CIP)

优点:

  • 高性能,LVS 不用处理响应,负载降低一半
  • IP 透明,RS 可以拿到客户端 IP(CIP)

缺点:

  • 不支持端口映射,转发只能相同端口
  • 强制要求 LVS 和 RS 在同一物理网段内
  • 强制要求每台 RS 上配置 VIP 和 ARP 抑制

NAT(网络地址转换)

请求和响应双向流量都经过 LVS

前提条件:

  • LVS 同时配置 VIP 和 内网 IP(DIP)
  • LVS 和 RS 位于同一个物理子网内(能将 LVS 配置为默认网关的前提)
  • RS 的默认网关指向 LVS 的 DIP(返回的响应包走 LVS 的前提)

转发流程:

  • 请求阶段
    1. LVS 将请求的目的 IP 从 VIP 修改为 RS 的 RIP
    2. 更改端口
  • 响应阶段
    1. LVS 作为默认网关接收 RS 返回的响应包
    2. 将响应的源 IP 从 RIP 修改为 VIP,并更改端口

优点:

  • 无需 RS 配置 VIP,对 RS 没有特殊要求
  • 支持端口映射,VIP 和 RIP 不需要是相同端口
  • IP 透明,RS 可以拿到客户端 IP(CIP)

缺点:

  • 强制要求 LVS 和 RS 在同一物理网段内
  • 性能瓶颈,请求和响应都必须经过 LVS,双倍流量要求

Tunnel(IP 隧道)

请求通过 IP 隧道封装,响应直接返回

前提条件:

  • RS 上配置 VIP 和 IP 隧道(解 IP 封装的前提)

转发流程:

  • 请求阶段
    1. LVS 在请求 IP 头前再封装一层 IP 头,源 IP 是 LVS 的 DIP,目的 IP 是 RS 的 RIP
    2. RS 收到请求包后,解封装出原本的 IP 头
  • 响应阶段
    1. RS 直接返回,源 IP 是 VIP,目的 IP 是 CIP

优点:

  • 突破性能瓶颈,LVS 只处理请求包
  • LVS 和 RS 不要求同一物理网段内,可跨网段部署
  • IP 透明,RS 可以拿到客户端 IP(CIP)

缺点:

  • 不支持端口映射
  • 强制要求每台 RS 上配置 VIP 和 IP 隧道

FullNAT(全地址转换)

NAT 增强型,请求和响应双向流量都经过 LVS,但不要求同一网段

前提条件:

  • LVS 支持 FULLNAT(原生 LVS 不支持)

转发流程:

  • 请求阶段
    1. LVS 将请求的源 IP 修改为本地的转发 IP(DIP),目的 IP 改为 RIP
    2. 更改端口
  • 响应阶段
    1. LVS 将响应的源 IP 修改为 VIP,目的 IP 改为 CIP
    2. 更改端口

优点:

  • 无需 RS 配置 VIP,对 RS 没有特殊要求
  • 支持端口映射,VIP 和 RIP 不需要是相同端口
  • LVS 和 RS 不要求同一物理网段内,可跨网段部署

缺点:

  • 真实客户端 IP 丢失,RS 端无法收到 CIP,只能看到 LVS 的 DIP,需要通过 LVS 在 TCP Option 内添加 TOA 模块来携带 CIP
  • 性能瓶颈,请求和响应都必须经过 LVS,双倍流量要求,且来回都要经过源目 IP 转换

LVS 负载均衡算法

负载均衡算法决定了 LVS 要把请求转发到哪个 RS,分为静态调度(不关心后端实时负载)和动态调度(根据后端实时负载动态调整)。

静态调度

RR(轮询调度)

按顺序将请求依次轮流分配给集群中的每台服务器,循环往复。

WRR(加权轮询调度)

在 RR 的基础上,为每台服务器分配的权重(Weight)进行调度。权重越高的服务器,分配到的请求比例越大。

SH(源地址哈希调度)

根据请求的源 IP 地址(客户端 IP)进行哈希运算,从静态哈希表中找到对应的服务器。

DH(目标地址哈希调度)

根据请求的目标 IP 地址(或目标端口)进行哈希运算,决定请求分配给哪台服务器。

动态调度

LC(最少连接调度)

动态地将新请求分配给当前已建立连接数最少的服务器。

WLC(加权最少连接调度)

结合最少连接和服务器权重进行计算。公式通常为:(当前连接数 / 权重)(当前连接数 × 256 + 非活跃连接数) / 权重,计算结果最小的服务器获得新请求。

会话保持

会话保持(Session Persistence)的作用是将同一个客户端的请求转发到同一 RS,从而保证 TCP 长连接。

核心参数 persistence_timeout

  • 工作原理:LVS 会在内存中维护一个持久连接表,记录客户端 IP 与后端 RS 的绑定关系。只要在该超时时间内,来自源 IP 的包都会绕过调度算法,直接路由到之前选定的 RS。

  • 配置方式:在 Keepalived 的 virtual_server 配置块中,添加 persistence_timeout 参数(单位为秒)。

    1
    2
    3
    4
    virtual_server 172.19.1.19 5222 {
    persistence_timeout 60 # 会话保持 60 秒
    ...
    }

LVS 健康检查

LVS(IPVS 内核模块)只负责包转发,对 RS 的健康检查由 keepalived 承担。

工作机制

Keepalived 会根据配置文件设定的时间间隔,定期向后端 RS 发送探测请求。

  • 故障剔除:如果某台 RS 连续多次未能正确响应探测请求,Keepalived 会判定其处于故障状态,并自动调用 ipvsadm 工具将其从 LVS 的转发规则池中移除,不再向其分配新的连接。
  • 自动恢复:当该 RS 恢复正常,且连续多次成功响应探测后,Keepalived 会重新将其加入 LVS 规则中,恢复流量转发。

检查方式

TCP_CHECK

  1. Keepalived 向 RS 发送 SYN
  2. 如果 RS 返回 SYN+ACK,则视 RS 为健康;超时则视为不健康
  3. Keepalived 向 RS 发送 RST 主动中断连接

HTTP_GET

  1. Keepalived 向 RS 发送 HTTP GET 请求
  2. 如果返回的 HTTP 状态码符合期望值(如期望 200),则视 RS 为健康,否则视为不健康

SSL_GET

HTTP_GET 的逻辑完全相同,区别在于 SSL_GET 走 HTTPS 协议

MISC_CHECK

用户自定义脚本/命令检查 RS 状态

防抖动机制

为了避免网络瞬间抖动导致 RS 被频繁剔除和加入,Keepalived 引入了“时间窗”概念。只有在连续多次检查成功或失败后,才会真正切换状态。这通常由以下几个参数控制:

  • 检查间隔 (delay_loop):每隔多久进行一次探测。
  • 响应超时时间 (connect_timeout):等待服务器返回响应的最长时间(单位:秒)。
  • 重试次数 (nb_get_retry / nb_sock_retry):连续失败多少次才最终判定为故障。
  • 重试间隔 (delay_before_retry):每次重试之间的等待时间(单位:秒)。

Keepalived 配置