MySQL Cluster 是MySQL官方出品的分布式数据库解决方案,使用的数据库引擎为NDB,跟单机下的MyISAM和Innodb引擎有所不同,操作界面之一就是MySQL,此外提供原生API,可以节省资源并加快执行速度。该方案比业界其他MySQL集群方案在数据量大时有更大优势,开发者使用上跟单库操作几乎无差异,原先使用MySQL的话几乎可以无缝迁移,就可以享受集群带来的力量。当然也有个明显的缺点:内存开销非常大,如果要选择该方案,需要足够的硬件内存资源。下面我们详细地讲述MySQL Cluster 的部署使用。


第一步:下载安装

我们可以从MySQL的官网上下载到http://dev.mysql.com/downloads/cluster/ 
此处我们下载的是源码版mysql-cluster-gpl-7.4.8.tar.gz,您可根据自己的情况选择其他二进制版本,免去依赖的安装。编译依赖比mysql多几个,主要注意下这里需要jdk7。只有jre是不够的,jdk8目前不支持。其他的依赖都没有特别的。

$ BUILD/autorun.sh
$ ./configure --prefix=/home/lyw/db/mysql-cluster
$ make -j4
$ sudo make install

安装好后我们可以看看bin目录下的内容,里面不仅有mysql开头的mysql相关文件,而且多了很多ndb开头的文件,这些ndb开头的文件就是MySQL Cluster的核心所在了。


第二步:用工具自动部署

从7.3版本开始,MySQL Cluster提供了一个自动部署工具,这真的是大大降低的入门的难度。

1.    启动自动部署工具
如果我们用的是桌面版,我们运行下面的命令,会自动用浏览器打开一个部署页面,

$ bin/ndb_setup.py

如果是服务器版,需要增加两个参数,免得在自己机器上打不开网页,如果有防火墙请允许对应端口访问。

$ bin/ndb_setup.py  -N 192.168.1.8  -p 8081

然后根据提示打开对应的网页,这里是http://192.168.1.8:8081/welcome.html
我们点击页面上的文字链接“Create New MySQL Cluster”,进入下面的页面

wKioL1Y7Dmmyg9rXAADxD6jXEl4312.jpg


Application area中:
        第一项simple testing意思是只分配很少的内存,因此只能存一点点数据
        第二项Web application则会尽量多分配内存。(具体多少根据下面几页配置决定)
        第三项realtime是在Web application的基础上,缩短心跳的间隔,能更快的发现机器故障。
Write load中:
        三项的对应的写吞吐率,第一项小于100/s,第二项100~1000/s,第三项1000/s以上。
一般测试我们选择Web application和Medium就好了,一般都能应付。
下面的SSH property部分需要在多台机器部署时有用,如果跟hadoop一样已经有免密码登陆,则不用改,如果需要密码登陆,则写上机器的用户名密码。我们这里是本机部署因此无所谓。

2.    进入下一页服务器配置:

wKiom1Y7Diqigd-xAADNgtbz9Ik113.jpg

默认情况下Memory会配置为本机的所有内存,这样会导致内存不足而启动失败,请少配置一点。不过也不能太少,单机时最少1.8G,当配置小于1.8G时,基本上存不了什么数据,那时操作会报一些看起来奇怪的错误,因为跟其他的引擎错误不同。
如果您有很多机器,可以点击左下角的AddHost按钮多增加几台,每台的内存需要在450M以上,总内存还是需要在1.8G以上。


3.    进入下一页进程配置:

wKioL1Y7DmqA_eG7AADmqAPDcx4758.jpg


默认情况下会配置1个管理节点,2个数据节点,2个MySQL节点,另外还有3个API结点(直接用Ndb API连接及ndb工具运行时使用)。
自动配置时一般每个Data节点和MySQL节点都需要450M以上内存(普通MySQL只需要100M,这里会特别费内存),最好稍微计算下内存是否够用。如果内存足够,可以点击左下角的Add process按钮增加几个数据节点,其他节点测试时一般不用增加。如下图。

wKiom1Y7DiqCa3HUAACeej_pWfM341.jpg


4.    再下一页是配置修改

wKioL1Y7DmujjQD3AAGLg1imffo312.jpg


我们可以点击绿色圈的“+”修改一下端口,路径等。管理节点的默认端口号是1186,如果修改了端口号,那后面的操作都需要增加参数。SQL节点使用了3306, 3307这样的默认端口,如果本机跑了其他MySQL占用了这两个端口,请修改下。

5.    最后进入下一页部署启动

wKiom1Y7DiuCOim9AAHrhw4RU0s212.jpg


只要点击下面中间那个”Deply and start cluster”按钮,然后等待一分钟左右,让进度条走完,除API外状态都变绿圈圈,MySQL Cluster就部署成功了。

wKioL1Y7DmvSDLnTAADK9nMYTPg046.jpg


 

我们现在就可以用mysql客户端去登陆了,您也可以用您喜欢的图形界面来查看。

$ bin/mysql -uroot -h127.0.0.1 -P3306
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| ndbinfo            |
| performance_schema |
| test               |
| tmp                |
+--------------------+
6 rows in set (0.00 sec)

mysql> create database lyw;
Query OK, 1 row affected (0.05 sec)

mysql> use lyw;
Database changed

mysql> create table t1 (id int primary key, a int, v varchar(32)) engine ndbcluster;
Query OK, 0 rows affected (0.77 sec)

mysql> insert into t1 values (1, 1, 'a'), (2, 2, 'b');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from t1;
+----+------+------+
| id | a    | v    |
+----+------+------+
|  1 |    1 | a    |
|  2 |    2 | b    |
+----+------+------+
2 rows in set (0.00 sec)

我们发现默认的数据库比平常多两个,特别是 ndbinfo,当然是存储 ndb相关的一些数据了。当我们创建表格时,我们要在后面指定存储引擎 engine ndbcluster,否则创建出来的表格还是默认的innodb,只在单机上有数据。我们下面用多种工具校验下数据确实存储到了ndb引擎。
方法一:查看创建语句 show create table t1;  如果返回的内容里面有ENGINE=ndbcluster,说明用的是ndb引擎。

方法二:链接上我们的另外一个MySQL节点。看是否有对应的数据

$ bin/mysql -uroot -h127.0.0.1 -P3307
mysql> select * from lyw.t1;
+----+------+------+
| id | a    | v    |
+----+------+------+
|  1 |    1 | a    |
|  2 |    2 | b    |
+----+------+------+
2 rows in set (0.00 sec)

数据能从另外的节点查到,说明数据已经在ndb上,如果您自己创建一个其他引擎的表,数据在其他库是查不到的。

方法三:用ndb_desc命令,后面两个参数是数据库名和表名。管理者端口改了,或不是本机,需要增加参数 -c 192.168.1.8:1186

$ bin/ndb_desc -p -d lyw t1
或
$ bin/ndb_desc -p -d lyw t1 -c 192.168.1.8:1186

如果有一大屏幕的内容,说明这个表已经在ndb引擎里了,并且显示了关于该表的各种信息。


第三步:创建磁盘表

ndb默认创建的表格是内存表,意思是所有数据都加载在内存中,当内存不能够放下所有数据时,将不能插入数据。数据再磁盘中也会存,但那些只是在宕机重启后用于加载的,平常不会去读。如果数据全部在内存,而我们的内存并非很大,需要存储的数据却很多,那怎么办呢,7.3版本开始ndb引擎支持磁盘表,创建时需要多两个步骤,我们下面来创建一下。
首先我们要创建一个日志文件组lg1:

mysql> create logfile group lg1 add undofile 'undo.lg1' initial_size 16M engine ndbcluster;

然后创建一个表空间ts1:

mysql> create tablespace ts1 add datafile 'data.ts1' use logfile group lg1 initial_size 64M engine ndbcluster;

这时我们就可以创建表格了:

mysql> create table t2 (id int primary key, a int, v varchar(32)) tablespace ts1 storage disk engine ndbcluster;

这里比上面有多个几个关键字 tablespace ts1 storage disk。
这里的数据和日志文件就相当于innodb引擎里的数据文件和日志文件,一般日志文件不用太大,而数据文件需要足够放表里的数据。如果运行到一定时间发现不够了,我们也可以添加的。

mysql> alter tablespace ts1 add datafile 'data2.ts1' initial_size 128M engine ndbcluster;

这样ts1这个表空间里面就有两个数据文件了,总大小是64+128=192M了。
日志组也同样可以增加文件,这个一般在写入吞吐率增加时才需要增加。

mysql> alter logfile group lg1 add undofile 'undo2.lg1' initial_size 16M engine ndbcluster;


表空间创建好后我们可以用ndb_show_tables命令查看是否真的建立成功了

$ bin/ndb_show_tables  |grep -E "lg1|ts1"
37    Tablespace           Online   -                             ts1
36    Undofile             Online   -                             undo.lg1
39    Datafile             Online   -                             data2.ts1
38    Datafile             Online   -                             data.ts1
40    Undofile             Online   -                             undo2.lg1
35    LogfileGroup         Online   -                             lg1

另外我们也可以到文件系统上去看,是否有了对应的文件。


第四步:自己手动部署集群

前面我们部署的集群是用了自动化工具的,有些配置不能轻易修改,只适合快速和初学使用,实际应用的时候我们还是应该要手动地去部署。同时也为我们后面的集群扩容做准备。我们参考自动部署产生的配置文件,在上面修改一下。
数字49目录下的config.ini就是我们最关键的配置了。刚才我们生成的配置文件如下

[NDB_MGMD DEFAULT]
Portnumber=1186

[NDB_MGMD]
NodeId=49
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data/49/
Portnumber=1186

[TCP DEFAULT]
SendBufferMemory=4M
ReceiveBufferMemory=4M

[NDBD DEFAULT]
BackupMaxWriteSize=1M
BackupDataBufferSize=16M
BackupLogBufferSize=4M
BackupMemory=20M
BackupReportFrequency=10
MemReportFrequency=30
LogLevelStartup=15
LogLevelShutdown=15
LogLevelCheckpoint=8
LogLevelNodeRestart=15
DataMemory=135M
IndexMemory=22M
MaxNoOfTables=4096
MaxNoOfTriggers=3500
NoOfReplicas=2
StringMemory=25
DiskPageBufferMemory=64M
SharedGlobalMemory=20M
LongMessageBuffer=32M
MaxNoOfConcurrentTransactions=16384
BatchSizePerLocalScan=512
FragmentLogFileSize=256M
NoOfFragmentLogFiles=3
RedoBuffer=32M
MaxNoOfExecutionThreads=2
StopOnError=false
LockPagesInMainMemory=1
TimeBetweenEpochsTimeout=32000
TimeBetweenWatchdogCheckInitial=60000
TransactionInactiveTimeout=60000
HeartbeatIntervalDbDb=15000
HeartbeatIntervalDbApi=15000

[NDBD]
NodeId=1
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data/1/

[NDBD]
NodeId=2
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data/2/

[MYSQLD DEFAULT]

[MYSQLD]
NodeId=53
HostName=127.0.0.1

[MYSQLD]
NodeId=54
HostName=127.0.0.1

[API]
NodeId=50
HostName=127.0.0.1

[API]
NodeId=51
HostName=127.0.0.1

[API]
NodeId=52
HostName=127.0.0.1


[NDB_MGMD] 组没有多少内容,可以根据自己的情况改改端口路径等。
[NDBD DEFAULT] 组配置了各数据节点相同的参数,我们可以看到这个文件中配置的内存都是挺大的,我们可以自行调整,如果机器内存较小,可以把所有内存都配小一点,如果内存较大,(每个节点16G以内),只要将DataMemoryIndexMemory改大一点就好了。
我们可能需要将数据配置到其他路径下,就修改下对应的路径。
FragmentLogFileSize*NoOfFragmentLogFiles因大于DataMemory的值,否则会出现内存用不完而硬盘不够放的情况。
增加几个 [NDBD] 组的内容即可增加几个数据节点,注意NDBD 的id范围在1~48之间。
增加几个 [MYSQLD] 组的内容即可增加几个MySQL节点。这种id范围在1~255之间。
由于数据节点范围是1~48,资源很宝贵,因此尽量将这个区间保留给数据节点,其他节点使用49~255的范围。
[API] 组一般不用动,如果编程时大量使用原生API编程,需要增加一些。bin目录下的ndb_开头的工具都是使用API组的连接,不过他们属于短连接,使用完就释放了。

我们再看一下53或54目录下的my.cnf,这是mysql的配置文件

[mysqld]
log-error=mysqld.53.err
datadir="/home/lyw/db/mysql-cluster/run/data/53/"
tmpdir="/home/lyw/db/mysql-cluster/run/data/53/tmp"
basedir="/home/lyw/db/mysql-cluster/"
port=3306
ndbcluster=on
ndb-nodeid=53
ndb-connectstring=127.0.0.1:1186,
socket="/home/lyw/db/mysql-cluster/run/data/53/mysql.socket"

可以看到里面多了3行ndb相关的参数,您可以自行在配置文件里增加参数,比如innodb相关的,因为innodb引擎已经不再使用,默认128M的内存,48M的日志文件显得过大,我们完全可以将他们调小。设置下server-id,方便后面说的主从复制。

innodb_buffer_pool_size = 16M
innodb_additional_mem_pool_size = 2M
innodb_log_file_size = 5M
innodb_log_buffer_size = 5M
server-id = 53

如果是单机下,我们准备一个初始化和启动脚本initial.sh,最好加上执行权限:

basedir=/home/lyw/db/mysql-cluster/run/data
bindir=/home/lyw/db/mysql-cluster
$bindir/bin/ndb_mgmd --ndb-nodeid=49 --config-dir=$basedir/49 --config-file=$basedir/49/config.ini  --initial
sleep 3
# 更多的数据节点,就增加几个数字
for id in 1  2
do
    mkdir $id
    $bindir/bin/ndbmtd --ndb-nodeid=$id --ndb-connectstring=127.0.0.1:1186  --initial
    sleep 10
done
sleep 10
cd $bindir
for id2 in 53  54
do
    mkdir -p $basedir/$id2/tmp
    $bindir/scripts/mysql_install_db --defaults-file=$basedir/$id2/my.cnf 
    $bindir/bin/mysqld_safe --defaults-file=$basedir/$id2/my.cnf &
done
sleep 3
ps aux|grep mysql

然后我们将前面配置的3种4个配置文件下面目录组织起来。

.
├── 49
│   └── config.ini
├── 53
│   └── my.cnf
├── 54
│   └── my.cnf
└── initial.sh

执行我们写好的脚本initial.sh,大约需要一分钟,显示一大堆的内容后,我们的集群就部署并启动好了。我们回过头去看下启动脚本,说明下启动的步骤:

1. 启动管理节点ndb_mgmd,注意,参数需要指定全路径,有个--initial,这个参数自在第一次启动时使用。

$bindir/bin/ndb_mgmd --ndb-nodeid=49 --config-dir=$basedir/49 --config-file=$basedir/49/config.ini  --initial

2. 启动每个数据节点ndbmtd,这里也一样第一次启动需要--initial参数进行初始化,目录需要事先创建好。

mkdir $id
$bindir/bin/ndbmtd --ndb-nodeid=$id --ndb-connectstring=127.0.0.1:1186  --initial

3. 初始化每个数据库 mysql_install_db

mkdir -p $basedir/$id2/tmp
$bindir/scripts/mysql_install_db --defaults-file=$basedir/$id2/my.cnf

4. 启动每个数据库mysqld

$bindir/bin/mysqld_safe --defaults-file=$basedir/$id2/my.cnf &

这样所有节点就全部启动好了。我们可以跟前面一样测试下系统是否工作正常。


第五步:集群在线扩容

我们前面部署的集群只有两个数据节点,能够存储的数据量有限,当我们数据越来越多时,就需要扩充集群容量,MySQL Cluster最强大的功能之一就是在线扩容,扩容期间服务看不出停顿。我们就来看看在线扩容是如何操作的吧。
我们用前面准备的集群,并且在集群中写入若干数据(写入过程略)。我这里写了lyw.sbtest1表100000条数据,我们用ndb_desc命令查看数据的分布情况

$ bin/ndb_desc -d lyw sbtest1 -pn
。。。。。。
FragmentCount: 2
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
0            49950        49950           10715136             0                        0                0                     1,2    
1            50050        50050           10747904             0                        0                0                     2,1

可以看到数据基本平均分布在两个分片里。默认情况下,分片数是跟节点数相同的,这个可以配置,在分片章节再讲。

我们用另外一个命令看一下集群的健康状况

$ bin/ndb_mgm
-- NDB Cluster -- Management Client --

ndb_mgm> show
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]    2 node(s)
id=1    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0, *)
id=2    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0)
[ndb_mgmd(MGM)]    1 node(s)
id=49    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)
[mysqld(API)]    5 node(s)
id=50 (not connected, accepting connect from 127.0.0.1)
id=51 (not connected, accepting connect from 127.0.0.1)
id=52 (not connected, accepting connect from 127.0.0.1)
id=53    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)
id=54    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)

ndb_mgm> all report memory
Node 1: Data usage is 18%(781 32K pages of total 4320)
Node 1: Index usage is 6%(196 8K pages of total 2848)
Node 2: Data usage is 18%(781 32K pages of total 4320)
Node 2: Index usage is 6%(196 8K pages of total 2848)

show命令查看各节点的存活状态如何。
all report memory 命令查看各数据节点的内存使用情况。

接下来我们打算将集群从2个数据节点扩充到4个数据节点。首先我们在49/config.ini配置文件里增加2个数据节点的配置:

[NDBD]
NodeId=3
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data/3/

[NDBD]
NodeId=4
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data/4/

我们用ndb_mgm客户端工具停止ndb_mgmd节点

ndb_mgm> 49 stop

ndb_mgmd节点停止了并不会影响集群的数据操作,因此您不用着急,慢慢来就好了。
再用命令行启动,这里的参数跟前面的不同,原先--initial 变成--reload,另外注意参数最好用全路径

$ /home/lyw/db/mysql-cluster/bin/ndb_mgmd --ndb-nodeid=49 --config-dir=/home/lyw/db/mysql-cluster/run/data/49 --config-file=/home/lyw/db/mysql-cluster/run/data/49/config.ini --reload

检查下是否启动正常

ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]    4 node(s)
id=1    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0, *)
id=2    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0)
id=3 (not connected, accepting connect from 127.0.0.1)
id=4 (not connected, accepting connect from 127.0.0.1)
[ndb_mgmd(MGM)]    1 node(s)
id=49    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)
[mysqld(API)]    5 node(s)
id=50 (not connected, accepting connect from 127.0.0.1)
id=51 (not connected, accepting connect from 127.0.0.1)
id=52 (not connected, accepting connect from 127.0.0.1)
id=53    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)
id=54    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8)

我们发现 ndb_mgmd节点已启动, 新增的2个数据节点3, 4并没有连接。我们还不着急启动他们俩,我们先将现在活着的节点逐个重启一下,让他们都知道很快就会有新同事来了。节点的重启需要花费数十秒,请耐心等待“Node 1: Started  (version 7.4.8)”字样的出现。(这些字符不是命令的输入),然后再操作下一条语句。

ndb_mgm> 1 restart
Node 1: Node shutdown initiated
Node 1: Node shutdown completed, restarting, no start.
Node 1 is being restarted
ndb_mgm> Node 1: Start initiated (version 7.4.8)
Node 1: Started (version 7.4.8)

ndb_mgm> 2 restart
Node 2: Node shutdown initiated
Node 2: Node shutdown completed, restarting, no start.
Node 2 is being restarted
ndb_mgm> Node 2: Start initiated (version 7.4.8)
Node 2: Started (version 7.4.8)

2个mysql节点也要逐个重启下

$ bin/mysqladmin -uroot -h127.0.0.1 -P3306 shutdown
$ bin/mysqld_safe --defaults-file=/home/lyw/db/mysql-cluster/run/data/53/my.cnf &

$ bin/mysqladmin -uroot -h127.0.0.1 -P3307 shutdown
$ bin/mysqld_safe --defaults-file=/home/lyw/db/mysql-cluster/run/data/54/my.cnf &

我们用ndb_mgm> show命令检查一下,是否都启动成功(显示内容略)
至此原先环境的所有进程都已经重启好了,我们启动新加入的两个节点,注意最后的--initial参数

$ mkdir 3 4
$ /home/lyw/db/mysql-cluster/bin/ndbmtd --ndb-nodeid=3 --ndb-connectstring=127.0.0.1:1186  --initial    
$ /home/lyw/db/mysql-cluster/bin/ndbmtd --ndb-nodeid=4 --ndb-connectstring=127.0.0.1:1186  --initial

数十秒后,用show命令检查,显示如下:

ndb_mgm> show
[ndbd(NDB)]    4 node(s)
id=1    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0, *)
id=2    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0)
id=3    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, no nodegroup)
id=4    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, no nodegroup)
。。。。。。

节点都已启动成功,不过3,4两个节点后面显示为 “no nodegroup”,而1,2两个节点显示为“Nodegroup: 0”。根据MySQL Cluster的结构,一个集群可由多个nodegroup组成,一个nodegroup可由多个datanode组成,数据分片fragement在相同nodegroup的多个datanode间相互同步。至于还没有加入任何组的数据节点是不会提供服务的。我们需要为这两个节点建立一个组。

ndb_mgm> create nodegroup 3,4
Nodegroup 1 created
ndb_mgm> show
[ndbd(NDB)]    4 node(s)
id=1    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0, *)
id=2    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 0)
id=3    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 1)
id=4    @127.0.0.1  (mysql-5.6.27 ndb-7.4.8, Nodegroup: 1)

这样我们就有两个nodegroup了。再来看下我们之前插入的100000条数据的分布情况,

$ bin/ndb_desc -d lyw sbtest1 -pn
。。。。。。
FragmentCount: 2
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
0            49950        49950           10715136             0                        0                0                     1,2    
1            50050        50050           10747904             0                        0                0                     2,1

我们发现还是跟以前一样是两个分片,且都在1,2两个数据节点上。就算是等上一天也不会改变,似乎我们的新节点还没有生效。我们加一个新表lyw2.sbtest1 试试,也写入100000条。

$ bin/ndb_desc -d lyw2 sbtest1 -pn
。。。。。。
FragmentCount: 4
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
0            24943        24943           5373952              0                        0                0                     1,2    
2            25007        25007           5373952              0                        0                0                     2,1    
3            24961        24961           5373952              0                        0                0                     4,3    
1            25089        25089           5373952              0                        0                0                     3,4

我们发现新表的数据是可以自动分布到新的节点上去了。
如果我们想让原先表 lyw.sbtest1的数据也均匀分布到新节点上,还需要在mysql客户端做下面的操作。

mysql> alter online table lyw.sbtest1 reorganize partition;

这时再用ndb_desc查看分布,数据已经分布到新节点上去了

$ bin/ndb_desc -d lyw sbtest1 -pn
。。。。。。
FragmentCount: 4
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
0            24943        99964           10715136             0                        0                0                     1,2    
1            25089        99972           10747904             0                        0                0                     2,1    
2            25007        25007           5373952              0                        0                0                     3,4    
3            24961        24961           5373952              0                        0                0                     4,3

 不过还是会发现0,1 两个分片的内存使用量(Frag fixed memory列)并没有下降,目前版本这个内存只会在删除表的情况下才会释放,个人觉得这是个较大缺陷,估计后面的版本会改进吧。


第六步:表的分片设定

1.    分片数量控制

前面创建的表格的分片数都是系统根据节点数自动设置的,一般跟节点数相同,实际上这个分片数也是可以指定的,用partitions参数:

mysql> create table t3( id int primary key, a int, v varchar(32)) engine ndbcluster partition by key(id) partitions 1;
mysql> create table t8( id int primary key, a int, v varchar(32)) engine ndbcluster partition by key(id) partitions 8;

如果某些表估计数据量不大,就可以考虑将分片数设置为1,这种情况下就相当于是单库操作。如果某些表数据量巨大,就可以增大分片数,最大分片数是8*nodegroup数。

2.    多主键下的分片控制

当我们创建的表格需要两个主键的时候会是怎样的呢?我们也来创建一个:

mysql> create table d1(id1 int, id2 int, a int, v varchar(32), primary key (id1, id2)) engine ndbcluster;
mysql> insert into d1 values(1,1,1,'a'), (1,2,3,'a'), (1,3,4, 'b'), (1,4,5,'d');

这里我们插入的数据id1都相同,id2是不同的,然后我们查看数据的分布:

$ bin/ndb_desc -d lyw d1 -pn
。。。。。。
-- Attributes --
id1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
id2 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
0            1            1               32768                32768                   0                0                     1,2    
2            1            1               32768                32768                   0                0                     2,1    
1            1            1               32768                32768                   0                0                     3,4    
3            1            1               32768                32768                   0                0                     4,3

4个分片里面全有数据,实际上这里的分片规则是根据两个key一起决定的,我们再看表属性里面id1 和id2 都有 “DISTRIBUTION KEY” 字样,也是说明了这一点。
如果是这样分片很有可能不是我们想要的分片方式,我们经常会希望让id1相同的数据都在一起,在一个分片上就能查找到,这样能够减少数据库的查询开销。要想达到这个目的,我们建表时需要多写一点内容。

mysql> create table d2(id1 int, id2 int, a int, v varchar(32), primary key (id1, id2)) engine ndbcluster partition by key(id1);
mysql> insert into d2 values(1,1,1,'a'), (1,2,3,'a'), (1,3,4, 'b'), (1,4,5,'d');

建表语句后面增加了partition by key(id1)。我们插入同样的4行,再来看表属性

$ bin/ndb_desc -d lyw d2 -pn
。。。。。。
-- Attributes --
id1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY
id2 Int PRIMARY KEY AT=FIXED ST=MEMORY
。。。。。。
-- Per partition info -- 
Partition    Row count    Commit count    Frag fixed memory    Frag varsized memory    Extent_space    Free extent_space    Nodes    
3            4            4               32768                32768                   0                0                     4,3

所有数据都在3号分片上,这绝非是巧合,您可以自己多插入些数据试试。另外我们看到id2属性比id1 少了“ DISTRIBUTION KEY”这部分内容,也说明了该表只按照id1进行分片。

我们也可以指定只按照id2进行分片,但是不可以按照非主键的列进行分片:

mysql> create table d3(id1 int, id2 int, a int, v varchar(32), primary key (id1, id2)) engine ndbcluster partition by key(id2);
Query OK, 0 rows affected (1.04 sec)

mysql> create table d4(id1 int, id2 int, a int, v varchar(32), primary key (id1, id2)) engine ndbcluster partition by key(a);
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function


第七步:NDB引擎的事务

InnoDB引擎支持所有4个级别的事务,而NDB引擎却只支持READ COMMITTED级别事务,比InnoDB引擎的默认级别低了一级,也就是说,本来在InnoDB引擎下运行良好的程序,迁移到NDB引擎有可能会产生一些错误。迁移前需要做好足够的检查和测试。下面我们用一个例子说明下NDB引擎的事务情况。我们用

mysql-A>和mysql-B>>区分两个客户端
mysql-A> create table t1 (id int primary key, a int, v varchar(32)) engine ndbcluster;
mysql-A> insert into t1 values (1, 1, 'a'), (2, 2, 'b');
mysql-A> begin;
Query OK, 0 rows affected (0.02 sec)

mysql-B>> begin;
Query OK, 0 rows affected (0.00 sec)

mysql-A> update t1 set a = 100 where id = 1;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0 

mysql-B>> select * from t1 where id = 1;
+----+------+------+
| id | a    | v    |
+----+------+------+
|  1 |    1 | a    |
+----+------+------+
1 row in set (0.00 sec)

mysql-A> commit;
Query OK, 0 rows affected (0.00 sec)

mysql-B>> select * from t1 where id = 1;
+----+------+------+
| id | a    | v    |
+----+------+------+
|  1 |  100 | a    |
+----+------+------+
1 row in set (0.00 sec)

可以看到在事务A里面commit前事务B并不能查到更改,但是commit后,B就能查到了更改。而在InnoDB引擎里面,B是永远都查不到外界的任何修改的。如果原先的代码中依赖可重复读,那么迁移时需要修改下。


第八步:分布式权限管理

NDB使用的权限系统就是MySQL这一套,只是到目前为止的权限还是配置在MySQL节点上,并且各个MySQL节点的权限数据可以不同,如果修改了其中一个节点的权限,其他节点的权限并没有修改。为了使所有的MySQL节点的权限是分布式一致的,我们需要做一定的调整。
NDB提供了一个sql脚本share/ndb_dist_priv.sql帮助我们做这件事情,这个脚本会创建几个函数供我们使用,我们在任意一个MySQL节点执行下面这个两行代码即可。

$ bin/mysql -uroot -h127.0.0.1 -P3306
mysql> source share/ndb_dist_priv.sql;
mysql> call mysql.mysql_cluster_move_privileges();

我们来测试下权限情况:
先来删掉两个无密码的用户。在任意一个MySQL节点执行删除语句。

mysql> delete from mysql.user where user='';

在每个MySQL节点执行下面这条语句刷新权限。

mysql> flush privileges;

在任意一个MySQL节点添加一个用户。

mysql> grant all on *.* to 'lyw'@'%' identified by '123456';

执行后我们尝试用新用户登录

$ bin/mysql -ulyw -h127.0.0.1 -P3306 -p123456
mysql>
$ bin/mysql -ulyw -h127.0.0.1 -P3307 -p123456
mysql>

我们发现两个MySQL节点都已经有了lyw这个新用户,并且已经生效。以后如果使用grant方法进行权限的更改,都能够同步到每一个MySQL节点上。而直接操作user表修改权限,需要flush privileges时,需要在每个MySQL节点上执行flush privileges命令才能全部生效。


第九步:管理节点高可用

前面集群配置里面的管理节点ndb_mgmd进程是单个的,只是单台的话可用性较低。虽然说该节点宕机并不影响读写等操作,但还是会影响到集群的节点配置变更,因此最好还是配置为高可用。ndb_mgmd自身是支持高可用的,在前面的配置基础上稍作调整即可。
1.    config.ini配置增加一个 [NDB_MGMD] 分组

[NDB_MGMD]
NodeId=149
HostName=127.0.0.1
DataDir=/home/lyw/db/mysql-cluster/run/data2/149/
Portnumber=1187

2.    并且将这份配置文件复制出一份,49和149两个配置文件内容必须完全相同:

cp –r 49 149

3.    所有节点的 --ndb-connectstring 参数配置多个端口或IP,逗号分隔:

在 ndb_mtd 启动参数中修改为 
--ndb-connectstring=127.0.0.1:1186,127.0.0.1:1187,

在 my.cnf 配置文件中修改为 
ndb-connectstring=127.0.0.1:1186,127.0.0.1:1187,

4.    启动时先将所有ndb_mgmd进程启动,因此前面的启动脚本 initial.sh 要多加一行:

$bindir/bin/ndb_mgmd --ndb-nodeid=149 --config-dir=$basedir/149 --config-file=$basedir/149/config.ini  --initial

5.    然后就可以执行启动脚本启动了。

./initial.sh

这样配置后,挂掉任意一台 ndb_mgmd 是不会影响任何服务的,线上机器最好这样配置。ndb_mgmd 压力非常小,无需独立两台机器,跟其他数据节点 ndb_mtd 等混合部署即可。

第十步:其他集群管理

1. 关闭集群
ndb相关节点关闭用ndb_mgm客户端

ndb_mgm> shutdown
或
bin/ndb_mgm -e shutdown

mysql 节点用mysql的关闭方法

bin/mysqladmin -uroot -h127.0.0.1 -P3306 shutdown
或
sudo service mysql stop

2. 启动集群
前面集群的第一次启动,命令行参数后面都有个--initial,从第二次启动开始,就不需要这个参数了。单机时可以稍微修改下前面的初始化脚本为启动脚本。

$ /home/lyw/db/mysql-cluster/bin/ndb_mgmd --ndb-nodeid=49 --config-dir=/home/lyw/db/mysql-cluster/run/data/49 --config-file=/home/lyw/db/mysql-cluster/run/data/49/config.ini
$ /home/lyw/db/mysql-cluster/bin/ndbmtd --ndb-nodeid=1 --ndb-connectstring=127.0.0.1:1186
。。。。。。

3. 主从复制(热备份)
跟普通的MySQL主从复制一样,只是这里可以在集群A任意选择一台MySQL节点作为主,在集群B任意选择一台MySQL节点作为从,让他们之间建立主从即可,传统方式和GTID方式均可。这样集群A的任何修改都会同步到集群B,当然是异步的。可以作为异地灾备方案。
同样的,可以利用主从配置方法配置出更多结构:一主多从,双主,三主等。

4. NDB冷备份
NDB提供类似mysqldump的在线冷备份功能

ndb_mgm> start backup

执行后,会在数据节点目录下多一个BACKUP目录,备份内容就在该目录下,并自动命名为BACKUP-1。以后执行数字依次递增。数字也可以手动指定,如

ndb_mgm> start backup 20151111
$ ls 1/BACKUP/
BACKUP-1   BACKUP-20151111

内容就备份到BACKUP-20151111目录下了。

以上就是MySQL Cluster的基本功能了,更多的细节功能需要在使用中去逐步发现和体会。

在多种集群之间选择犹豫时,可以参考下《MySQL Cluster, Fabric, Cobar 三大集群特性对比》这篇文章,一定会对你有所帮助的。