ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL高可用集群实战:基于GTID复制与HAProxy+Keepalived的MNA架构

MySQL高可用集群实战:基于GTID复制与HAProxy+Keepalived的MNA架构 1. 项目概述为什么我们需要MNA集群在数据库运维的日常里高可用性High Availability, HA和读写分离是绕不开的两个核心命题。单点数据库的风险太高一旦宕机业务就可能直接停摆而将所有读写压力都集中在一台机器上性能瓶颈又显而易见。MySQL作为最流行的开源关系型数据库其高可用方案众多从早期的MHAMaster High Availability到官方的InnoDB Cluster再到各大云厂商的托管服务选择很多。但今天我想聊的是一个在特定场景下非常经典、稳定且资源利用率高的方案基于MySQL主从复制与KeepalivedHAProxy构建的MNA集群环境。这里的“MNA”并非一个官方术语而是在很多企业级实践中形成的一种架构代称通常指Master主库 - Node从库节点 - Agent/Proxy代理层的协同工作模式。这个方案的核心思想是不依赖特别复杂的集群管理组件而是用成熟、轻量的开源工具组合出一个具备自动故障转移、读写分离、负载均衡能力的数据库服务层。我选择这个方案进行深度配置实践是因为它在很多中小规模、对成本敏感但又对稳定性有要求的业务场景中表现出了极强的生命力。它避免了引入过于沉重的中间件架构清晰每个组件的职责明确出问题了也容易排查。接下来我会把自己搭建这样一套环境的核心思路、详细步骤、踩过的坑以及调优心得毫无保留地分享出来。无论你是刚开始接触MySQL高可用的DBA新手还是正在为现有架构寻找更优解的技术负责人相信这篇内容都能给你带来直接的参考价值。2. 集群架构设计与核心组件解析在动手敲命令之前我们必须先把架构想清楚。一个健壮的MNA集群不是把几个软件随便装在一起就能工作的每个组件的选型和部署位置都决定了集群的最终表现。2.1 整体架构拓扑我们规划一个最小化的高可用单元包含以下角色1台 Master 节点承担所有写操作和部分实时性要求高的读操作。2台 Slave 节点承担读操作实现读写分离和负载均衡。同时作为Master的备用机为故障切换提供候选。2台 Proxy 节点部署HAProxy提供统一的数据库访问入口实现读请求的负载均衡和健康检查。2台 Keepalived 节点与Proxy节点部署在同一机器上也可以分离通过VRRP协议虚拟出一个VIPVirtual IP。客户端只需连接这个VIP后端Proxy的实际主从切换对客户端透明。这样我们一共需要5台服务器。使用两台ProxyKeepalived是为了避免代理层本身成为单点。整个数据流是这样的应用连接VIP - VIP指向当前主Proxy - HAProxy根据规则将写请求转发给Master读请求负载均衡到两个Slave - 数据库响应。注意这里有一个关键设计取舍。我们没有使用Keepalived直接漂移MySQL的VIP到Master节点而是漂移HAProxy的VIP。这样做的好处是故障转移的粒度更细控制更灵活。例如当某个Slave延迟过大时HAProxy可以自动将其从读池中摘除但这并不影响Master和VIP。只有Master彻底宕机我们才需要触发切换脚本提升一个Slave为新的Master并让HAProxy更新配置。这个逻辑比Keepalived直接检测MySQL要复杂但更精准。2.2 核心组件功能与选型理由MySQL主从复制这是整个架构的数据同步基础。我们选择基于GTID全局事务标识符的复制模式而不是传统的基于二进制日志文件和位置的复制。GTID复制大大简化了故障转移和主从维护的复杂度能自动定位复制位置避免了手动找binlog文件和position的麻烦。这是搭建现代MySQL高可用架构的首选。HAProxy它是一个高性能的TCP/HTTP负载均衡器。我们用它来做数据库的“交通警察”。为什么不用NginxNginx的stream模块虽然也能做TCP负载均衡但其健康检查功能和对后端状态的管理能力相对HAProxy较弱。HAProxy是专业的负载均衡器专为高并发、高可靠的后端服务分发而设计其丰富的监控页面和精细的后端权重、状态管理功能更适合数据库这类关键服务。核心功能对后端MySQL节点进行定期健康检查通过连接并执行SELECT 1将3306端口的写请求定向到Master组将读请求均匀分发到Slave组提供Web管理页面实时查看后端状态。Keepalived它利用VRRP协议解决单点故障问题。工作原理两台机器上运行Keepalived一组一备。它们共同虚拟出一个VIP。主节点会定期发送VRRP通告报文备份节点监听。如果备份节点超过一定时间advert_intpriority差值计算收不到通告就会认为主节点故障随即接管VIP并执行预设的脚本例如重启本机的HAProxy服务以确保其监听VIP。为什么需要它虽然有两台HAProxy但应用需要配置一个固定的连接地址。如果没有VIP我们就得在应用配置里写死两个Proxy的地址并在一个宕机时手动修改配置这不符合高可用的要求。Keepalived实现了代理层的高可用对应用完全透明。3. 基础环境准备与MySQL主从搭建有了清晰的蓝图我们就可以开始准备“建筑材料”了。这一部分是整个集群的基石必须保证稳固。3.1 系统与网络环境初始化假设我们五台服务器的IP分别为Master: 192.168.1.10Slave1: 192.168.1.11Slave2: 192.168.1.12Proxy/Keepalived1: 192.168.1.20Proxy/Keepalived2: 192.168.1.21虚拟VIP: 192.168.1.100所有节点都需要执行的操作主机名与Hosts解析为每台机器设置易于识别的主机名如db-master,db-slave1,proxy-1并在所有节点的/etc/hosts文件中添加所有节点的IP和主机名映射。这是为了避免后续配置中对IP地址的依赖让配置更清晰。防火墙与SELinux开放必要的端口如3306, 9600, 8888等或直接在生产环境评估后暂时关闭。SELinux建议设置为permissive模式以避免权限问题。时间同步集群内所有服务器的时间必须高度一致否则会导致日志时间混乱、健康检查异常等问题。使用chronyd或ntpd服务配置它们从同一时间源同步。安装MySQL使用官方Yum仓库或下载特定版本的RPM包在所有三台数据库节点Master, Slave1, Slave2上安装相同版本的MySQL例如MySQL 8.0。务必保证版本一致小版本号也尽量相同可以避免很多意想不到的复制兼容性问题。3.2 配置MySQL GTID主从复制在Master节点192.168.1.10上操作首先编辑MySQL配置文件/etc/my.cnf在[mysqld]部分添加关键配置server-id 10 # 每个节点必须唯一这里用IP末段 log-bin mysql-bin # 开启二进制日志 binlog-format ROW # 推荐使用ROW格式数据一致性更好 gtid-mode ON # 开启GTID模式 enforce-gtid-consistency ON # 强制GTID一致性 log-slave-updates ON # 允许从库也写binlog为级联复制或未来该从库升级为主库做准备配置完成后重启MySQL服务。接着登录MySQL创建用于复制的专用账号并授权CREATE USER repl192.168.1.% IDENTIFIED BY StrongPassword123!; GRANT REPLICATION SLAVE ON *.* TO repl192.168.1.%; FLUSH PRIVILEGES;然后查看Master状态记录下必要信息虽然在GTID下不是必须但备份时有用SHOW MASTER STATUS\G在Slave节点192.168.1.11/12上操作同样编辑my.cnfserver-id分别设为11和12其他GTID相关配置与Master相同。重启MySQL服务后登录并配置复制源。这里直接使用GTID自动定位是GTID复制最大的优势CHANGE MASTER TO MASTER_HOST192.168.1.10, MASTER_USERrepl, MASTER_PASSWORDStrongPassword123!, MASTER_AUTO_POSITION 1; # 关键参数设置为1表示使用GTID自动定位 START SLAVE;使用SHOW SLAVE STATUS\G命令检查复制状态。关键要看两个线程的状态Slave_IO_Running: YesSlave_SQL_Running: Yes以及Retrieved_Gtid_Set和Executed_Gtid_Set是否在正常增长。实操心得在配置主从前建议先在Master上做一次全量备份使用mysqldump --single-transaction --master-data2或mysqlpump并在Slave上恢复然后再启动复制。这样可以避免在配置期间Master有数据写入导致Slave需要追很久的日志。对于已有大量数据的Master使用物理备份工具如XtraBackup是更好的选择。4. HAProxy与Keepalived的配置与调优数据库层准备就绪后我们来搭建前端的流量调度与高可用层。这一层的配置直接决定了应用的体验和集群的可靠性。4.1 HAProxy配置详解我们在两台Proxy节点192.168.1.20和192.168.1.21上安装HAProxy。配置是相同的。安装命令以CentOS为例yum install -y haproxy核心配置文件/etc/haproxy/haproxy.cfg的全局和代理层配置如下global log /dev/log local0 info maxconn 4096 # 根据机器内存调整建议(maxconn * 每个连接内存估算) 可用内存 user haproxy group haproxy daemon defaults log global mode tcp # MySQL是TCP协议必须用mode tcp option tcplog option dontlognull retries 3 timeout connect 5000ms timeout client 50000ms # 客户端超时根据长连接需求调整 timeout server 50000ms # 后端服务器超时 # 监控页面配置方便我们查看后端状态 listen stats bind *:8888 # 监控页面访问端口 mode http stats enable stats uri /haproxy-status stats auth admin:YourAdminPassword # 设置查看监控页面的账号密码 # 主库写服务配置 listen mysql-write bind *:9600 # 对外提供写服务的端口应用连接此端口进行写操作 mode tcp balance roundrobin # 写请求通常只发往一个主库这里roundrobin意义不大但可保留 option tcp-check tcp-check connect port 3306 tcp-check send PING\r\n tcp-check expect string PONG server db-master 192.168.1.10:3306 check inter 2000 rise 2 fall 3 # 从库读服务配置 listen mysql-read bind *:9601 # 对外提供读服务的端口应用连接此端口进行读操作 mode tcp balance roundrobin # 读请求负载均衡算法也可用leastconn option tcp-check tcp-check connect port 3306 tcp-check send PING\r\n tcp-check expect string PONG server db-slave1 192.168.1.11:3306 check inter 2000 rise 2 fall 3 weight 1 server db-slave2 192.168.1.12:3306 check inter 2000 rise 2 fall 3 weight 1配置关键点解析mode tcp这是必须的因为MySQL协议运行在TCP层之上。如果错误地配置为mode httpHAProxy将无法正确解析和转发数据包。健康检查tcp-check我们配置了一个简单的TCP层检查连接3306端口并发送一个MySQL Ping命令PING\r\n期待返回PONG。inter定义检查间隔rise定义成功几次标记为UPfall定义失败几次标记为DOWN。这个检查比简单的端口探测更可靠。读写分离通过两个独立的listen块绑定不同端口9600写9601读在应用层实现物理分离。这是最简单清晰的分离方式。更复杂的方式可以用HAProxy的ACL规则根据SQL语句判断但误判风险高不推荐。maxconn这个参数限制了HAProxy能处理的最大并发连接数。需要根据服务器内存估算每个连接约占用1-2KB内存并留有余量。设置过低会导致新连接被拒绝过高可能导致内存耗尽。启动HAProxysystemctl start haproxy; systemctl enable haproxy访问http://192.168.1.20:8888/haproxy-status输入账号密码即可看到后端MySQL节点的状态UP/DOWN、会话数等信息非常直观。4.2 Keepalived配置与脑裂预防Keepalived的配置主备节点略有不同。我们以.20为主.21为备。主节点192.168.1.20配置/etc/keepalived/keepalived.confglobal_defs { router_id proxy-1 # 标识本节点需唯一 } vrrp_script chk_haproxy { script /usr/bin/killall -0 haproxy # 检查haproxy进程是否存在 interval 2 # 检查间隔 weight -5 # 如果检查失败优先级降低5 fall 2 # 连续失败2次才认为失败 rise 1 # 成功1次就认为恢复 } vrrp_instance VI_1 { state MASTER # 初始状态为主 interface eth0 # 绑定VIP的网络接口名根据实际情况修改 virtual_router_id 51 # 虚拟路由ID同一组Keepalived必须相同范围0-255 priority 100 # 初始优先级主节点应高于备节点 advert_int 1 # VRRP通告间隔单位秒 authentication { auth_type PASS auth_pass 1111 # 认证密码主备需一致 } virtual_ipaddress { 192.168.1.100/24 dev eth0 # 定义的虚拟VIP } track_script { chk_haproxy # 调用上面定义的检查脚本 } notify_master /etc/keepalived/notify.sh master # 状态切换时触发的脚本 notify_backup /etc/keepalived/notify.sh backup notify_fault /etc/keepalived/notify.sh fault }备节点192.168.1.21配置只需修改router_id为proxy-2state为BACKUPpriority设置为一个低于100的值如90。其他部分完全相同。关键机制与防脑裂vrrp_script这个脚本定义了如何检查HAProxy的健康状态。killall -0命令不会真正杀死进程只是检查进程是否存在。如果HAProxy崩溃脚本返回非0导致该节点优先级降低weight -5备份节点由于优先级更高会抢占VIP。这实现了代理服务故障的自动转移。脑裂预防脑裂是指两个节点都认为自己是主节点都持有VIP。预防措施包括virtual_router_id一致确保主备在同一个VRRP组内通信。网络质量确保主备节点间网络稳定advert_int设置合理。网络抖动可能导致备份节点收不到通告而抢占VIP。防火墙必须开放VRRP协议通信IP协议号112 组播地址224.0.0.18。脚本仲裁可以在notify_master脚本中加入更严格的判断例如尝试访问一个只有真正主节点才能访问的资源如一个特定的文件锁、数据库锁确认成功后再进行后续操作如重启本机HAProxy绑定VIP。这是一个增强方案。notify脚本这是一个非常实用的钩子。我们创建/etc/keepalived/notify.sh在里面可以根据状态变化执行操作。例如在切换为master时确保本机的HAProxy服务正在运行并监听所有IP包括VIP在切换为backup时可以主动关闭一些服务或进行日志记录。启动Keepalivedsystemctl start keepalived; systemctl enable keepalived使用ip addr show eth0命令在主节点上应该能看到VIP192.168.1.100。5. 故障转移模拟与全链路测试配置完成后绝不能假设一切正常。我们必须模拟各种故障验证集群的自动恢复能力。这是上线前最关键的步骤。5.1 测试场景与操作步骤我们设计几个核心测试场景场景一读负载均衡与健康检查使用多个MySQL客户端持续连接到192.168.1.100:9601读VIP执行查询。观察HAProxy监控页面访问http://192.168.1.20:8888或http://192.168.1.21:8888确认读请求被均匀分配到两个Slave节点db-slave1和db-slave2。手动停止一个Slave节点的MySQL服务systemctl stop mysqld。观察监控页面该Slave状态应很快变为DOWN并且所有读请求不再发往该节点。恢复服务后状态应自动变回UP并重新接收流量。场景二Keepalived主备切换代理层高可用在初始状态VIP192.168.1.100应该在主Proxy节点.20上。在主Proxy节点上停止Keepalived服务systemctl stop keepalived。在备Proxy节点.21上立即使用ip addr show eth0查看会发现VIP已经漂移过来。此时应用连接192.168.1.100:9600或:9601流量会自动转到新的主Proxy.21上处理。整个过程对应用透明连接可能会发生短暂中断TCP超时但无需修改应用配置。恢复原主节点.20的Keepalived服务由于它的优先级更高VIP可能会漂移回去。可以通过调整nopreempt参数来控制是否允许抢占。场景三MySQL主库故障切换最核心的测试这是最复杂的一环因为HAProxy和Keepalived本身无法自动完成MySQL主从身份切换。它们只能检测后端MySQL是否可达。当Master宕机时HAProxy会将其标记为DOWN写端口9600的所有请求都会失败。因此我们需要一个额外的故障转移管理脚本通常由运维人员手动触发或由更高级的监控系统如Zabbix, PrometheusAlertmanager在检测到Master长时间不可用时自动调用。这个脚本需要做以下几件事确认原Master确实无法恢复。选择一个数据最接近原Master的Slave通过比较Executed_Gtid_Set。在该Slave上执行STOP SLAVE; RESET SLAVE ALL;清除其从属身份。在其他存活的Slave上指向新的Master。通知HAProxy更新配置将写后端组指向新的Master IP并重载配置。可选将原Master修复后作为新的Slave加入集群。踩坑实录自动切换脚本一定要谨慎务必加入多次确认机制和人工干预的入口。我曾经遇到过因为网络抖动导致脚本误判主库宕机进而触发切换造成“双主”数据冲突的严重事故。建议在生产环境中至少将“提升新主”这一步设置为需要手动确认。或者采用MHAMaster High Availability这类更成熟、经过大量实践检验的工具来管理MySQL主从切换它封装了这些复杂的逻辑和故障处理机制。5.2 应用端配置与连接池建议对于应用程序配置变得非常简单写数据源连接字符串指向jdbc:mysql://192.168.1.100:9600/your_database读数据源连接字符串指向jdbc:mysql://192.168.1.100:9601/your_database连接池配置要点超时时间设置合理的连接超时、socket超时时间应略大于HAProxy中timeout server的设置避免因代理层超时关闭连接而应用端不知情。心跳检测启用连接池的定期心跳如validationQuery: SELECT 1及时剔除被HAProxy或MySQL关闭的无效连接。故障转移感知一些高级的连接池如HikariCP或框架如Spring Cloud支持多数据源自动切换但在此架构下我们依赖VIP漂移应用层面通常不需要复杂配置。重点是确保应用在数据库连接异常时有重试机制。6. 性能监控、日常维护与问题排查集群上线后持续的监控和维护是保证其长期稳定运行的保障。6.1 关键监控指标MySQL层复制延迟在Slave上监控Seconds_Behind_Master。虽然这不是一个绝对精确的值但趋势增长是明显的危险信号。更准确的方法是监控Executed_Gtid_Set的差距。线程状态定期检查SHOW SLAVE STATUS\G确保Slave_IO_Running和Slave_SQL_Running均为Yes没有报错。资源使用CPU、内存、磁盘IO、网络流量。特别是磁盘空间和binlog保留时间。HAProxy层会话数与队列通过监控页面或stats socket查看scur当前会话和qcur当前队列。如果qcur持续增长说明后端处理不过来需要扩容或优化。后端状态时刻关注后端服务器的UP/DOWN状态。错误计数关注econ连接错误、eresp响应错误是否在增长。Keepalived层VRRP状态通过ip addr命令或journalctl -u keepalived查看日志确认本节点当前是MASTER还是BACKUPVIP绑定是否正常。脚本执行日志检查自定义的notify.sh脚本是否有执行是否报错。6.2 常见问题排查思路当应用报告数据库连接失败或慢时可以按照以下链路快速排查应用层检查应用服务器网络是否正常能否ping通VIP192.168.1.100。代理层telnet 192.168.1.100 9600测试端口通不通。如果不通问题可能在Keepalived或防火墙。访问http://VIP:8888/haproxy-status看HAProxy监控页面是否能打开后端MySQL节点状态是否为UP。数据库层如果HAProxy显示某个节点DOWN直接登录该MySQL服务器检查MySQL服务状态、错误日志/var/log/mysqld.log。检查主从复制状态是否有复制错误或大事务阻塞。网络层检查各节点之间的防火墙规则、SELinux状态以及网络是否有丢包或延迟激增。一个典型故障案例现象读请求非常慢但写请求正常。 排查登录HAProxy监控页发现两个Slave都是UP状态。分别直连两个Slave执行查询发现其中一个Slave响应极慢。检查该慢Slave的服务器资源发现磁盘IO使用率100%。进一步检查发现是某个未使用索引的全表扫描查询导致。临时Kill掉问题会话并优化该查询语句。这套MNA集群环境通过组合MySQL、HAProxy、Keepalived这三个久经考验的组件为我们提供了一个理解高可用架构的绝佳实践样板。它的优势在于组件简单、可控性强每一个环节出了问题我们都能清晰地定位并手动干预。当然它也有缺点比如自动故障转移尤其是数据库主从切换不够智能化对运维人员的脚本开发能力和应急响应速度有要求。对于更复杂、规模更大的场景可以考虑引入Orchestrator、ProxySQL等更专业的工具。但无论如何亲手搭建并理解这套基础架构都是你深入数据库高可用领域不可或缺的一课。在实际操作中最重要的永远是测试、测试、再测试将各种故障场景都在预发布环境模拟一遍你的心里才会真正有底。
返回列表