MySQL NDB Cluster,官方如今更常称之为 MySQL NDB Cluster,是一套专为分布式环境设计、追求高可用与高性能的数据库解决方案。它的核心理念十分清晰:将数据分散到多个节点,借助并行处理与冗余机制来增强读写性能与系统可靠性。底层依赖的 NDB 存储引擎,天生适合处理高并发、低延迟的负载场景——电信计费、金融交易等对实时性与稳定性要求严苛的业务,正是它的主战场。
一、 MySQL Cluster 的功能特性
首先来看它的几个关键特性。
高可用是基本能力。集群内置故障检测与自动恢复机制,当某个节点发生故障时,系统能够自行接管,确保数据与服务不中断。这背后依赖于多副本机制以及节点间的状态同步。
分布式存储则是另一大亮点。NDB 引擎会自动将数据切分为多个分片,并分散存储到不同的数据节点上。这意味着存储容量与性能能够随着节点数量的增加而线性扩展——想要扩容?只需增加一个节点即可。
实时处理能力是它与传统 MySQL 最显著的差异之一。NDB 引擎在内存中管理数据(同时也支持持久化),能够提供毫秒级的响应速度,非常适合在线游戏、高频交易等需要快速反馈的应用场景。
自动分区帮助用户省去了手动分表的麻烦。NDB 会根据主键或其他指定键自动进行分区,尽量让数据在各节点间均匀分布,从而避免热点集中。当然,如果分区键选择不当,也会引发问题,后续的部署部分会展示具体案例。
动态扩展让运维工作变得轻松。无需停机即可动态添加或移除节点,弹性扩容就是这么简单。
事务、并行查询、多地域复制等功能同样没有缺失——NDB 支持完整的 ACID 事务,允许多个查询并发执行,还能跨数据中心进行数据同步,使整个集群具备地理级容灾能力。
二、 MySQL Cluster 的体系架构

整个集群由三种角色组成,分工明确:
SQL 节点,可以理解为一台“轻量化”的 MySQL 服务器。它负责所有数据库上层工作——连接管理、SQL 解析、查询优化、缓存,但唯独不存储数据。数据存到哪里?交给数据节点。因此 SQL 节点本质上是纯粹的 SQL 执行器,底层存储完全交由 NDB 引擎处理。
管理节点是集群的中枢,负责配置管理、节点启停、备份调度。它是整个集群的大脑,因此启动顺序上必须最先启动。对应的守护进程是 ndb_mgmd。
数据节点是真正的存储层。每个数据节点仅保存完整数据的一个分片(一个 fragment),但只要副本数配置得当(例如 NoOfReplicas=2),每个分片都有备份,存储层就不会出现单点故障。数据节点对应的进程是 ndbd 或 ndbmtd(多线程版本)。
三、 部署 MySQL Cluster
下面以银河麒麟 Linux 为例,通过一个具体的部署过程演示集群搭建。节点信息如下(实际 IP 和主机名请根据环境调整):

安装介质为 RPM 包,版本 8.0.23,列表如下:
mysql-cluster-community-client-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-client-plugins-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-common-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-data-node-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-libs-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-management-server-8.0.23-1.el8.x86_64.rpm
mysql-cluster-community-server-8.0.23-1.el8.x86_64.rpm
以下是详细步骤,每个节点需要执行的操作将分别说明。
(1)所有节点关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
(2)所有节点关闭 SELinux
编辑 /etc/selinux/config,将 SELINUX=enforcing 改为 SELINUX=disabled。
(3)所有节点配置主机名与 IP 映射
编辑 /etc/hosts,添加以下内容:
192.168.79.11 node11
192.168.79.12 node12
192.168.79.13 node13
192.168.79.14 node14
(4)所有节点卸载原有的 mariadb 和 mysql
# 检查是否安装了 mariadb
yum list installed | grep mariadb*
# 卸载 mariadb
yum remove mariadb* -y
# 检查是否安装了 mysql
yum list installed | grep mysql*
# 卸载 mysql
yum remove mysql* -y
(5)在 node11 上安装 SQL 节点所需包
rpm -ivh mysql-cluster-community-client-plugins-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-common-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-libs-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-client-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-server-8.0.23-1.el8.x86_64.rpm
(6)在 node12 上安装管理节点及客户端管理工具
rpm -ivh mysql-cluster-community-management-server-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-client-plugins-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-common-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-libs-8.0.23-1.el8.x86_64.rpm
rpm -ivh mysql-cluster-community-client-8.0.23-1.el8.x86_64.rpm
(7)在 node13 和 node14 上安装数据节点包
rpm -ivh mysql-cluster-community-data-node-8.0.23-1.el8.x86_64.rpm
(8)在 node12 上配置管理节点
创建配置目录并编写 config.ini:
mkdir -p /var/lib/mysql-cluster/
编辑 /var/lib/mysql-cluster/config.ini,内容如下:
[NDBD DEFAULT]
NoOfReplicas=2
DataMemory=80M
IndexMemory=18M
[TCP DEFAULT]
[MYSQLD DEFAULT]
[NDB_MGMD DEFAULT]
[NDB_MGMD]
HostName=node12
DataDir=/var/lib/mysql-cluster
[NDBD]
HostName=node13
DataDir=/usr/local/mysql/data
[NDBD]
HostName=node14
DataDir=/usr/local/mysql/data
[MYSQLD]
(9)在 node12 上启动管理节点
ndb_mgmd -f /var/lib/mysql-cluster/config.ini --initial
启动信息中会提示 IndexMemory 已废弃,但这不影响正常使用。
(10)在 node13 和 node14 上配置数据节点
创建数据目录并设置权限:
mkdir -p /usr/local/mysql/data
chown -R mysql:mysql /usr/local/mysql/data
编辑 /etc/my.cnf,添加以下内容:
[mysql_cluster]
ndb-connectstring=node12
(11)在 node13 和 node14 上启动数据节点
ndbd --initial
成功启动后,控制台会显示连接信息以及节点 ID 分配情况。
(12)在 node12 的管理节点上查看集群初始状态
ndb_mgm
ndb_mgm> show
此时应能看到两个数据节点(id=2,3)已连接,但 SQL 节点(id=4)尚未连接。
(13)在 node11 上配置 SQL 节点
编辑 /etc/my.cnf:
[mysqld]
ndbcluster
ndb-connectstring=node12
[mysql_cluster]
ndb-connectstring=node12
(14)在 node11 上启动 SQL 节点
systemctl start mysqld
(15)在 node12 上验证集群状态
ndb_mgm
ndb_mgm> show
此时四个节点应全部在线:
[ndbd(NDB)] 2 node(s)
id=2 @192.168.79.13 (mysql-8.0.23 ndb-8.0.23, Nodegroup: 0, *)
id=3 @192.168.79.14 (mysql-8.0.23 ndb-8.0.23, Nodegroup: 0)
[ndb_mgmd(MGM)] 1 node(s)
id=1 @192.168.79.12 (mysql-8.0.23 ndb-8.0.23)
[mysqld(API)] 1 node(s)
id=4 @192.168.79.11 (mysql-8.0.23 ndb-8.0.23)
也可以分别检查各节点的状态:
ndb_mgm> 1 status
Node 1: connected (Version 8.0.23)
ndb_mgm> 2 status
Node 2: started (mysql-8.0.23 ndb-8.0.23)
ndb_mgm> 3 status
Node 3: started (mysql-8.0.23 ndb-8.0.23)
ndb_mgm> 4 status
Node 4: connected (Version 8.0.23)
(16)在 node11 上登录 MySQL 并修改 root 密码
初始密码记录在 /var/log/mysqld.log 中,登录后执行:
mysql> alter user root@localhost identified by 'Welcome_1';
(17)创建分布式表并插入测试数据
这里以经典的 scott 库为例:
create database scott;
use scott;
create table dept (
deptno int primary key,
dname varchar(10),
loc varchar(10)
) ENGINE=ndbcluster;
create table emp (
empno int primary key,
ename varchar(10),
job varchar(10),
mgr int,
hiredate varchar(10),
sal int,
comm int,
deptno int,
foreign key(deptno) references dept(deptno)
) ENGINE=ndbcluster;
insert into dept values(10,'ACCOUNTING','NEW YORK');
insert into dept values(20,'RESEARCH','DALLAS');
insert into dept values(30,'SALES','CHICAGO');
insert into dept values(40,'OPERATIONS','BOSTON');
insert into emp values(7369,'SMITH','CLERK',7902,'1980/12/17',800,null,20);
insert into emp values(7499,'ALLEN','SALESMAN',7698,'1981/2/20',1600,300,30);
insert into emp values(7521,'WARD','SALESMAN',7698,'1981/2/22',1250,500,30);
insert into emp values(7566,'JONES','MANAGER',7839,'1981/4/2',2975,null,20);
insert into emp values(7654,'MARTIN','SALESMAN',7698,'1981/9/28',1250,1400,30);
insert into emp values(7698,'BLAKE','MANAGER',7839,'1981/5/1',2850,null,30);
insert into emp values(7782,'CLARK','MANAGER',7839,'1981/6/9',2450,null,10);
insert into emp values(7788,'SCOTT','ANALYST',7566,'1987/4/19',3000,null,20);
insert into emp values(7839,'KING','PRESIDENT',-1,'1981/11/17',5000,null,10);
insert into emp values(7844,'TURNER','SALESMAN',7698,'1981/9/8',1500,null,30);
insert into emp values(7876,'ADAMS','CLERK',7788,'1987/5/23',1100,null,20);
insert into emp values(7900,'JAMES','CLERK',7698,'1981/12/3',950,null,30);
insert into emp values(7902,'FORD','ANALYST',7566,'1981/12/3',3000,null,20);
insert into emp values(7934,'MILLER','CLERK',7782,'1982/1/23',1300,null,10);
(18)查看表的分片情况
检查 emp 表的分区分布:
mysql> select partition_name,table_rows
from information_schema.PARTITIONS
where table_name='emp' and table_schema='scott';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0 | 1 |
| p1 | 13 |
+----------------+------------+
14 条数据中 13 条集中在 p1 分片上,显然出现了数据倾斜。原因在于 emp 表以 empno 作为主键(NDB 默认将其作为分区键),而 empno 的值分布并不均匀——在哈希分区策略下,大部分数据恰好落入了同一个分区。
换成以 ename 作为主键再试一次:
(19)创建新表 emp1,以 ename 为主键
create table emp1 (
empno int,
ename varchar(10) primary key,
job varchar(10),
mgr int,
hiredate varchar(10),
sal int,
comm int,
deptno int,
foreign key(deptno) references dept(deptno)
) ENGINE=ndbcluster;
insert into emp1 select * from emp;
(20)查看 emp1 的分片分布
mysql> select partition_name,table_rows
from information_schema.PARTITIONS
where table_name='emp1' and table_schema='scott';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0 | 5 |
| p1 | 9 |
+----------------+------------+
数据分布比之前均衡了许多。这个对比直观地说明了一个关键点:NDB 分区键的选择直接决定了数据分布的均匀性,如果分区键选取不当,就容易产生热点,导致部分节点负载过高。在实际生产环境中,需要仔细评估数据特征,选择合适的分片键。
