MySQL NDB Cluster Installation - in VirtualBox...

Diesen Beitrag schrieb ich 7 Jahre und 4 Monate zuvor; die nachfolgenden Ausführungen müssen heute nicht unbedingt noch genau so funktionieren. Behalte das beim Lesen (und vor allem: beim Nachmachen!) bitte stets im Hinterkopf.

Geschätzte Lesezeit: 5 Minuten

Weitere Beiträge der Artikelserie „MySQL NDB Cluster“ findest du an dieser Stelle.

Die kranke Idee

Wie einige von euch auf Twitter ja vielleicht schon am Rande mitbekommen haben beschäftige ich mich derzeit sehr intensiv mit MySQL-NDB-Cluster. Nachdem ich jetzt eine vergleichsweise lange Zeit mit der Theorie verbracht habe konnte ich inzwischen damit beginnen, ein wenig in die Praxis einzusteigen. Das Produktivsystem werden zwei NDB-Cluster sein, die rechenzentrumsübergreifend eine Master-to-Master-Replikation fahren. Über virtuelle IPs wird die Verfügbarkeit realisiert – das System bleibt verfügbar, wenn einzelne Knoten ausfallen und sogar, wenn ein ganzer Standort ausfällt. Das greift in viele Bereiche ein und ist ein etwas umfangreicheres Projekt. Um ein Gefühl für die Sache zu bekommen, begann ich zu spielen: Cluster GREEN fand seinen Platz auf meinem MacPro, Cluster BLUE auf dem iMac und jeweils unter VirtualBox. DNS und DHCP laufen hier auf einem RaspberryPi.

Ein Grundsystem installieren

Das System soll unter dem aktuellen Ubuntu Server LTS laufen; zum Zeitpunkt der Erstellung des Artikels ist das die 14.04.2. Meine Idee ist, mir eine Installation als Basis zu erstellen und diese dann zu klonen, so dass ich nicht n-mal langweilige Installationsarbeit leisten muss. Auf die Details gehe ich an dieser Stelle mal nicht ein – es ist eine Standard-Installation von Ubuntu in VirtualBox auf einem 8GB VDI mit LVM, ohne Home Encryption und mit SSH, Netzwerk über NAT, Audio deaktiviert, kein Floppy, kein CD-ROM. Die Hardware-„Ausstattung“ wird wie folgt sein (sollte sich jemand fragen, weshalb ich mit den 32GB RAM in meinem MacPro sehr glücklich bin: deshalb beispielsweise :D ):

  • zwei Management Nodes: 512MB RAM, 1x CPU
  • zwei Data Nodes: 2048MB RAM, 2x CPU

Hernach erledigen wir alle Schritte, die sowohl auf den Management als auch auf den Data Nodes anfallen: Ordner erstellen, Updates und Pakete installieren; später werden wir noch das Netzwerk umkonfigurieren, denn DHCP ist für unsere Zwecke nicht so günstig, aber für den Moment ist es ganz angenehm, wenn die Kisten Verbindung nach außen aufbauen können.

root@datanode1:~# apt-get update && apt-get upgrade
root@datanode1:~# apt-get install htop libaio1 libaio-dev munin-node
root@datanode1:~# mkdir /var/lib/mysql-cluster

Schon jetzt erstellen wir uns eine /etc/hosts, die für alle Hosts gelten wird:

## file: "/etc/hosts"
## IP           Hostname                Alias
127.0.0.1       localhost
10.0.2.10       lnv-10.intern           datanode1
10.0.2.11       lnv-11.intern           datanode2
10.0.2.20       lnv-20.intern           management1
10.0.2.21       lnv-21.intern           management2

Anschließend muss das MySQL-Cluster-Paket (zum Zeitpunkt der Erstellung dieses Artikels 7.4.6) heruntergeladen und ausgepackt werden; wir schieben es direkt nach /usr/local.

root@datanode1:~# cd /usr/local
root@datanode1:/usr/local# wget https://dev.mysql.com/get/Downloads/MySQL-Cluster-7.4/mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64.tar.gz
root@datanode1:/usr/local# tar xvfz mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64.tar.gz
root@datanode1:/usr/local# rm mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64.tar.gz

Jetzt kann die VM heruntergefahren und abgeschaltet werden: das Grundsystem ist fertig. Ich klone die Datenplatte – für das erste Management-System. Einfach nur kopieren ist nicht – beim Kopieren würde auch die UUID übernommen werden, so dass die neue Maschine nicht von der Platte würde booten können.

petzi:datanode1 spillerm$ VBoxManage clonevdi datanode1.vdi management1.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: cd612365-71ac-4cd1-8e1b-7b910a87e227

Management Nodes einrichten

management1

In VirtualBox wird jetzt eine neue Maschine angelegt; dieser Maschine füttere ich das eben erstellte management1.vdi als Datenplatte ein und starte das System durch. Benötigt wird außerdem eine config.ini, in der die grundlegende Konfiguration unseres Clusters vorgenommen wird; sie liegt in /var/lib/mysql-cluster. Wir richten uns entsprechend ein:

root@management1# cd /usr/local/
root@management1# cp mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64/bin/ndb_mgm* /usr/bin
root@management1# chmod 755 /usr/bin/ndb_mg*
root@management1# mkdir -p /usr/local/mysql/mysql-cluster
root@management1# rm -rf mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64*
root@management1# echo "ndb_mgmd -f /var/lib/mysql-cluster/config.ini --configdir=/var/lib/mysql-cluster/" > /etc/init.d/ndb_mgmd && chmod 755 /etc/init.d/ndb_mgmd
root@management1# wget https://raw.githubusercontent.com/netzwerkgoettin/misc/master/mysql/config.ini -O /var/lib/mysql-cluster/config.ini

Abschließend muss in /etc/hostname noch der Hostname geändert werden (von datanode1 auf management1) und wir bearbeiten die /etc/network/interfaces, so dass die IP fortan nicht mehr per DHCP bezogen, sondern statisch vergeben wird; Gateway und DNS werden nicht benötigt:

## file: "/etc/network/interfaces"
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
  address 10.0.2.20
  netmask 255.255.255.0

management2

Die Maschine management1 ist nun soweit vorbereitet - sie kann heruntergefahren, abgeschaltet und geklont werden.

petzi:datanode1 spillerm$ VBoxManage clonevdi management1.vdi management2.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: 2e91831c-238b-48be-b66a-338b482b02c3

Der Host management2 wird in VirtualBox analog zu management1 eingerichtet, die Datenplatte management2.vdi wird ihm untergeschoben und er wird hochgefahren. Hier muss nur in /etc/hostname der Hostname geändert werden (von management1 auf management2) und in /etc/network/interfaces die IP-Adresse (von 10.0.2.20 auf 10.0.2.21). Außerdem muss in /etc/mysql-proxy.conf die proxy-address angepasst werden! Zur Sicherheit sollten nun beide Management Nodes einmal sauber durchgestartet werden – Netzwerk-Adapter 1 habe ich hierbei auf Internal Network gesetzt, Netzwerk-Adapter 2 hingegen auf Bridged Network – in meinem Fall über das WLAN-Interface des iMac. So bieten die Management Nodes „nach innen“ ein Interface mit einer Adresse aus dem 10.0.2.x-Netzwerk, „nach außen“ erhalten sie eine Adresse aus meinem regulären 192.168.2.x-Netzwerk, die über meinen DHCP fest vergeben wird. Zu beachten ist, dass hierfür auf beiden Management Nodes die /etc/network/interfaces um eth1 erweitert werden muss:

...
auto eth1
iface eth1 inet dhcp

Inbetriebnahme der Management Nodes

management1

root@management1:~# /etc/init.d/ndb_mgmd start
MySQL Cluster Management Server mysql-5.6.24 ndb-7.4.6
root@management1:~# ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm> show
Connected to Management Server at: localhost:1186
ERROR Message: The cluster configuration is not yet confirmed by all defined management servers.
This management server is still waiting for node 2 to connect.

Das ist doch mal eine klare Ansage. Nun denn: starten wir auf die gleiche Weise den Dienst auf management2!

management2

root@management2:~# /etc/init.d/ndb_mgmd start
MySQL Cluster Management Server mysql-5.6.24 ndb-7.4.6
root@management1:~# ndb_mgm
-- NDB Cluster -- Management Client --
ndb_mgm> show
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]	2 node(s)
id=3 (not connected, accepting connect from datanode1)
id=4 (not connected, accepting connect from datanode2)

[ndb_mgmd(MGM)]	2 node(s)
id=1	@10.0.2.20  (mysql-5.6.24 ndb-7.4.6)
id=2	@10.0.2.21  (mysql-5.6.24 ndb-7.4.6)

[mysqld(API)]	2 node(s)
id=5 (not connected, accepting connect from any host)
id=6 (not connected, accepting connect from any host)

Wunderbar, beide Management Nodes sind up&running. Der Rest erwartungsgemäß nicht – die müssen wir ja nun aufziehen. Wir beenden die Arbeiten an den management nodes, indem wir abschließend noch auf beiden Nodes dafür sorgen, dass /etc/init.d/ndb_mgmd beim Booten ausgeführt wird.

root@management1:/usr/local# update-rc.d ndb_mgmd defaults
update-rc.d: warning: /etc/init.d/ndb_mgmd missing LSB information
update-rc.d: see 
 Adding system startup for /etc/init.d/ndb_mgmd ...
   /etc/rc0.d/K20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc1.d/K20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc6.d/K20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc2.d/S20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc3.d/S20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc4.d/S20ndb_mgmd -> ../init.d/ndb_mgmd
   /etc/rc5.d/S20ndb_mgmd -> ../init.d/ndb_mgmd

Die Data Nodes einrichten

Hierzu starten wir unsere datanode1 wieder; das Netzwerk belassen wir noch auf NAT, damit wir bequemerweise die Konfigurationsdateien aus dem Netz ziehen können. Wir müssen Binaries an Ort und Stelle bewegen, Startscripte erstellen, alles einrichten. Die data nodes benötigen eine my.cnf in /etc; sollte es bereits einen Ordner /etc/mysql geben, so ist man gut beraten, diesen umzubenennen, da er zu Konflikten führen kann. Und natürlich muss die bind-address gegebenenfalls angepasst werden!

root@datanode1:~# groupadd mysql
root@datanode1:~# useradd -g mysql mysql
root@datanode1:~# wget https://raw.githubusercontent.com/netzwerkgoettin/misc/master/mysql/my.cnf -O /etc/my.cnf
root@datanode1:~# cd /usr/local
root@datanode1:/usr/local# ln -s mysql-cluster-gpl-7.4.6-linux-glibc2.5-x86_64 mysql
root@datanode1:/usr/local# cd mysql
root@datanode1:/usr/local/mysql# mkdir /usr/share/mysql
root@datanode1:/usr/local/mysql# cp share/english/errmsg.sys /usr/share/mysql/
root@datanode1:/usr/local/mysql# mv bin/* /usr/bin
root@datanode1:/usr/local/mysql# rmdir bin/
root@datanode1:/usr/local/mysql# ln -s /usr/bin .
root@datanode1:/usr/local/mysql# scripts/mysql_install_db --user=mysql --basedir=.
Installing MySQL system tables...
[...]
root@datanode1:/usr/local/mysql# chown -R root:mysql .
root@datanode1:/usr/local/mysql# chown -R mysql data/
root@datanode1:/usr/local/mysql# cp support-files/mysql.server /etc/init.d/
root@datanode1:/usr/local/mysql# chmod 755 /etc/init.d/mysql.server

An dieser Stelle würde ich empfehlen, die VM herunterzufahren, abzuschalten und wiederum zu klonen – zu datanode2. Wie gehabt: in VirtualBox eine neue VM datanode2 anlegen, datanode2.vdi als Datenplatte einfüttern, booten. Den Hostnamen anpassen, die IP – wie bei den Management Nodes fest vergeben. Ob ihr die Maschine dann rebootet oder von Hand umsetzt sei euch überlassen – jedenfalls können nun datanode1 und datanode2 gestartet werden, wiederum beide mit internem Netz statt NAT. Und nun wird es spannend: wir können initialisieren und dann unsere Dienste starten. Die Initialisierung muss nur dann gemacht werden, wenn

  • der Node das erste Mal gestartet wird oder
  • wenn die config.ini auf den Management Nodes geändert wurde

datanode1 initialisieren

root@datanode1:~# cd /var/lib/mysql-cluster
root@datanode1:/var/lib/mysql-cluster# ndbd --initial
2015-05-05 21:26:29 [ndbd] INFO     -- Angel connected to '10.0.2.20:1186'
2015-05-05 21:26:29 [ndbd] INFO     -- Angel allocated nodeid: 3

Dann mal spicken auf einem der Management Node (ja, es ist egal, welcher von beiden genutzt wird):

ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]	2 node(s)
id=3	@10.0.2.10  (mysql-5.6.23 ndb-7.4.4, starting, Nodegroup: 0)
id=4 (not connected, accepting connect from 10.0.2.11)

[ndb_mgmd(MGM)]	2 node(s)
id=1	@10.0.2.20  (mysql-5.6.23 ndb-7.4.4)
id=2	@10.0.2.21  (mysql-5.6.23 ndb-7.4.4)

[mysqld(API)]	2 node(s)
id=5 (not connected, accepting connect from any host)
id=6 (not connected, accepting connect from any host)

datanode2 initialisieren

root@datanode2:/var/lib/mysql-cluster# ndbd --initial
2015-05-05 21:39:55 [ndbd] INFO     -- Angel connected to '10.0.2.21:1186'
2015-05-05 21:39:55 [ndbd] INFO     -- Angel allocated nodeid: 4
ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]	2 node(s)
id=3	@10.0.2.10  (mysql-5.6.24 ndb-7.4.6, starting, Nodegroup: 0, *)
id=4	@10.0.2.11  (mysql-5.6.24 ndb-7.4.6, starting, Nodegroup: 0)

[ndb_mgmd(MGM)]	2 node(s)
id=1	@10.0.2.20  (mysql-5.6.24 ndb-7.4.6)
id=2	@10.0.2.21  (mysql-5.6.24 ndb-7.4.6)

[mysqld(API)]	2 node(s)
id=5 (not connected, accepting connect from any host)
id=6 (not connected, accepting connect from any host)

mysql.server und secure_installation auf beiden data nodes

$ /etc/init.d/mysql.server start
.............................*
root@datanode1:~# /usr/local/mysql/bin/mysql_secure_installation
[...]
Set root password? [Y/n]
[...]
Remove anonymous users? [Y/n]
[...]
Disallow root login remotely? [Y/n]
[...]
Remove test database and access to it? [Y/n] n
[...]
Reload privilege tables now? [Y/n] Y
[...]
Cleaning up...

MySQL-NDB-Cluster ist nun up & running.

ndb_mgm> show
Cluster Configuration
---------------------
[ndbd(NDB)]	2 node(s)
id=3	@10.0.2.10  (mysql-5.6.24 ndb-7.4.6, Nodegroup: 0, *)
id=4	@10.0.2.11  (mysql-5.6.24 ndb-7.4.6, Nodegroup: 0)

[ndb_mgmd(MGM)]	2 node(s)
id=1	@10.0.2.20  (mysql-5.6.24 ndb-7.4.6)
id=2	@10.0.2.21  (mysql-5.6.24 ndb-7.4.6)

[mysqld(API)]	2 node(s)
id=5	@10.0.2.10  (mysql-5.6.24 ndb-7.4.6)
id=6	@10.0.2.11  (mysql-5.6.24 ndb-7.4.6)

Großartig! Abschließend sorgen wir noch dafür, dass ndbd und mysql.server beim Booten automatisch gestartet werden – wiederum auf beiden Data Nodes. Hierzu habe ich den Aufruf /usr/bin/ndbd einfach in die /etc/rc.local geschrieben (vor das exit 0!) und mysql.server als Startscript hinzugefügt.

$ update-rc.d mysql.server defaults

Das ist die Basis: von hier aus gehen wir weiter. Die nächsten Schritte verpacke ich der Übersichtlichkeit halber in eigene Artikel, denn wie ihr seht: es entsteht ein ganz schöner Overhead. (Der nächste Schritt in meinem Cluster besteht in Distributed Privileges.) Mein MacPro langweilt sich vergleichsweise – mal sehen, ob das so bleibt… ;)

Mögliche Fehler

Forced node shutdown completed

Fehler : Node 4: Forced node shutdown completed. Occured during startphase 0. Initiated by signal 9.

Lag in meinem Fall daran, dass meine Data Nodes gnadenlos zu wenig RAM hatten (zum Testen hatte ich es mit 512MB versucht, die Systeme belegen im Leerlauf aber schon 1GB); Ubuntu packte darauf hin sozusagen seine Prozess-Fliegenklatsche (OOM Killer) aus und erschlug wahllos Prozesse. Lässt sich beispielsweise per dmesg gut nachvollziehen.

No such file or directory

Das passiert beispielsweise, wenn man die 32bit-Binaries auf ein 64bit-System packt und ndb_mgmd zu starten versucht: das Binary ist da, und dennoch behauptet das System No such file or directory. Mittels file /usr/bin/ndb_mgmd lässt sich der Fehler beispielsweise recht schnell eingrenzen… Kommt davon, wenn man beim Download pennt… ;)

Failed to allocate nodeid

Failed to allocate nodeid, error: 'Error: Could not alloc node id at management1 port 1186: No free node id found for ndbd(NDB).'

Diese Meldung erscheint zum Beispiel, wenn man auf einem der Data Nodes einen ndbd starten möchte, er jedoch schon läuft…