尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

MySQL NDB Cluster实战:从零搭建高可用分布式数据库集群

MySQL NDB Cluster实战:从零搭建高可用分布式数据库集群 1. 从单点到集群为什么我们需要NDB Cluster如果你已经是一个MySQL DBA或者正在管理一个快速增长的在线业务那么下面这个场景你一定不陌生某个核心业务表的数据量已经达到了单机存储的极限查询响应时间开始变慢写入操作在高峰期频繁超时。你尝试了读写分离、分库分表甚至上了缓存但面对高并发、强一致性的实时交易场景比如秒杀、实时库存扣减或者金融交易这些方案要么引入复杂的应用层逻辑要么在一致性上做出妥协最终让你陷入“拆东墙补西墙”的困境。这时候MySQL NDB Cluster简称NDB就该登场了。它不是一个简单的“集群版MySQL”而是一个内存优先、无共享架构、自动分片、支持多主写入的分布式数据库。简单来说它把数据切分成多个分片Fragment每个分片在多个数据节点Data Node上都有副本任何一个数据节点宕机其他副本可以立刻顶上保证服务不中断。所有的数据节点都通过高速网络互联形成一个分布式的内存数据池应用通过SQL节点也就是我们熟悉的MySQL Server或者原生的NDB API来访问这个数据池。我之所以花时间折腾NDB是因为几年前我们一个核心的支付对账系统在日交易量突破千万笔后单机MySQL的写入瓶颈和主从延迟问题彻底爆发。我们当时评估了多种方案最终NDB的线性扩展能力和“五个九”的高可用承诺吸引了我们。从最初的测试集群到最终的生产上线踩过的坑、调过的参数足够写一本小册子。今天我就以一个过来人的身份带你从零开始手把手搭建一个高可用的NDB Cluster并分享那些官方文档里不会写的“实战心得”。2. 集群架构深度解析NDB的“五脏六腑”与网络拓扑在动手敲命令之前我们必须把NDB Cluster的架构和角色吃透。这就像盖房子前要看懂设计图否则搭建过程就是一团乱麻。一个标准的NDB Cluster包含三类核心进程它们各司其职管理节点 (Management Node,ndb_mgmd)这是集群的“大脑”和“配置中心”。它不存储任何业务数据主要职责是存储集群配置维护一个全局的config.ini文件定义了所有节点的IP、角色、内存大小等参数。节点管理与监控负责启动、停止、重启数据节点和SQL节点并提供ndb_mgm客户端工具供管理员查看集群状态、执行管理命令。仲裁与心跳监控所有节点的健康状态在节点发生故障时协调故障转移。一个生产环境通常建议部署两个管理节点形成主备避免单点故障。管理节点对资源要求很低甚至可以和SQL节点部署在同一台机器上。数据节点 (Data Node,ndbd或ndbmtd)这是集群的“心脏”和“肌肉”真正存储数据的地方。数据全部存放在内存中也可配置部分数据落盘并通过多副本机制保证高可用。ndbd单线程进程适用于核心数较少的场景。ndbmtd多线程进程这是现在的默认和推荐选项能充分利用多核CPU的性能尤其是在数据节点内存很大比如超过64GB时优势明显。数据分片与副本假设你设置NoOfReplicas2那么每份数据都会在2个不同的数据节点上存有副本。这些数据节点最好部署在不同的物理服务器上以实现真正的机器级容灾。SQL节点 (MySQL Server Node,mysqld)这是集群的“脸面”和“翻译官”。对我们DBA和应用开发者来说它就是一个标准的MySQL服务器支持绝大部分SQL语法、连接协议和客户端工具。无状态服务SQL节点本身不持久化任何表结构或数据除了本地的系统库如mysql。它通过NDB存储引擎与底层的数据节点通信。水平扩展你可以部署任意多个SQL节点应用可以像连接普通MySQL一样连接它们通过负载均衡器分发请求从而实现SQL处理能力的线性扩展。一个典型的最小高可用生产架构至少需要2个管理节点一主一备4个数据节点2个节点组每组2个副本实现N1冗余2个SQL节点实现负载均衡和故障转移所有节点之间必须通过高速、低延迟的网络互联万兆网络是基本要求。网络质量直接决定了集群的性能和稳定性。3. 实战环境规划与系统级调优纸上谈兵结束我们开始实战。假设我们要为一个新的实时风控系统搭建NDB Cluster预计初期数据量500GBQPS在1万左右。我规划了如下环境服务器6台同配置物理服务器或高性能云主机操作系统均为 CentOS 7.9 / Ubuntu 20.04 LTS。mgmt01(192.168.1.101): 主管理节点 SQL节点1mgmt02(192.168.1.102): 备管理节点 SQL节点2ndb01(192.168.1.111): 数据节点1ndb02(192.168.1.112): 数据节点2ndb03(192.168.1.113): 数据节点3ndb04(192.168.1.114): 数据节点4硬件每台机器32核CPU128GB内存数据节点额外配备NVMe SSD用于重做日志和检查点。网络所有机器在一个子网万兆网络互联并配置主机名解析。注意强烈建议使用静态IP并在每台机器的/etc/hosts文件中配置所有节点的主机名和IP映射。依赖DNS解析在集群启动和故障恢复时是致命的。第一步系统级调优所有节点这些调优是为了给NDB提供一个稳定的“地基”很多线上问题追根溯源都是系统参数没设对。关闭透明大页 (Transparent HugePages)THP会导致内存分配延迟波动对延迟敏感的NDB是灾难性的。# 检查状态 cat /sys/kernel/mm/transparent_hugepage/enabled # 临时关闭 echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag # 永久关闭编辑 /etc/rc.local 或使用 grub 配置调整内核参数编辑/etc/sysctl.conf以下参数对网络性能和内存管理至关重要。# 增加TCP缓冲区大小提升网络吞吐 net.core.rmem_max 134217728 net.core.wmem_max 134217728 net.ipv4.tcp_rmem 4096 87380 134217728 net.ipv4.tcp_wmem 4096 65536 134217728 # 增加文件描述符和进程数限制 fs.file-max 1000000 # 减少swap使用倾向让数据尽量留在内存 vm.swappiness 1 # 加快故障检测调整ARP和TCP超时 net.ipv4.neigh.default.gc_stale_time 120 net.ipv4.tcp_keepalive_time 600 net.ipv4.tcp_keepalive_probes 3 net.ipv4.tcp_keepalive_intvl 30执行sysctl -p使配置生效。调整资源限制编辑/etc/security/limits.conf确保NDB进程可以打开足够多的文件和线程。ndb-user soft nofile 65536 ndb-user hard nofile 65536 ndb-user soft nproc 16384 ndb-user hard nproc 16384这里假设我们创建一个专用用户ndb-user来运行集群进程。4. 软件安装与集群配置文件精讲我们选择MySQL官方编译好的二进制包进行安装版本选用MySQL NDB 8.0。在所有节点上操作。# 1. 创建用户和目录 groupadd mysql useradd -r -g mysql -s /bin/false ndb-user mkdir -p /usr/local/mysql /data/ndb_data /data/ndb_logs chown -R ndb-user:mysql /usr/local/mysql /data/ndb_data /data/ndb_logs # 2. 下载并解压安装包 (以8.0.36为例请替换为最新版本) wget https://dev.mysql.com/get/Downloads/MySQL-Cluster-8.0/mysql-cluster-8.0.36-linux-glibc2.17-x86_64.tar.gz tar -xzvf mysql-cluster-8.0.36-*.tar.gz -C /usr/local/ cd /usr/local ln -s mysql-cluster-8.0.36-linux-glibc2.17-x86_64 mysql # 3. 配置环境变量 echo export PATH/usr/local/mysql/bin:$PATH /etc/profile.d/mysql.sh source /etc/profile.d/mysql.sh接下来是重头戏编写集群配置文件。配置文件主要分为两部分管理节点的config.ini和 SQL节点的my.cnf。管理节点配置文件 (/usr/local/mysql/config.inion mgmt01)这个文件定义了整个集群的拓扑和参数由管理节点读取并分发。[ndbd default] # 数据节点通用配置 NoOfReplicas2 # 数据副本数2是标准高可用配置 DataMemory80G # 分配给数据的内存根据物理内存的70%-80%设置 IndexMemory10G # 分配给索引的内存 DataDir/data/ndb_data # 数据目录存放日志、检查点文件 FileSystemPathDD/data/ndb_data # 数据文件路径 BackupDataDir/data/ndb_backups # 备份目录 # 以下两个参数控制多久将数据刷新到磁盘影响宕机恢复时间 DiskPageBufferMemory1G SharedGlobalMemory2G # 重做日志相关大小和数量决定了能容忍多长的宕机时间 FragmentLogFileSize256M NoOfFragmentLogFiles200 # 重做日志总大小 256M * 200 50GB # 控制节点间心跳和超时网络差的环境需要调大 HeartbeatIntervalDbDb5000 HeartbeatIntervalDbApi5000 [ndb_mgmd] # 管理节点1 NodeId1 HostName192.168.1.101 DataDir/data/ndb_logs/mgmd [ndb_mgmd] # 管理节点2 NodeId2 HostName192.168.1.102 DataDir/data/ndb_logs/mgmd [ndbd] # 数据节点组1 - 主副本 NodeId11 HostName192.168.1.111 ServerPort1186 # 内部通信端口 [ndbd] # 数据节点组1 - 备副本 NodeId12 HostName192.168.1.112 ServerPort1186 [ndbd] # 数据节点组2 - 主副本 NodeId21 HostName192.168.1.113 ServerPort1186 [ndbd] # 数据节点组2 - 备副本 NodeId22 HostName192.168.1.114 ServerPort1186 [mysqld] # SQL节点1 NodeId51 HostName192.168.1.101 [mysqld] # SQL节点2 NodeId52 HostName192.168.1.102关键参数解读NoOfReplicas2这是高可用的基石。意味着每份数据有2个副本分布在不同的数据节点上。一个节点组Node Group包含这些副本。我们4个数据节点正好组成2个节点组11,12和21,22实现了数据分片和冗余。DataMemory和IndexMemory这是规划的重中之重。务必确保(DataMemory IndexMemory) * NoOfReplicas的总和小于所有数据节点的物理内存总和并预留至少25%给操作系统和其他进程。估算不准会导致集群无法启动或运行中内存溢出。NoOfFragmentLogFiles和FragmentLogFileSize决定了重做日志环的大小。这个环必须足够大能容纳从上一次本地检查点LCP开始到现在的所有数据变更。否则在数据节点恢复时会因为日志覆盖而失败。一个粗略估算日志环大小 每小时数据变更量 * 最大预期恢复小时数。SQL节点配置文件 (/etc/my.cnfon mgmt01 mgmt02)这个文件和普通MySQL配置很像但必须启用NDB存储引擎并指向管理节点。[mysqld] userndb-user datadir/var/lib/mysql socket/var/lib/mysql/mysql.sock log-error/var/log/mysqld.log pid-file/var/run/mysqld/mysqld.pid # NDB 特定配置 ndbcluster # 启用NDB引擎 ndb-connectstring192.168.1.101,192.168.1.102 # 连接管理节点 [mysql_cluster] ndb-connectstring192.168.1.101,192.168.1.102将config.ini复制到备管理节点 (mgmt02) 的相同位置。5. 集群启动、初始化和状态验证启动顺序有严格规定管理节点 - 数据节点 - SQL节点。关闭时顺序相反。第一步启动管理节点在mgmt01和mgmt02上分别执行cd /usr/local/mysql ndb_mgmd -f ./config.ini --initial --configdir/data/ndb_logs/mgmd--initial仅在第一次启动或配置文件发生根本性变化时使用它会清除之前的集群配置状态。--configdir指定存储生成的集群配置二进制文件的目录。第二步启动数据节点在所有四台数据节点服务器 (ndb01-ndb04) 上执行ndbmtd --ndb-connectstring192.168.1.101,192.168.1.102 --ndb-nodeid对应NodeId # 例如在 ndb01 (IP 111) 上NodeId是11命令为 # ndbmtd --ndb-connectstring192.168.1.101,192.168.1.102 --ndb-nodeid11首次启动也可以使用--initial参数来初始化数据目录但这会清空所有数据生产环境慎用。第三步检查集群状态在任意一台安装了管理客户端的机器上比如mgmt01ndb_mgm # 进入管理客户端后 ndb_mgm SHOW你会看到一个详细的连接状态表。关键看connected状态。当所有数据节点的状态变为Started才算启动成功。这个过程可能需要几分钟因为数据节点要进行内存分配、日志文件初始化等操作。第四步启动SQL节点并初始化系统表在mgmt01和mgmt02上启动MySQL服务mysqld --defaults-file/etc/my.cnf --initialize-insecure --userndb-user # --initialize-insecure 仅用于首次初始化生成空密码的root用户。生产环境应用 --initialize 生成随机密码。 mysqld_safe --defaults-file/etc/my.cnf --userndb-user 启动后登录MySQL检查NDB引擎是否就绪mysql -u root SELECT * FROM ndbinfo.nodes;如果能看到数据节点的信息说明SQL节点已成功连接到集群。第五步创建NDB表并验证在任意一个SQL节点上创建数据库和表CREATE DATABASE ndb_test; USE ndb_test; CREATE TABLE user ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, balance DECIMAL(15,2) DEFAULT 0.00, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), INDEX idx_name (name) ) ENGINENDB;注意ENGINENDB。然后插入一些数据。接着在另一个SQL节点上查询应该能立刻看到刚插入的数据这验证了数据的实时同步。6. 生产环境关键配置调优与监控集群跑起来只是第一步要稳定高效地服务生产流量还需要精细调优。1. 事务与并发调优NDB默认配置可能不适合高并发写入。在管理节点config.ini的[ndbd default]部分可以调整[ndbd default] # 增加事务处理线程数提升并发能力 MaxNoOfConcurrentTransactions4096 MaxNoOfConcurrentOperations100000 # 调整事务元数据内存 TransactionBufferMemory32M # 针对大量主键查询或范围扫描的优化 MaxNoOfLocalScans1024 BatchSizePerLocalScan256这些参数需要根据实际业务压力通过ndbinfo.counters表观察TRANSACTIONS、OPERATIONS等计数器进行动态调整。2. 备份与恢复策略NDB自带在线热备份工具ndb_mgm。启动备份ndb_mgm START BACKUP备份文件会保存在各数据节点的BackupDataDir下。恢复备份恢复过程需要停止集群在所有数据节点上执行ndb_restore -b backup_id -n node_id -m --backup_path/data/ndb_backups/BACKUP-backup_id/-m选项恢复元数据表结构只需要在一个节点执行一次。-r恢复数据在每个数据节点上都要执行并指定对应的-n。3. 监控与告警监控是集群的眼睛。除了常规的MySQL监控项连接数、QPS、慢查询NDB需要重点关注内存使用率ndbinfo.memoryusage。确保DataMemory和IndexMemory的使用率低于80%。重做日志状态ndbinfo.logspaces。观察LOGSPACE的USED比例如果持续很高说明日志环可能太小或者检查点LCP太慢。节点与连接状态ndb_mgm SHOW和ndbinfo.nodes。慢事务与超时ndbinfo.counters中的TRANSACTIONS和OPERATIONS的COMMIT、ABORT计数器。可以编写脚本定期采集这些信息并集成到PrometheusGrafana中。一个关键的告警规则是任何数据节点失去连接超过5秒必须立即触发PagerDuty或电话告警。7. 常见“深坑”与故障排查实战指南这里分享几个我踩过的、刻骨铭心的坑。坑一数据节点启动失败报错“Out of memory”现象ndbmtd进程启动后很快退出日志显示无法分配内存。排查首先检查config.ini中的DataMemory、IndexMemory设置是否超过物理内存。记住要乘以NoOfReplicas计算总需求。检查系统是否禁用了THP见第3步。检查ulimit -a确保max memory size和virtual memory不受限。使用pmap -x pid查看进程内存映射有时是glibc的memory arena问题可以设置环境变量MALLOC_ARENA_MAX4来限制。解决通常是参数设置过大。一个经验公式(DataMemory IndexMemory) (物理内存 * 0.75) / NoOfReplicas。初次搭建建议设置小一点比如32G稳定后再在线调整NDB支持动态调整部分内存参数。坑二集群运行一段时间后写入突然变慢甚至超时现象应用侧大量写操作超时但管理客户端SHOW显示所有节点Started。排查立刻连接ndb_mgm执行ALL REPORT MEMORYUSAGE查看各数据节点的内存使用情况。如果DataMemory使用率超过98%集群会进入“只读”状态以保护数据这是最常见的原因。检查ndbinfo.logspaces如果USED比例超过90%说明重做日志即将写满这会阻塞新的写事务等待检查点释放空间。检查网络ping和iperf3测试节点间延迟和带宽。网络抖动会导致心跳超时触发节点重组Node Recovery期间会阻塞事务。解决对于内存不足紧急情况下可以尝试在线增加DataMemory如果预留了空间。长远看需要扩容数据节点或优化数据模型比如压缩字段、归档历史数据。对于日志环满检查config.ini中的TimeBetweenLocalCheckpoints默认20ms和TimeBetweenGlobalCheckpoints默认2s。在写入量巨大的场景可以适当调小TimeBetweenLocalCheckpoints来加速检查点但会增加CPU和磁盘IO开销。这是一个权衡。对于网络问题与运维团队协作检查交换机、网卡状态确保网络隔离和带宽保障。坑三单个SQL节点宕机后部分查询报错“Table xxx doesnt exist”现象负载均衡器将流量切到存活SQL节点后大部分业务正常但少数复杂查询或连接查询报错。根因NDB的表结构元数据缓存机制。当在一个SQL节点上创建或修改表结构后元数据会异步传播到其他SQL节点。如果传播完成前另一个SQL节点执行了相关查询就可能遇到元数据不同步的错误。解决应用重试最简单的方案让应用层对这种特定错误码进行短暂延迟后重试。使用ndb_metadata_check工具定期或在执行DDL后手动触发元数据同步。优化DDL操作习惯尽量避免在业务高峰期执行DDL。对于关键表结构变更可以考虑在低峰期通过管理客户端 (ndb_mgm) 执行RESTART NODE sql_node_id来温和地重启SQL节点强制其重新拉取最新元数据。坑四备份文件巨大恢复时间远超预期现象一个500GB的集群备份文件可能达到1TB以上恢复需要数小时。根因NDB的备份是物理备份包含了数据文件、重做日志和检查点文件的副本。ndb_restore默认是单线程的。优化并行恢复ndb_restore支持-p参数指定并行度。你可以同时在多个数据节点上运行恢复进程并为每个进程指定不同的--backup-path和-n节点ID。但要注意协调确保元数据只恢复一次。压缩备份备份时使用操作系统管道进行压缩例如在管理节点启动备份后用脚本将各节点的备份文件流式压缩。恢复时先解压。测试恢复流程定期进行恢复演练记录恢复时间并作为RTO恢复时间目标的依据。不要等到真出事时才第一次操作。搭建和维护一个生产级的NDB Cluster就像带领一支特种部队每个成员节点都必须高度协同任何短板都可能引发连锁反应。它不适合所有场景——对于读多写少、事务不复杂、数据量巨大的OLAP场景或许有更经济的选择。但对于那些要求极高可用性、强一致性、且写入密集的在线核心业务当你真正需要“五个九”的可用性和线性扩展能力时NDB Cluster是经过战场考验的利器。
返回列表