企业级高可用实战:Keepalived + LVS(DR)+ MariaDB 主主架构深度解析
引言
在企业级应用中,数据库作为业务数据的"核心载体",其高可用性、读写性能和数据一致性直接决定业务能否稳定运行。无论是电商交易系统(订单生成、库存扣减)、金融支付平台(交易对账、资金流转),还是政务管理系统(数据上报、业务审批),**"数据库一旦宕机,业务就瘫痪"**已成为不可触碰的红线。传统的单节点或简单主从架构,已经无法满足现代互联网高并发、高可用的刚性需求。本文将基于实际操作,详细拆解通过 Keepalived(VIP 漂移) + LVS(DR 模式流量分发) + MariaDB 主主复制(双活写) 构建的稳固企业级架构。
第一部分:项目背景与架构选型逻辑
1. 业务场景与数据库核心诉求
在业务演进过程中,数据库会面临以下四大类刚性需求:
- 无间断服务(高可用) :数据库需实现7×24小时不间断运行,避免因单点故障(如数据库服务器宕机、磁盘损坏、网络中断)导致业务中断。例如:电商平台秒杀活动中,若数据库不可用,将直接导致订单无法生成,每中断1分钟可能造成数万元营收损失;金融系统中,数据库故障可能引发交易对账异常,甚至触发合规风险。
- 高并发承载(读写性能):随着用户规模增长,数据库面临的读写请求呈指数级上升(如日均SQL执行量从100万次增至1亿次)。单台数据库的CPU、内存、IO能力易成为瓶颈:读请求过多会导致查询延迟(如用户查询订单列表超时),写请求集中会造成事务阻塞(如多用户同时提交订单导致库存更新排队)。
- 数据零丢失(可靠性):业务数据需具备"抗丢失"能力,即使遭遇硬件故障或软件异常,也需保证数据不损坏、不丢失。例如:用户充值记录、订单信息若因数据库故障丢失,将直接引发用户投诉与信任危机;同时,多节点间的数据需实时同步,避免出现"主库数据已更新,从库仍展示旧数据"的一致性问题。
- 灵活扩展(可扩展性):业务增长过程中,需支持"按需扩展"数据库能力:读压力增大时可快速新增读节点,写压力上升时可优化写分发策略,避免因架构僵化导致"业务倒逼重构"的被动局面。
2. 传统数据库架构的致命痛点与局限
在采用本方案前,多数企业曾使用"单节点数据库"或"简单主从架构",但面临以下难以突破的瓶颈:
① 单节点数据库:单点故障风险致命
- 风险:数据库仅部署在一台服务器上,一旦硬件故障(如电源损坏、磁盘坏道)或软件崩溃(如MariaDB进程异常退出),将导致全量业务中断。
- 恢复效率极低:依赖人工干预恢复(如更换服务器、重建数据库、恢复备份),平均恢复时间(MTTR)通常超过30分钟,远无法满足"秒级切换"的业务需求;若备份数据不完整,还可能导致部分业务数据永久丢失。
② 简单主从架构(一主一从):读写瓶颈与切换缺陷
- 读性能局限 :虽然通过"主库写、从库读"分摊读压力,但从库仅能扩展读能力,无法缓解主库的写压力(如大量订单写入仍集中在主库);且从库数量增多时,缺乏统一的读请求分发机制,易导致部分从库过载(如某台从库承担80%读请求)、部分从库空闲。
- 高可用缺陷:主库故障时,需手动将从库提升为新主库,再修改业务系统的数据库连接地址,切换过程耗时且易出错(如忘记同步从库未应用的binlog导致数据不一致);同时,从库仅作为"备用节点",写请求始终依赖主库,主库写瓶颈无法突破。
③ 无负载均衡:请求分发混乱
- 硬编码问题:部分企业尝试用"业务层硬编码连接地址"实现读写分离(如读请求连从库IP,写请求连主库IP),但存在两大问题:一、缺乏故障检测机制,若某台从库宕机,业务层无法实时感知,仍会将读请求分发至故障节点,导致部分读业务失败;二、扩展性差,新增读节点时,需修改业务代码中的连接地址列表,重启服务才能生效,不符合"无感知扩展"的运维需求。
④ 数据同步与一致性风险
- 数据断层:传统主从架构依赖MariaDB原生的binlog同步,若网络延迟或主库binlog丢失,会导致从库数据滞后或同步失败;且主库故障时,若从库未完全同步主库数据,强制切换会造成"数据断层"(如主库已提交的订单,从库未记录),引发严重商业事故。
3. 技术方案的选型逻辑
针对上述痛点,需构建一套"高可用负载均衡 + 双主互备 + 读写协同"的数据库架构。我们最终选型 《Keepalived + LVS(DR) + MariaDB主主》 组合,正是基于以下核心诉求:
- 为什么选择 MariaDB 主主(突破写瓶颈与双活备份) :
采用"双主互备"模式(两台MariaDB均为主库,可同时处理写请求),彻底解决传统主从架构的"写依赖单主"问题,写性能理论上提升2倍;两台主库实时同步数据(通过binlog双向同步),任一主库故障时,另一主库已拥有完整数据,避免数据丢失;同时,支持"读写请求均分发至双主",进一步提升整体并发能力。 - 为什么选择 LVS(DR模式)(高效分发读写请求) :
LVS作为四层负载均衡器,基于IP和端口转发请求,具备超高并发承载能力(单机可支撑10万+并发连接) ,远超Nginx等七层负载均衡器;采用DR(直接路由)模式,请求仅经过LVS转发至后端MariaDB节点,响应数据直接从MariaDB返回给客户端,避免"请求回程流量"占用LVS带宽,转发效率接近物理机直连;支持"健康检查",实时检测MariaDB节点状态,若某台主库宕机,LVS自动将请求分发至另一台健康主库,避免业务访问故障节点。 - 为什么选择 Keepalived(负载均衡层高可用) :
LVS作为请求分发核心,若自身单点故障,将导致全量数据库请求无法转发。通过Keepalived的VRRP协议实现LVS主备高可用:主LVS节点故障时,备LVS节点可在1-3秒内自动接管虚拟IP(VIP),实现"无感知切换",彻底消除负载均衡层单点风险;支持"优先级配置",可根据LVS节点性能设置主备角色,确保高性能节点优先承担转发任务。
4. 项目预期价值与目标
通过部署本架构,预期实现以下技术与业务价值:
- 高可用升级 :数据库层可用性从 99.9% 提升至 99.99% ,年均故障中断时间从8.76小时降至 52.56分钟,核心业务(如订单、支付)无服务中断风险。
- 性能翻倍 :写性能从单主 500TPS 提升至双主 1000+ TPS,读性能支持通过新增从节点无限扩展(LVS统一分发读请求),95% SQL查询响应时间 < 200ms。
- 数据可靠:双主实时同步数据,任一节点故障无数据丢失;LVS健康检查 + Keepalived主备切换,实现"故障自动转移",无需人工干预。
- 运维高效 :新增数据库节点时,仅需接入LVS集群,无需修改业务代码;负载均衡与数据库节点状态可通过监控平台实时查看,故障定位效率提升 70%。
第二部分:项目环境与节点规划
1. 实验拓扑概述
本实验基于 VMware 虚拟化环境,划分了 10.1.8.0/24(业务网)和 10.1.1.0/24(外部网)两个网段。由 router 负责开启路由转发和 NAT,连接外部客户端与内部业务集群;ha1 和 ha2 组成 LVS/Keepalived 双机热备层;db1 和 db2 组成 MariaDB 数据层。
2. 节点规划表
| 主机名 | IP 地址 | 网关 | DNS | VIP 地址 | 服务器角色 |
|---|---|---|---|---|---|
| client1 | 10.1.8.21 (vmnet8) | 10.1.8.20 | 223.5.5.5 | 无 | 客户端 |
| client2 | 10.1.1.21 (vmnet1) | 10.1.1.20 | 223.5.5.5 | 无 | 客户端 |
| router | 10.1.8.20 / 10.1.1.20 | 10.1.8.2 | 223.5.5.5 | 无 | 路由器(开启转发与NAT) |
| ha1 | 10.1.8.13 (vmnet8) | 10.1.8.20 | 223.5.5.5 | 10.1.8.100 | LVS+Keepalived 主服务器 |
| ha2 | 10.1.8.14 (vmnet8) | 10.1.8.20 | 223.5.5.5 | 10.1.8.100 | LVS+Keepalived 备服务器 |
| db1 | 10.1.8.11 (vmnet8) | 10.1.8.20 | 223.5.5.5 | 10.1.8.100 | DB 主服务器 |
| db2 | 10.1.8.12 (vmnet8) | 10.1.8.20 | 223.5.5.5 | 10.1.8.100 | DB 从服务器 |
3. 基础环境准备
所有节点均使用 CentOS 7 模板机,需先配置好主机名、网卡 IP 和网关。特别注意: 路由器 router 需要开启系统内核 IP 转发功能,并关闭防火墙限制。
bash
# 在 router 上开启路由转发
[root@router ~ 19:29:32]# vim /etc/sysctl.conf
net.ipv4.ip_forward=1
[root@router ~ 19:30:30]# sysctl -p
net.ipv4.ip_forward = 1
第三部分:后续实操内容框架
步骤一:MariaDB 安装与双主(主主)复制配置
1. 安装与安全初始化
分别在 db1 和 db2 上安装 mariadb-server,并开启二进制日志。
bash
[root@db1 ~ 19:32:56]# yum install -y mariadb-server
[root@db2 ~ 19:32:56]# yum install -y mariadb-server
# 开启二进制日志和 relay log
[root@db1 ~ 19:35:56]# vim /etc/my.cnf.d/server.cnf
[mysqld]
server-id=1 # db2 上修改为 2
log_bin=mysql-bin
relay_log=mysql-relay-bin
# 启动服务并运行安全初始化脚本
[root@db1 ~ 19:36:49]# systemctl enable mariadb.service --now
[root@db1 ~ 19:36:55]# mysql_secure_installation
2. 配置 db2 -> db1 复制
登录 db1 创建复制用户并查看位点,然后到 db2 配置 CHANGE MASTER。
sql
-- 在 db1 执行
MariaDB [(none)]> grant replication slave, replication client on *.* to 'repl'@'10.1.8.12' identified by 'huawei';
MariaDB [(none)]> show master status\G;
*************************** 1. row ***************************
File: mysql-bin.000003
Position: 1650
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)
-- 记下 File 和 Position
-- 在 db2 执行
MariaDB [(none)]> change master to master_host='10.1.8.11', master_user='repl', master_password='huawei', master_port=3306, master_log_file='mysql-bin.000003', master_log_pos=1650, master_connect_retry=30;
MariaDB [(none)]> start slave;
MariaDB [(none)]> show slave status\G;
-- 确保 Slave_IO_Running: Yes 和 Slave_SQL_Running: Yes
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.1.8.11
Master_User: repl
Master_Port: 3306
Connect_Retry: 30
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 1650
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 529
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 1650
Relay_Log_Space: 823
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
3. 配置 db1 -> db2 复制(主主反向)
反向操作一遍,将 db2 作为主库,db1 作为从库。
bash
# 在 db2 上创建 repl 用户(授权给 10.1.8.11)
# 在 db1 上执行 CHANGE MASTER TO MASTER_HOST='10.1.8.12'...
验证数据同步:在主库建库建表插入数据,在从库查询,确认已自动同步。

步骤二:配置 LVS-RS(真实后端服务器)
最关键的一步! 在 DR 模式下,所有的 Real Server(db1 和 db2)都必须在 lo 接口上绑定 VIP,并抑制 ARP 响应,防止路由器把 VIP 的 MAC 错误映射到 RS 上。
bash
# 增加虚拟网卡(绑定 VIP 到 lo)
[root@db1 ~ 19:46:36]# nmcli connection add type dummy ifname dummy con-name dummy ipv4.method manual ipv4.addresses 10.1.8.100/32
[root@db1 ~ 19:46:42]# nmcli connection up dummy
# 配置 ARP 参数,抑制响应
[root@db1 ~ 19:46:48]# cat >> /etc/sysctl.conf << EOF
> net.ipv4.conf.all.arp_ignore = 1
> net.ipv4.conf.all.arp_announce = 2
> net.ipv4.conf.dummy.arp_ignore = 1
> net.ipv4.conf.dummy.arp_announce = 2
> EOF
[root@db1 ~ 19:47:28]# sysctl -p
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.dummy.arp_ignore = 1
net.ipv4.conf.dummy.arp_announce = 2
# db2操作相同
(db2 也需执行相同配置。)
步骤三:配置 Keepalived 和 LVS-DS(调度器)
在 ha1 和 ha2 上安装 keepalived 和 ipvsadm。
1. 配置 ha1(Master 节点)
bash
[root@ha1 ~ 19:27:10]# yum install -y keepalived ipvsadm
[root@ha1 ~ 19:49:21]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id ha1
}
vrrp_instance db {
state MASTER
interface ens33
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.1.8.100/24
}
}
virtual_server 10.1.8.100 3306 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 50
protocol TCP
real_server 10.1.8.11 3306 {
weight 1
TCP_CHECK {
connect_timeout 3
retry 3
delay_before_retry 3
}
}
real_server 10.1.8.12 3306 {
weight 1
TCP_CHECK {
connect_timeout 3
retry 3
delay_before_retry 3
}
}
}
2. 配置 ha2(Backup 节点)
复制 ha1 的配置,仅修改 router_id 为 ha2,将 state MASTER 改为 state BACKUP,priority 110 改为 priority 100。
3. 启动与验证
bash
# 分别在 ha1 和 ha2 上执行
[root@ha1 ~ 19:52:00]# systemctl enable keepalived.service --now
# 查看 VIP 是否正确绑定
[root@ha1 ~ 19:52:12]# ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
ens33 UP 10.1.8.13/24 10.1.8.100/24 fe80::baf4:a2c5:6e5c:ea60/64 fe80::6f9c:c7bf:36f9:e430/64
[root@ha2 ~ 19:52:12]# ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
ens33 UP 10.1.8.14/24 fe80::baf4:a2c5:6e5c:ea60/64 fe80::6f9c:c7bf:36f9:e430/64 fe80::878c:d585:6df9:4cf3/64
# 查看 LVS 规则是否生效
[root@ha1 ~]# ipvsadm -Ln
[root@ha1 ~ 19:52:29]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.1.8.100:3306 rr persistent 50
-> 10.1.8.11:3306 Route 1 0 0
-> 10.1.8.12:3306 Route 1 0 0
[root@ha2 ~ 19:52:29]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.1.8.100:3306 rr persistent 50
-> 10.1.8.11:3306 Route 1 0 0
-> 10.1.8.12:3306 Route 1 0 0
步骤四:高可用与负载均衡验证
- 基础连通性测试 :在客户端
client1上使用mysql -ulaogao -phuawei -h 10.1.8.100连接数据库,验证轮询调度。 - LVS 单点故障切换测试 :在
ha1上执行systemctl stop keepalived,再次在客户端连接 VIP,应能自动切换到ha2并保持数据库连接不断。 - DB 节点故障自动摘除测试 :停止
db1上的 MariaDB 服务。LVS 健康检查会将db1剔除集群,后续客户端请求全部自动转发至db2,业务无感知,数据零丢失。
第四部分:排错与避坑指南(总结)
- 防火墙与 SELinux :实验环境务必在 LVS 和 RS 上先执行
systemctl stop firewalld和setenforce 0,否则健康检查不通过,后端会被踢出。 - ARP 抑制 :DR 模式下的 Real Server 忘记配置
arp_ignore=1会导致 VIP 冲突,出现请求转发不过去或者网络不通的现象。 - 端口匹配 :
virtual_server的端口必须和真实后端数据库监听的3306端口完全一致。(如果你后期的实验在 80 端口跑 Nginx 反向代理,就需要专门配一个virtual_server 10.1.8.100 80块!)