Keepalived LVSDR MariaDB 主主业务场景与数据库核心诉求在企业级应用中数据库作为业务数据的 “核心载体”其高可用性、读写性能、数据一致性直接决定业 务能否稳定运行。无论是电商交易系统订单生成、库存扣减、金融支付平台交易对账、资金流 转还是政务管理系统数据上报、业务审批均对数据库提出以下刚性需求无间断服务高可用数据库需实现 24×7 小时不间断运行避免因单点故障如数据库服务器宕机、磁盘损坏、网络中 断导致业务中断。例如电商平台秒杀活动中若数据库不可用将直接导致订单无法生成每 中断 1 分钟可能造成数万元营收损失金融系统中数据库故障可能引发交易对账异常甚至触发 合规风险。高并发承载读写性能随着用户规模增长数据库面临的读写请求呈指数级上升如日均 SQL 执行量从 100 万次增至 1 亿次。单台数据库服务器的 CPU、内存、IO 能力易成为瓶颈读请求过多会导致查询延迟如用 户查询订单列表超时写请求集中会造成事务阻塞如多用户同时提交订单导致库存更新排 队。数据零丢失可靠性业务数据需具备 “抗丢失” 能力即使遭遇硬件故障或软件异常也需保证数据不损坏、不丢失。例 如用户充值记录、订单信息若因数据库故障丢失将直接引发用户投诉与信任危机同时多节 点间的数据需实时同步避免出现 “主库数据已更新从库仍展示旧数据” 的一致性问题。灵活扩展可扩展性业务增长过程中需支持 “按需扩展” 数据库能力读压力增大时可快速新增读节点写压力上升时 可优化写分发策略避免因架构僵化导致 “业务倒逼重构” 的被动局面。传统数据库架构的痛点与局限在采用《Keepalived LVSDR MariaDB 主主》方案前多数企业曾使用 “单节点数据库” 或 “简单 主从架构”但面临以下难以突破的瓶颈单节点数据库单点故障风险致命问题核心数据库仅部署在一台服务器上一旦服务器硬件故障如电源损坏、磁盘坏道或 软件崩溃如 MariaDB 进程异常退出将导致全量业务中断。恢复效率低依赖人工干预恢复如更换服务器、重建数据库、恢复备份平均恢复时间 MTTR通常超过 30 分钟远无法满足 “秒级切换” 的业务需求若备份数据不完整还可 能导致部分业务数据永久丢失。简单主从架构一主一从读写瓶颈与切换缺陷读性能局限虽然通过 “主库写、从库读” 分摊读压力但从库仅能扩展读能力无法缓解主库 的写压力如大量订单写入仍集中在主库且从库数量增多时缺乏统一的读请求分发机 制易导致部分从库过载如某台从库承担 80% 读请求、部分从库空闲。高可用缺陷主库故障时需手动将从库提升为新主库再修改业务系统的数据库连接地址 切换过程耗时且易出错如忘记同步从库未应用的 binlog 导致数据不一致同时从库仅 作为 “备用节点”写请求始终依赖主库主库写瓶颈无法突破无负载均衡请求分发混乱部分企业尝试用 “业务层硬编码连接地址” 实现读写分离如读请求连从库 IP写请求连主库 IP 但存在两大问题① 缺乏故障检测机制若某台从库宕机业务层无法实时感知仍会将读请求分发至故障节点导 致部分读业务失败② 扩展性差新增读节点时需修改业务代码中的连接地址列表重启服务才能生效不符合 “无 感知扩展” 的运维需求。**数据同步与一致性风险: **传统主从架构依赖 MariaDB 原生的 binlog 同步若网络延迟或主库 binlog 丢失会导致从库数据 滞后或同步失败且主库故障时若从库未完全同步主库数据强制切换会造成 “数据断层”如主 库已提交的订单从库未记录技术方案的选型逻辑针对上述痛点需构建一套 “高可用负载均衡 双主互备 读写协同” 的数据库架构而《Keepalived LVSDR MariaDB 主主》组合正是基于以下核心诉求选型**MariaDB 主主突破写瓶颈与双活备份 **采用 “双主互备” 模式两台 MariaDB 均为主库可同时处理写请求彻底解决传统主从架 构的 “写依赖单主” 问题写性能理论上提升 2 倍两台主库实时同步数据通过 binlog 双向同步任一主库故障时另一主库已拥有完整数 据避免数据丢失同时支持 “读写请求均分发至双主”进一步提升整体并发能力。**LVSDR 模式高效分发读写请求 **LVS 作为四层负载均衡器基于 IP 和端口转发请求具备超高并发承载能力单机可支撑 10 万 并发连接远超 Nginx 等七层负载均衡器采用 DR直接路由模式请求仅经过 LVS 转发至后端 MariaDB 节点响应数据直接从 MariaDB 返回给客户端避免 “请求回程流量” 占用 LVS 带宽转发效率接近物理机直连支持 “健康检查”实时检测 MariaDB 节点状态若某台主库宕机LVS 自动将请求分发至另 一台健康主库避免业务访问故障节点。**Keepalived负载均衡层高可用 **LVS 作为请求分发核心若自身单点故障将导致全量数据库请求无法转发。通过 Keepalived 的 VRRP 协议实现 LVS 主备高可用主 LVS 节点故障时备 LVS 节点可在 1-3 秒内自动接管 虚拟 IPVIP实现 “无感知切换”彻底消除负载均衡层单点风险支持 “优先级配置”可根据 LVS 节点性能设置主备角色确保高性能节点优先承担转发任务。项目价值与预期目标通过部署《Keepalived LVSDR MariaDB 主主》架构预期实现以下技术与业务价值高可用升级数据库层可用性从 99.9% 提升至 99.99%年均故障中断时间从 8.76 小时降至 52.56 分钟核心业务如订单、支付无服务中断风险性能翻倍写性能从单主 500 TPS 提升至双主 1000 TPS读性能支持通过新增从节点无限扩展 LVS 统一分发读请求95% SQL 查询响应时间200ms数据可靠双主实时同步数据任一节点故障无数据丢失LVS 健康检查 Keepalived 主备切换 实现 “故障自动转移”无需人工干预运维高效新增数据库节点时仅需接入 LVS 集群无需修改业务代码负载均衡与数据库节点状 态可通过监控平台实时查看故障定位效率提升 70%。MariaDB 主从复制原理MariaDB 主从复制是指主库将数据变更以日志形式传输给从库从库重放日志实现数据一致。主库 二进制日志binlog主库核心日志记录所有修改数据的 SQL增删改、建表等是主 从同步的 “数据源头”从库 中继日志relay log从库本地日志存储从主库获取的 binlog 内容避免直接通过网络 读取主库 binlog 主库 binlog dump 线程负责向从库传输 binlog从库 IO 线程负责连接主库、拉取 binlog 并写入本地 relay log从库 SQL 线程负责读取 relay log、执行其中的 SQL还原主库数据变更。主从同步完整原理流程步骤 1主库记录数据变更到 binlog当主库执行数据变更操作如INSERT/UPDATE/DELETE 、CREATE TABLE等时操作先写入**事务日志redo log**保证数据持久化事务提交时MySQL 会将该操作的 SQL或数据变更事件按顺序写入 binlog **布骤 2从库 IO 线程连接主库请求同步 binlog **从库启动后IO线程 会主动连接主库并向主库发送两个关键信息要同步的主库 binlog 文件名称要同步的binlog 位置position即从哪个位置开始读取 首次同步时从库会请求主库全量数据的 binlog或先全量备份再同步增量后续仅请求增量 binlog。步骤 3主库 binlog dump 线程传输 binlog 给从库主库接收到从库的同步请求后会创建binlog dump线程 响应该线程根据从库指定的 binlog 文件和位置读取主库 binlog 中的增量数据将读取到的 binlog 内容事件通过网络传输给从库的 IO 线程主库会记录 “哪些从库正在同步哪个 binlog 位置”确保从库断线重连后能续传。**步骤 4从库 IO 线程写入 relay log **从库 IO 线程接收到主库传输的 binlog 内容后不会直接执行而是先写入本地的relay log中继日志避免网络中断导致数据丢失同时更新从库状态文件master.info/relay-log.info记录已同步的主库 binlog 文件 位置本地 relay log 的文件 位置确保从库重启后能继续同步不重复 / 遗漏数据。**步骤 5从库 SQL 线程重放 relay log实现数据一致 **从库SQL线程 会实时读取 relay log 中的内容按顺序解析 relay log 中的 binlog 事件SQL 或行变更在从库本地执行这些事件对应的操作还原主库的数据变更执行完成后更新relay-log.info标记已处理的 relay log 位置避免重复执行。主主复制只需要把主节点当做从节点、从节点当做主节点再做一遍项目实践项目环境主机名IP 地址网关DNSVIP地址服务器角色client2.laogao.cloud10.1.1.21(vmnet1)10.1.1.20223.5.5.5无客户端client1.laogao.cloud10.1.8.21(vmnet8)10.1.8.20223.5.5.5无客户端router.laogao.cloud10.1.8.20(vmnet8) 10.1.1.20(vmnet1)10.1.8.2 无网关223.5.5.5 无DNS无路由器ha1.laogao.cloud10.1.8.13(vmnet8)10.1.8.20223.5.5.510.1.8.100LVSkeepalived 服务器ha2.laogao.cloud10.1.8.14(vmnet8)10.1.8.20223.5.5.510.1.8.100LVSkeepalived 服务器db1.laogao.cloud10.1.8.11(vmnet8)10.1.8.20223.5.5.510.1.8.100db服务器db2.laogao.cloud10.1.8.12(vmnet8)10.1.8.20223.5.5.510.1.8.100db服务器基础配置主机名、IP 地址、网关# client2:[rootcentos7 ~14:44:04]# hostnamectl set-hostname client2.ljw.cloud[rootcentos7 ~14:44:29]# bash[rootclient2 ~14:44:31]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.1.21/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootclient2 ~14:45:38]# nmcli connection up ens33# client1:[rootcentos7 ~14:39:23]# hostnamectl set-hostname client1.ljw.cloud[rootcentos7 ~14:40:11]# bash[rootclient1 ~14:40:24]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.21/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootclient1 ~14:41:37]# nmcli connection up ens33# router:[rootcentos7 ~14:45:56]# hostnamectl set-hostname router.ljw.cloud[rootcentos7 ~14:46:10]# bash[rootrouter ~14:46:12]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.20/24 ipv4.gateway 10.1.8.2 ipv4.dns 223.5.5.5 autoconnect yes[rootrouter ~14:47:21]# nmcli connection up ens33[rootrouter ~14:47:35]# nmcli connection add type ethernet con-name ens35 ifname ens35 ipv4.method manual ipv4.addresses 10.1.1.20/24 autoconnect yes[rootrouter ~14:48:37]# nmcli connection up ens35# ha1:[rootcentos7 ~14:49:00]# hostnamectl set-hostname ha1.ljw.cloud[rootcentos7 ~14:49:17]# bash[rootha1 ~14:49:19]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.13/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootha1 ~14:50:10]# nmcli connection up ens33# ha2:[rootcentos7 ~14:50:29]# hostnamectl set-hostname ha2.ljw.cloud[rootcentos7 ~14:50:48]# bash[rootha2 ~14:50:50]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.14/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootha2 ~14:51:41]# nmcli connection up ens33# db1:[rootcentos7 ~14:51:57]# hostnamectl set-hostname db1.ljw.cloud[rootcentos7 ~14:52:07]# bash[rootdb1 ~14:52:10]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.11/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootdb1 ~14:52:54]# nmcli connection up ens33# db2:[rootcentos7 ~14:53:54]# hostnamectl set-hostname db2.ljw.cloud[rootcentos7 ~14:54:09]# bash[rootdb2 ~14:54:11]# nmcli connection modify ens33 ipv4.method manual ipv4.addresses 10.1.8.12/24 ipv4.gateway 10.1.8.20 ipv4.dns 223.5.5.5 autoconnect yes[rootdb2 ~14:54:48]# nmcli connection up ens33配置 router# 开启路由[rootrouter ~14:58:55]# echo net.ipv4.ip_forward1 /etc/sysctl.conf# 或者sed -i s/ip_forward0/ip_forward1/g /etc/sysctl.conf[rootrouter ~]# sysctl -p[rootrouter ~15:23:21]# systemctl enable firewalld --now[rootrouter ~15:27:10]# firewall-cmd --set-defult-zonetrustedsuccess[rootrouter ~15:27:36]# firewall-cmd --add-masqueradesuccess[rootrouter ~15:27:52]# firewall-cmd --add-masquerade --permanentsuccessMariaDB 安装和初始化配置 db1# 安装软件包[rootdb1 ~15:00:16]# yum install -y mariadb-server# 开启二进制日志[rootdb1 ~15:43:45]# vim /etc/my.cnf.d/server.cnf[mysqld]# 在mysqld块最后添加如下内容server-id1log_binmysql-binrelay_logmysql-relay-bin# 启用并启动服务[rootdb1 ~15:44:20]# systemctl enable mariadb --now# 安全初始化[rootdb1 ~15:44:25]# mysql_secure_installationNOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE!PLEASE READ EACH STEP CAREFULLY!In order to log into MariaDB to secure it, well need the current password for the root user. If youve just installed MariaDB, and you havent set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] y New password: Re-enter new password: Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from localhost. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MariaDB comes with a database named test that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up... All done! If youve completed all of the above steps, your MariaDB installation should now be secure. Thanksforusing MariaDB!配置 db2# 安装软件包[rootdb2 ~15:00:35]# yum install -y mariadb-server# 开启二进制日志[rootdb2 ~15:49:34]# vim /etc/my.cnf.d/server.cnf# 在mysqld块最后添加如下内容server-id2log_binmysql-binrelay_logmysql-relay-bin# 启用并启动服务[rootdb2 ~15:49:53]# systemctl enable mariadb --now# 安全初始化[rootdb2 ~15:50:09]# mysql_secure_installationMariaDB 主从db2-db1主库db1从库db2# 配置主数据库MariaDB[(none)]grant replication slave, replication client on *.* torepl10.1.8.12identified by123;Query OK,0rows affected(0.00sec)MariaDB[(none)]flush privileges;Query OK,0rows affected(0.00sec)MariaDB[(none)]show master status\G;***************************1. row *************************** File: mysql-bin.000003 Position:1722Binlog_Do_DB: Binlog_Ignore_DB:1rowinset(0.00sec)ERROR: No query specified# 配置从数据库MariaDB[(none)]change master tomaster_host10.1.8.11, -master_userrepl, -master_password123, -master_port3306, -master_log_filemysql-bin.000003, -master_log_pos1722, -master_connect_retry30;Query OK,0rows affected(0.00sec)MariaDB[(none)]show slave status\G;***************************1. row *************************** Slave_IO_State: Master_Host:10.1.8.11 Master_User: repl Master_Port:3306Connect_Retry:30Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos:1722Relay_Log_File: mysql-relay-bin.000001 Relay_Log_Pos:4Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: No Slave_SQL_Running: No......1rowinset(0.00sec)ERROR: No query specified# 启动同步再次查看状态MariaDB[(none)]start slave;Query OK,0rows affected(0.00sec)MariaDB[(none)]show slave status\G ***************************1. row *************************** Slave_IO_State: Waitingformaster to send event Master_Host:10.1.8.11 Master_User: repl Master_Port:3306Connect_Retry:30Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos:1722Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos:529Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes........# 确保 Slave_IO_Running 和 Slave_SQL_Running 状态为yesMariaDB 主从db1-db2主库db2从库db1# 配置主数据库MariaDB[(none)]grant replication slave, replication client on *.* torepl10.1.8.11identified by123;Query OK,0rows affected(0.00sec)MariaDB[(none)]show master status\G;***************************1. row *************************** File: mysql-bin.000003 Position:1647Binlog_Do_DB: Binlog_Ignore_DB:1rowinset(0.00sec)ERROR: No query specified# 配置从数据库MariaDB[(none)]change master tomaster_host10.1.8.12, -master_userrepl, -master_password123, -master_port3306, -master_log_filemysql-bin.000003, -master_log_pos1647, -master_connect_retry30;Query OK,0rows affected(0.01sec)MariaDB[(none)]show slave status\G;***************************1. row *************************** Slave_IO_State: Waitingformaster to send event Master_Host:10.1.8.12 Master_User: repl Master_Port:3306Connect_Retry:30Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos:1647Relay_Log_File: mysql-relay-bin.000002 Relay_Log_Pos:529Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: Yes Slave_SQL_Running: Yes配置 LVS-RS所有后端主机都要做相同配置。# 增加虚拟网卡[rootdb1 ~16:13:27]# nmcli connection add type dummy ifname dummy con-name dummy ipv4.method manual ipv4.addresses 10.1.8.100/32[rootdb1 ~16:14:20]# nmcli connection up dummy# 配置arp参数关闭arp对dummy网卡的解析cat/etc/sysctl.confEOF 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[rootdb1 ~16:16:39]# sysctl -pnet.ipv4.conf.all.arp_ignore1net.ipv4.conf.all.arp_announce2net.ipv4.conf.dummy.arp_ignore1net.ipv4.conf.dummy.arp_announce2配置 keepalived 和 LVS-DS配置 ha1[rootha1 ~14:59:17]# yum install -y keepalived ipvsadm[rootha1 ~16:19:55]# cp /etc/keepalived/keepalived.conf{,.bak}[rootha1 ~16:20:21]# vim /etc/keepalived/keepalived.conf!Configuration Fileforkeepalived global_defs{router_id ha1}vrrp_instance db{state MASTER interface eth33 virtual_router_id51priority110advert_int1authentication{auth_type PASS auth_pass1111}virtual_ipaddress{10.1.8.100/24}}virtual_server10.1.8.1003306{delay_loop6lb_algo rr lb_kind DR persistence_timeout50protocol TCP real_server10.1.8.113306{weight1TCP_CHECK{connect_timeout3retry3delay_before_retry3}}real_server10.1.8.123306{weight1TCP_CHECK{connect_timeout3retry3delay_before_retry3}}}[rootha1 ~16:26:00]# systemctl enable keepalived --now在keepalivedLVS配置中后端 real_server 后端服务器不支持直接使用域名必须指定 IP 地 址。这是由 LVS 的工作原理和 Keepalived 的配置机制决定的。原因LVS 工作在四层传输层LVS 基于 IP 地址和端口进行负载均衡转发不涉及 DNS 解析 无法识别域名。** Keepalived 配置特性**Keepalived 的 real_server 配置项要求明确的 IP 地址 address 参数其语法解析器不支持域名格式会直接将域名视为无效配置。启动验证失败若强行在 real_server 中填写域名Keepalived 启动时会报错如 invalid IP address导致配置加载失败。替代方案通过脚本动态更新配置配置 ha2[rootha2 ~14:59:39]# yum install -y keepalived ipvsadm[rootha2 ~16:28:27]# cp /etc/keepalived/keepalived.conf{,.bak}# 将db1修改过的文件复制过来进行修改[rootha2 ~16:31:06]# scp 10.1.8.13:/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf!Configuration Fileforkeepalived global_defs{router_id ha2}vrrp_instance db{state BACKUP interface eth33 virtual_router_id51priority100advert_int1authentication{auth_type PASS auth_pass1111}virtual_ipaddress{10.1.8.100/24}}virtual_server10.1.8.1003306{delay_loop6lb_algo rr lb_kind DR protocol TCP real_server10.1.8.113306{weight1TCP_CHECK{connect_timeout3retry3delay_before_retry3}}real_server10.1.8.123306{weight2TCP_CHECK{connect_timeout3retry3delay_before_retry3}}}[rootha2 ~16:33:54]# systemctl enable keepalived --now测试# 创建测试账户[rootdb1 ~16:17:11]# mysql -uroot -p123MariaDB[(none)]grant all privileges on *.* toljw%identified by123;Query OK,0rows affected(0.00sec)MariaDB[(none)]flush privileges;Query OK,0rows affected(0.00sec)MariaDB[(none)]quit Bye[rootclient1 ~14:56:07]# yum install -y mysql[rootclient1 ~16:52:13]# mysql -uljw -p123 -h 10.1.8.100# 停止ha1上Keepalived服务测试mysql连接[rootha1 ~]# systemctl stop keepalived.service# 启动ha1上Keepalived服务测试mysql连接[rootha1 ~]# systemctl start keepalived.service# 停止db1上mariadb服务测试mysql连接[rootdb1 ~]# systemctl stop mariadb