生产环境血泪史:LVS+Keepalived高可用负载均衡从入门到跑路
今天跟大家分享一下用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服务器集群)
这个架构的好处是简单清晰,用户访问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的分享就到这里。这套方案我看人在生产环境中用了好几年,踩过不少坑,也积累了一些经验。如果你正在考虑搭建高可用的负载均衡集群,希望这篇文章能给你一些参考。
当然,技术这东西日新月异,我分享的可能不是最新最炫的方案,但绝对是经过实战检验的可靠方案。在选择技术方案的时候,稳定性往往比新颖性更重要。
如果你在实施过程中遇到问题,欢迎留言讨论。运维这条路上,大家互相帮助,共同进步。记得关注@运维躬行录,领取学习资料。我会持续分享更多实用的运维技术和经验!