今天跟大家分享一下用LVS+Keepalived搭建高可用负载均衡的实践(踩坑)。

说起来也是巧,刚开始接触负载均衡的时候,我以为Nginx就是万能的(多希望能一招鲜吃遍天)。后来业务量上来了才发现,Nginx是七层的负载均衡。与四层负载均衡的主要区别在于工作层级和处理的数据内容。在四层负载均衡方面还是有局限性的。特别是那种大流量、高并发的场景,LVS的优势就体现出来了。

什么是LVS

LVS全称Linux虚拟服务器(LVS)是由章文嵩(国防科技大学)博士于1998年5月发起的一个开源项目,旨在通过集群技术构建高性能、高可用的虚拟服务器系统,是中国早期具有代表性的自由软件项目之一。其核心功能是通过IP负载均衡技术将客户端请求分发至服务器集群,实现服务的可伸缩性与透明性,支持TCP/UDP协议及持久连接。

LVS采用三层架构:前端负载调度器(负责分发请求)、中间服务器池(处理实际服务)和底层共享存储(保障数据一致性)。系统提供三种IP负载均衡模式:基于网络地址转换的VS/NAT、基于IP隧道的VS/TUN以及基于直接路由的VS/DR,分别适配不同网络环境。调度算法包括轮询、加权最少连接等八种策略,优化资源分配。随着技术演进,LVS被集成至Linux内核,并广泛应用于Web、邮件等高并发场景,形成覆盖千级节点的集群框架。

为什么选择LVS+Keepalived这个组合?

这个问题我被问过无数次了。简单来说,LVS负责干活,Keepalived负责保命。

LVS工作在内核空间,处理数据包的效率极高。我记得当时做压测,单台LVS能轻松处理几十万的并发连接,这个数据在当时简直让人不敢相信。而且LVS对后端服务器完全透明,不需要修改任何应用代码。

但LVS有个致命缺陷,就是没有健康检查功能。如果后端服务器挂了,LVS还是会继续往那台机器上转发请求,用户就会看到连接超时的错误页面。

这时候Keepalived就派上用场了。它不仅能提供健康检查,还能实现LVS的高可用。两台LVS服务器互为备份,主服务器挂了,备服务器立马接管,用户基本感觉不到。

我之前用过F5这种硬件负载均衡器,功能确实强大,但价格也是真的贵。一台设备几十万,小公司根本用不起。LVS+Keepalived这个组合,成本低,性能好,稳定性也不差,性价比超高。

架构设计和规划

在开始配置之前,我们先来理一下整体架构。我一般会采用这样的设计:

Internet
    |
    v
VIP (虚拟IP)
    |
    v
LVS Master/Backup (Keepalived)
    |
    v
Real Servers (Web服务器集群)

2025-07-29T15:26:16.png

这个架构的好处是简单清晰,用户访问VIP,LVS负责将请求分发到后端的真实服务器上。如果主LVS挂了,备LVS会自动接管VIP,保证服务不中断。

在实际部署中,我会准备至少4台服务器:

  • 2台LVS服务器(主备)
  • 2台以上的Web服务器

当然,如果预算有限,也可以把LVS和Web服务器部署在同一批机器上,但这样会增加故障的风险。

LVS的工作模式选择

LVS有三种工作模式,我在生产环境中主要用DR模式。

NAT模式虽然配置简单,但所有的响应流量都要经过LVS,容易成为瓶颈。我曾经在一个小项目中用过NAT模式,刚开始还好,但随着用户量增长,LVS的网卡很快就跑满了。

TUN模式适合跨地域的部署,但配置复杂,而且对网络环境要求比较高。除非是特殊需求,否则我不建议使用。

DR模式是我的首选。在这种模式下,LVS只处理入站流量,出站流量直接从后端服务器返回给客户端,避免了流量瓶颈。而且配置相对简单,性能也最好。

DR模式的关键在于MAC地址重写。LVS收到客户端请求后,修改数据包的目标MAC地址,然后转发给后端服务器。后端服务器需要配置VIP作为回环地址,这样才能正确处理请求。

实际配置过程

好了,理论说得差不多了,现在开始实际配置。我以一个典型的Web服务负载均衡为例。

环境准备

假设我们有以下服务器:

  • LVS1: 192.168.1.10 (主)
  • LVS2: 192.168.1.11 (备)
  • Web1: 192.168.1.20
  • Web2: 192.168.1.21
  • VIP: 192.168.1.100

所有服务器都是CentOS 7系统,网卡名称为eth0。

LVS服务器配置

首先在两台LVS服务器上安装必要的软件:

yum install -y ipvsadm keepalived

然后配置内核参数,开启IP转发:

echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p

Keepalived主服务器配置

在LVS1上创建keepalived配置文件 /etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
   notification_email {
     admin@example.com
   }
   notification_email_from keepalived@example.com
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id LVS_MASTER
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

virtual_server 192.168.1.100 80 {
    delay_loop 6
    lb_algo wlc
    lb_kind DR
    persistence_timeout 0
    protocol TCP

    real_server 192.168.1.20 80 {
        weight 3
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
    
    real_server 192.168.1.21 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
            connect_port 80
        }
    }
}

这个配置文件看起来复杂,但其实逻辑很清晰。上半部分是VRRP配置,用于实现主备切换;下半部分是LVS配置,定义了虚拟服务器和真实服务器。

Keepalived备服务器配置

在LVS2上的配置基本相同,只需要修改几个参数:

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90    # 优先级要低于主服务器
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.100
    }
}

注意priority参数,备服务器的优先级必须低于主服务器,这样才能保证正常情况下主服务器持有VIP。

后端服务器配置

这是DR模式配置中最容易出错的地方。每台后端服务器都需要配置VIP作为回环地址,并且设置ARP参数。

在Web1和Web2上执行以下命令:

# 配置VIP到回环接口
ifconfig lo:0 192.168.1.100 netmask 255.255.255.255 up

# 设置ARP参数,防止ARP冲突
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce

为了让配置永久生效,还需要写到系统配置文件中:

# 写入网络配置文件
cat > /etc/sysconfig/network-scripts/ifcfg-lo:0 << EOF
DEVICE=lo:0
IPADDR=192.168.1.100
NETMASK=255.255.255.255
ONBOOT=yes
EOF

# 写入内核参数配置
cat >> /etc/sysctl.conf << EOF
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
EOF

sysctl -p

启动和测试

配置完成后,就可以启动服务了。

在两台LVS服务器上启动keepalived:

systemctl start keepalived
systemctl enable keepalived

启动后,可以通过以下命令检查状态:

# 查看VIP是否绑定成功
ip addr show eth0

# 查看LVS规则
ipvsadm -ln

# 查看keepalived日志
tail -f /var/log/messages

如果一切正常,你应该能看到VIP绑定在主服务器的网卡上,LVS规则也正确加载了。

测试的时候,我一般会用curl命令访问VIP:

curl -I http://192.168.1.100

如果能正常返回HTTP响应头,说明负载均衡工作正常。

踩过的坑和解决方案

在实际部署过程中,我遇到了不少问题,这里分享几个典型的。

ARP问题

这是DR模式最常见的问题。如果ARP参数配置不正确,会导致网络混乱,客户端无法正常访问。

症状:客户端访问VIP时,有时能访问,有时不能访问,表现很不稳定。

解决方案:确保所有后端服务器都正确配置了arp_ignore和arp_announce参数。这两个参数的作用是:

  • arp_ignore=1:只响应目标IP是本机IP的ARP请求
  • arp_announce=2:使用最合适的本地IP作为ARP请求的源IP

脑裂问题

有一次网络出现故障,两台LVS服务器都认为对方挂了,结果都绑定了VIP,造成了脑裂。

为了避免这个问题,我在keepalived配置中增加了脚本检查:

vrrp_script chk_http_port {
    script "/etc/keepalived/check_web.sh"
    interval 2
    weight -2
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    # ... 其他配置
    track_script {
        chk_http_port
    }
}

检查脚本 /etc/keepalived/check_web.sh

#!/bin/bash
counter=$(ps -C httpd --no-heading|wc -l)
if [ "${counter}" = "0" ]; then
    exit 1
else
    exit 0
fi

这样,如果本机的Web服务出现问题,keepalived会自动降低优先级,让备服务器接管。

性能调优

刚开始部署的时候,性能并没有达到预期。后来发现是一些内核参数没有优化。

# 增加连接跟踪表大小
echo 'net.netfilter.nf_conntrack_max = 1048576' >> /etc/sysctl.conf

# 调整TCP参数
echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_tw_recycle = 1' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_fin_timeout = 30' >> /etc/sysctl.conf

# 增加端口范围
echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf

sysctl -p

还有一个重要的优化是网卡中断绑定。在高并发场景下,把网卡中断绑定到特定的CPU核心上,能显著提升性能:

# 查看网卡中断号
cat /proc/interrupts | grep eth0

# 绑定中断到CPU核心(假设中断号是24)
echo 2 > /proc/irq/24/smp_affinity

监控和运维

部署完成后,监控是必不可少的。我一般会监控以下几个指标:

LVS连接状态

# 查看连接统计
ipvsadm -ln --stats

# 查看当前连接
ipvsadm -ln --connection

# 查看连接数
cat /proc/net/ip_vs_stats

系统资源监控

# CPU使用率
top

# 内存使用情况
free -h

# 网络流量
iftop

日志监控

keepalived的日志通常记录在 /var/log/messages 中,需要定期检查是否有异常信息。

我写了一个简单的监控脚本,定期检查服务状态:

#!/bin/bash

# 检查keepalived进程
if ! pgrep keepalived > /dev/null; then
    echo "Keepalived is not running!"
    # 发送告警邮件或短信
fi

# 检查VIP是否绑定
if ! ip addr show eth0 | grep 192.168.1.100 > /dev/null; then
    echo "VIP is not bound to this server"
fi

# 检查后端服务器健康状态
ipvsadm -ln | grep -v "RemoteAddress" | while read line; do
    if echo $line | grep -q "Route"; then
        server=$(echo $line | awk '{print $2}')
        if ! nc -z ${server%:*} ${server#*:}; then
            echo "Server $server is down!"
        fi
    fi
done

故障处理经验

在生产环境中,故障是不可避免的。我遇到过几次比较典型的故障,这里分享一下处理经验。

主服务器宕机

这种情况下,keepalived会自动进行主备切换,理论上用户不会感知到。但有一次切换过程中,发现新的主服务器上LVS规则没有正确加载。

原因是keepalived配置文件中的virtual_server配置有问题。解决方法是在备服务器上手动执行:

ipvsadm -C  # 清空现有规则
systemctl restart keepalived  # 重启keepalived

为了避免这种情况,我现在都会在keepalived配置中添加notify脚本:

vrrp_instance VI_1 {
    # ... 其他配置
    notify_master "/etc/keepalived/notify_master.sh"
    notify_backup "/etc/keepalived/notify_backup.sh"
    notify_fault "/etc/keepalived/notify_fault.sh"
}

notify_master.sh脚本内容:

#!/bin/bash
echo "$(date) - Becoming MASTER" >> /var/log/keepalived-state.log
# 确保LVS规则正确加载
sleep 2
ipvsadm -ln > /dev/null || systemctl restart keepalived

后端服务器故障

有一次其中一台Web服务器的磁盘满了,导致Apache无法正常工作。虽然keepalived的健康检查发现了问题,把这台服务器从负载均衡池中移除了,但用户还是反映偶尔会遇到访问异常。

后来发现是健康检查的间隔时间设置得太长了。我把检查间隔从6秒调整到2秒,故障检测的敏感度提高了很多:

virtual_server 192.168.1.100 80 {
    delay_loop 2  # 从6秒改为2秒
    # ... 其他配置
}

还有一个问题是TCP_CHECK只能检查端口是否开放,不能检查应用是否正常工作。比如Apache进程还在,但已经无法处理请求了。

为了解决这个问题,我改用HTTP_GET检查:

real_server 192.168.1.20 80 {
    weight 3
    HTTP_GET {
        url {
            path /health.html
            status_code 200
        }
        connect_timeout 3
        nb_get_retry 3
        delay_before_retry 3
    }
}

在每台Web服务器上创建一个简单的健康检查页面 /var/www/html/health.html

OK

这样就能更准确地检测应用的健康状态了。

网络分区故障

最麻烦的一次故障是机房网络出现了分区,两台LVS服务器之间无法通信,但都能正常访问外网。结果两台服务器都认为对方挂了,都绑定了VIP,造成了严重的网络混乱。

这种情况下,最好的解决方案是引入第三方仲裁。我后来在配置中增加了多个检查点:

vrrp_instance VI_1 {
    # ... 其他配置
    unicast_src_ip 192.168.1.10
    unicast_peer {
        192.168.1.11
    }
}

使用单播模式可以减少网络广播,提高稳定性。

高级配置和优化

随着业务的发展,基本的负载均衡配置可能无法满足需求。这里分享一些高级配置技巧。

会话保持

有些应用需要会话保持,比如购物车功能。LVS支持基于源IP的会话保持:

virtual_server 192.168.1.100 80 {
    # ... 其他配置
    persistence_timeout 300  # 会话保持5分钟
}

但这种方式有个问题,如果用户通过NAT网关访问,多个用户可能会被分配到同一台服务器上,造成负载不均衡。

更好的解决方案是在应用层实现会话共享,比如使用Redis存储session数据。

多端口负载均衡

如果需要对多个端口进行负载均衡,可以配置多个virtual_server:

virtual_server 192.168.1.100 80 {
    # HTTP服务配置
}

virtual_server 192.168.1.100 443 {
    # HTTPS服务配置
    lb_algo wlc
    lb_kind DR
    protocol TCP
    
    real_server 192.168.1.20 443 {
        weight 1
        TCP_CHECK {
            connect_port 443
        }
    }
}

防火墙配置

在生产环境中,防火墙配置很重要。需要开放以下端口:

# LVS服务器之间的VRRP通信
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='192.168.1.0/24' protocol value='vrrp' accept"

# 允许客户端访问VIP
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp

# 重新加载防火墙规则
firewall-cmd --reload

容量规划和扩展

随着业务增长,单个负载均衡集群可能无法满足需求。这时候需要考虑扩展方案。

水平扩展

最简单的方式是增加后端服务器。在keepalived配置中添加新的real_server即可:

real_server 192.168.1.22 80 {
    weight 1
    HTTP_GET {
        url {
            path /health.html
            status_code 200
        }
    }
}

添加完配置后,重新加载keepalived:

systemctl reload keepalived

垂直扩展

如果LVS服务器成为瓶颈,可以考虑升级硬件配置,特别是网卡和CPU。

我曾经遇到过网卡成为瓶颈的情况,单个千兆网卡在高峰期跑满了。后来换成万兆网卡,问题就解决了。

多层负载均衡

对于超大规模的应用,可以考虑多层负载均衡架构:

DNS轮询 -> LVS集群 -> Nginx集群 -> 应用服务器集群

这样可以充分发挥每种技术的优势,实现更好的性能和可扩展性。

与云服务的对比

现在很多公司都在上云,云厂商提供的负载均衡服务确实很方便。但自建LVS集群也有它的优势。

成本方面:云负载均衡按流量计费,对于大流量应用来说成本不低。自建LVS集群虽然需要投入人力维护,但硬件成本相对较低。

可控性方面:自建集群可以根据业务需求进行深度定制,云服务的可定制性相对有限。

数据安全方面:对于一些对数据安全要求极高的企业,自建集群可以避免数据经过第三方。

当然,云服务也有明显的优势,比如免运维、高可用保障、弹性扩展等。具体选择哪种方案,需要根据企业的实际情况来决定。

未来发展和新技术

虽然LVS已经是个"老古董"了,但它的核心理念到现在还是很先进的。随着技术的发展,也出现了一些新的负载均衡技术。

DPDK:基于用户空间的高性能数据包处理框架,能够实现更高的性能。

XDP:Linux内核的新特性,可以在网卡驱动层进行数据包处理,性能比传统的netfilter更好。

eBPF:可编程的内核技术,为负载均衡提供了更多的可能性。

不过对于大部分企业来说,LVS的性能已经完全够用了。而且这些新技术的学习成本比较高,维护难度也更大。

运维自动化

手工维护LVS集群是很累的,特别是当集群规模比较大的时候。我现在都会用一些自动化工具来简化运维工作。

Ansible自动化部署

我写了一个Ansible playbook来自动化部署LVS集群:

---
- hosts: lvs_servers
  tasks:
    - name: Install packages
      yum:
        name: "{{ item }}"
        state: present
      with_items:
        - ipvsadm
        - keepalived
    
    - name: Configure keepalived
      template:
        src: keepalived.conf.j2
        dest: /etc/keepalived/keepalived.conf
      notify: restart keepalived
    
    - name: Start and enable keepalived
      service:
        name: keepalived
        state: started
        enabled: yes

监控告警

我用Zabbix来监控LVS集群的状态,配置了以下监控项:

  • keepalived进程状态
  • VIP绑定状态
  • LVS连接数统计
  • 后端服务器健康状态
  • 系统资源使用情况

当出现异常时,会自动发送邮件和短信告警。

配置管理

为了避免配置漂移,我把所有的配置文件都放在Git仓库中管理。每次修改配置都要经过代码审查,然后通过CI/CD流水线自动部署到生产环境。

这样做的好处是配置变更有记录,出问题时可以快速回滚。

总结和思考

回顾之前使用LVS+Keepalived的经历,总的来说还是很满意的。虽然配置相对复杂一些,但稳定性和性能都很不错。

特别是在一些对性能要求极高的场景中,LVS的优势非常明显。当然,技术选型没有银弹,适合的才是最好的。如果你的业务规模不大,用Nginx可能更合适;如果预算充足,云负载均衡也是不错的选择。但如果你面临高并发、大流量的挑战,又希望有更多的控制权,LVS+Keepalived绝对值得考虑。

最后想说的是,运维这个工作就是这样,没有一劳永逸的解决方案。技术在不断发展,业务需求也在不断变化,我们需要保持学习的心态,不断提升自己的技能。

LVS虽然不是最新的技术,但它经受了时间的考验,在很多大型互联网公司都有应用。掌握LVS的配置和优化,对于运维工程师来说还是很有价值的。

希望我的这些经验能对大家有所帮助。运维路上,我们一起加油!


好了,今天关于LVS+Keepalived的分享就到这里。这套方案我看人在生产环境中用了好几年,踩过不少坑,也积累了一些经验。如果你正在考虑搭建高可用的负载均衡集群,希望这篇文章能给你一些参考。

当然,技术这东西日新月异,我分享的可能不是最新最炫的方案,但绝对是经过实战检验的可靠方案。在选择技术方案的时候,稳定性往往比新颖性更重要。

如果你在实施过程中遇到问题,欢迎留言讨论。运维这条路上,大家互相帮助,共同进步。记得关注@运维躬行录,领取学习资料。我会持续分享更多实用的运维技术和经验!

标签: none