MySQL Cluster has a pretty cool feature that allows you to add new data nodes whilst the cluster is online, thus avoiding any downtime. This is incredibly useful for scaling out the data nodes and adding additional node groups. In this article, I’ll show how to add two new data nodes to an existing cluster that has two data nodes defined. I’ll also explain what needs to happen after the configuration change to ensure that any existing data is correctly partitioned across the new nodes.
NoOfReplicas is set to 2 - so there are 2 copies of each fragment of data. The hosts comprising the cluster before the changes are:
- mysql01.local - 192.168.122.40 - Management and API node 1 (ndb-nodeid=1)
- mysql02.local - 192.168.122.41 - Management and API node 2 (ndb-nodeid=2)
- mysql03.local - 192.168.122.42 - Data node 1 (ndb-nodeid=3)
- mysql04.local - 192.168.122.43 - Data node 2 (ndb-nodeid=4)
I’ll be adding the following to the cluster:
- mysql05.local - 192.168.122.44 - Data node 3 (ndb-nodeid=5)
- mysql06.local - 192.168.122.45 - Data node 4 (ndb-nodeid=6)
The two new nodes will form a new nodegroup, and we’ll end up with two nodegroups in our cluster - nodegroup 0 containing the original members (ID=3, ID=4) and the new nodegroup 1 containing the two new members (ID=5, ID=6).
Prior to making changes, verify that the existing cluster is operational:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# ndb_mgm -e 'SHOW' Connected to Management Server at: localhost:1186 Cluster Configuration --------------------- [ndbd(NDB)] 2 node(s) id=3 @192.168.122.42 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0, Master) id=4 @192.168.122.43 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0) [ndb_mgmd(MGM)] 2 node(s) id=1 @192.168.122.40 (mysql-5.6.11 ndb-7.3.2) id=2 @192.168.122.41 (mysql-5.6.11 ndb-7.3.2) [mysqld(API)] 6 node(s) id=7 @192.168.122.40 (mysql-5.6.11 ndb-7.3.2) id=8 @192.168.122.41 (mysql-5.6.11 ndb-7.3.2) id=9 (not connected, accepting connect from any host) id=10 (not connected, accepting connect from any host) id=11 (not connected, accepting connect from any host) id=12 (not connected, accepting connect from any host) |
Load in some test data. I’ll just create a clustered database with a single table, and add a few rows of data to it. This will enable us to verify partitioning after the new data nodes have been added:
|
1 2 3 4 5 6 7 8 9 10 11 |
mysql> CREATE DATABASE clusterdb; Query OK, 1 row affected (0.10 sec) mysql> USE clusterdb; Database changed mysql> CREATE TABLE testtable ( id INT ) ENGINE=NDB; Query OK, 0 rows affected (0.50 sec) mysql> INSERT INTO testtable VALUES (1),(2),(3),(4),(5),(6),(7),(8); Query OK, 8 rows affected (0.24 sec) Records: 8 Duplicates: 0 Warnings: 0 |
If we run ndb_desc, we can see that the data has been partitioned across both existing data nodes, and that the appropriate fragments have been created for our two replicas:
|
1 2 3 4 5 6 |
# ndb_desc -d clusterdb testtable -c 192.168.122.41:1186 -pn ... -- Per partition info -- Partition Row count Commit count Frag fixed memory Frag varsized memory Extent_space Free extent_space Nodes 1 4 4 32768 0 0 0 4,3 0 4 4 32768 0 0 0 3,4 |
Next, modify config.ini on both management servers and add in the appropriate configuration for the two new data nodes. My config.ini files are stored at /var/lib/mysql/config.ini:
|
1 2 3 4 5 6 7 8 9 10 |
# vi /var/lib/mysql/config.ini ... [ndbd] NodeId = 5 Hostname = 192.168.122.44 [ndbd] NodeId = 6 Hostname = 192.168.122.45 ... |
Restart both management nodes so that the new configuration takes effect, with the --reload or --initial option. You’ll need to restart both at the same time so that the configurations do not differ across the two management nodes. Whilst this is occurring, the cluster will be operational as usual:
|
1 2 |
# killall ndb_mgmd # ndb_mgmd --config-file /var/lib/mysql/config.ini --ndb-nodeid=<nodeid> --config-dir /var/lib/mysql/cluster-cache --initial |
Verify that the new configuration is in effect by running ALL STATUS to show the status of ALL the data nodes:
|
1 2 3 4 5 6 |
# ndb_mgm -e 'ALL STATUS' Connected to Management Server at: localhost:1186 Node 3: started (mysql-5.6.11 ndb-7.3.2) Node 4: started (mysql-5.6.11 ndb-7.3.2) Node 5: not connected Node 6: not connected |
Perform a rolling restart of the existing data nodes. Ensure that each data node has restarted fully and successfully before restarting the next one:
|
1 2 3 4 5 6 7 8 9 |
# ndb_mgm ndb_mgm> 3 RESTART ... ndb_mgm> 3 STATUS Node 3: started (mysql-5.6.11 ndb-7.3.2) ndb_mgm> 4 RESTART ... ndb_mgm> 4 STATUS Node 4: started (mysql-5.6.11 ndb-7.3.2) |
Whilst the nodes are restarting, you can enter <NODEID> STATUS as above and observe the start phases (0 through to 101) until the node is fully online.
Next, perform a rolling restart of any existing API nodes (for example: mysqld instances):
|
1 2 3 |
# mysqladmin -u root -p shutdown Enter password: # /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql --user=mysql --ndbcluster --ndb-connectstring=192.168.122.40:1186,192.168.122.41:1186 & |
Now, the new data nodes can be started. Use the --initial option to ensure that the NDB filesystem is initialised. The new data nodes can be started at the same time:
|
1 2 3 4 5 6 |
mysql05.local# ndbd --initial 2013-06-30 15:30:07 [ndbd] INFO -- Angel connected to '192.168.122.40:1186' 2013-06-30 15:30:07 [ndbd] INFO -- Angel allocated nodeid: 5 mysql06.local# ndbd --initial 2013-06-30 15:30:10 [ndbd] INFO -- Angel connected to '192.168.122.40:1186' 2013-06-30 15:30:10 [ndbd] INFO -- Angel allocated nodeid: 6 |
Wait for the nodes to reach a started state by monitoring them in the ndb_mgm client using ALL STATUS:
|
1 2 3 4 5 6 |
ndb_mgm> ALL STATUS Connected to Management Server at: localhost:1186 Node 3: started (mysql-5.6.11 ndb-7.3.2) Node 4: started (mysql-5.6.11 ndb-7.3.2) Node 5: started (mysql-5.6.11 ndb-7.3.2) Node 6: started (mysql-5.6.11 ndb-7.3.2) |
Once all data nodes are online, issue SHOW:
|
1 2 3 4 5 6 7 8 9 10 |
ndb_mgm> SHOW Cluster Configuration --------------------- [ndbd(NDB)] 4 node(s) id=3 @192.168.122.42 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0, Master) id=4 @192.168.122.43 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0) id=5 @192.168.122.44 (mysql-5.6.11 ndb-7.3.2, no nodegroup) id=6 @192.168.122.45 (mysql-5.6.11 ndb-7.3.2, no nodegroup) ... |
As you can see, the new nodes are not placed into a nodegroup automatically. We must do this manually with the CREATE NODEGROUP command:
|
1 2 3 4 5 6 7 8 9 10 |
ndb_mgm> CREATE NODEGROUP 5,6 Nodegroup 1 created ndb_mgm> SHOW Cluster Configuration --------------------- [ndbd(NDB)] 4 node(s) id=3 @192.168.122.42 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0, Master) id=4 @192.168.122.43 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 0) id=5 @192.168.122.44 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 1) id=6 @192.168.122.45 (mysql-5.6.11 ndb-7.3.2, Nodegroup: 1) |
The new nodegroup is ready, and the data nodes have been added to the cluster without any downtime!
New data will be distributed around the new data nodes correctly, and the appropriate partitions (4 of them - 8 fragments as we have NoOfReplicas = 2 and 4 data nodes) will be created for new tables. But what about existing tables? Remember our clusterdb.testtable table that we created earlier? ndb_desc shows that this table has not been re-partitioned:
|
1 2 3 4 5 6 |
# ndb_desc -d clusterdb testtable -c 192.168.122.41:1186 -pn ... -- Per partition info -- Partition Row count Commit count Frag fixed memory Frag varsized memory Extent_space Free extent_space Nodes 0 4 4 32768 0 0 0 3,4 1 4 4 32768 0 0 0 4,3 |
We need to run ALTER ONLINE TABLE <tablename> REORGANIZE PARTITION from an API node for this re-balancing to occur:
|
1 |
mysql> ALTER ONLINE TABLE clusterdb.testtable REORGANIZE PARTITION; |
Let’s check again with ndb_desc:
|
1 2 3 4 5 6 7 8 |
# ndb_desc -d clusterdb testtable -c 192.168.122.41:1186 -pn ... -- Per partition info -- Partition Row count Commit count Frag fixed memory Frag varsized memory Extent_space Free extent_space Nodes 1 1 10 32768 0 0 0 4,3 0 3 6 32768 0 0 0 3,4 2 1 1 32768 0 0 0 5,6 3 3 3 32768 0 0 0 6,5 |
Excellent - we now have four partitions correctly fragmented (scroll across!) across the four nodes.
You should also OPTIMIZE TABLE to clear up any wasted space (the other type of fragmentation…):
|
1 2 3 4 5 6 7 |
mysql> OPTIMIZE TABLE clusterdb.testtable; +---------------------+----------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------------------+----------+----------+----------+ | clusterdb.testtable | optimize | status | OK | +---------------------+----------+----------+----------+ 1 row in set (0.00 sec) |
Remember - you’ll need to ALTER ... REORGANIZE PARTITION and OPTIMIZE all of your NDB tables. You can get a list of those tables from the INFORMATION_SCHEMA as follows:
|
1 2 3 4 5 6 7 8 9 10 |
mysql> SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE ENGINE = 'NDBCLUSTER'; +--------------+-----------------------+ | TABLE_SCHEMA | TABLE_NAME | +--------------+-----------------------+ | clusterdb | testtable | | mysql | ndb_apply_status | | mysql | ndb_index_stat_head | | mysql | ndb_index_stat_sample | +--------------+-----------------------+ 4 rows in set (0.03 sec) |
Finally, check the memory usage across the cluster from an ndb_mgm client:
|
1 2 3 4 5 6 7 8 9 |
ndb_mgm> ALL REPORT MemoryUsage Node 3: Data usage is 0%(27 32K pages of total 4096) Node 3: Index usage is 0%(25 8K pages of total 8224) Node 4: Data usage is 0%(27 32K pages of total 4096) Node 4: Index usage is 0%(25 8K pages of total 8224) Node 5: Data usage is 0%(21 32K pages of total 4096) Node 5: Index usage is 0%(4 8K pages of total 8224) Node 6: Data usage is 0%(21 32K pages of total 4096) Node 6: Index usage is 0%(4 8K pages of total 8224) |