Användarverktyg

Webbverktyg


teknik:mysql_ha_med_pacemaker

MySQL HA med Pacemaker

Här bygger jag ett HA-kluster med MySQL replikering och Pacemaker på två stycken Ubuntu 12.04 (Precise) maskiner.

Innan jag börjar är det bra om stegen i Corosync och Pacemaker på Debian följts, så vi har en grund att bygga på.

Installera MariaDB (alla noder)

Sedan Oracle köpte MySQL AB har jag stadigt rekommenderat MariaDB som en gratisversion, och upp till 5.5 är den fortfarande binärt kompatibel med Oracle MySQL.

Följ instruktionerna på den här sidan för att installera MariaDB. Vi som kör Ubuntu behöver följande i /etc/apt/sources.list.d/mariadb.list filen.

deb http://mirrors.fe.up.pt/pub/mariadb/repo/5.5/ubuntu precise main
deb-src http://mirrors.fe.up.pt/pub/mariadb/repo/5.5/ubuntu precise main

Uppdatera sedan apt, lägg till rätt nyckel för deras repository och installera servern.

apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
apt-get update
apt-get install mariadb-server

Konfigurera replikering

Replikering måste konfigureras manuellt först, i traditionell mysql-replikering är en nod master och en är slav. Master strömmar sina binära transaktionsloggar till slaven i realtid.

Slaven är hela tiden aktiv som en mysql-server men tillåter endast läsning, alltså inga skrivningar till databasen kan göras mot slavar. Detta kan vara bra för skräddarsydda applikationer som vill balansera ut lasten genom att dela upp läs och skrivfrågor till olika servrar.

Följ de här stegen exakt för att aktivera replikering.

Konfigurera master

Redigera följande rader i /etc/mysql/my.cnf.

[mysqld]
#bind-address           = 127.0.0.1
log_bin                 = /var/log/mysql/mysql-bin
log_bin_index           = /var/log/mysql/mysql-bin.index
server-id               = 1

Genom att kommentera bind-address gör vi så att servern lyssnar på alla gränssnitt.

Starta om servern med de nya ändringarna.

service mysql restart

Konfigurera slaven

Redigera följande rader i /etc/mysql/my.cnf.

[mysqld]
#bind-address           = 127.0.0.1
skip-slave-start
server-id               = 2
report_host             = linuxlab02
  • skip-slave-start ska endast användas i första uppstarten för att undvika att slavtråden startas direkt, kan kommenteras ut efter det.
  • report_host är namnet av slaven som rapporteras till master.

Stäng nu av mysql på slaven för de nästkommande stegen.

service mysql stop

Observera att om inställningen för tmpdir på en slav pekar mot en volym där filer raderas vid omstart så kommer replikering misslyckas.

Skapa användare för replikering på master

mysql> create user 'replication'@'192.168.22.%' identified by 'mittSlavLösenord';
mysql> grant replication slave on *.* to 'replication'@'192.168.22.%';

För pacemaker behöver vi även tillåta anslutningar från localhost för replication-användaren, samt ge användaren SUPER-privilegier så den kan befordra och degradera noder.

mysql> grant super, replication client *.* to 'replication'@localhost identified by 'mittSlavLösenord';

Manuell filsynkronisering

Innan replikering kan starta måste båda nodernas mysql ha en identisk datakatalog. Detta har ett antal olika påverkningar.

  • I Debian och Ubuntu skapas en systemanvändare i mysql som heter debian-sys-maint vars lösenord definieras i /etc/mysql/debian.cnf, så den filen måste synkas med master.
  • Metoden som beskrivs här passar bäst för nya system utan så mycket data.
  • Under den manuella filsynkroniseringen så pausas alla skrivningar till master-databasen.

Börja med att starta en ny terminal med en mysql-root-prompt på master.

mysql> flush tables with read lock;
mysql> show master status;
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000018 |      245 |              |                  |
+--------------------+----------+--------------+------------------+

Bemärk att så fort den här mysql-sessionen avslutas så upphör skrivskyddet som vi startade med det första kommandot (flush tables with read lock;) så om det är mycket trafik mot databasen bör man arbeta relativt snabbt. Annars kan man oftast ta det lugnt.

Det andra kommandot (show master status;) visar oss var master är i sina transaktionsloggar just nu. Vi måste senare få slaven att starta sin replikering från den punkten.

Radera först innehållet av datakatalogen på slaven, kom ihåg att tjänsten ej ska vara startad än!

rm -rf /var/lib/mysql/*

Sedan synkar vi över datakatalogen från master till slaven.

rsync -rav /var/lib/mysql linuxlab02:/var/lib/

Glöm nu inte att redigera /etc/mysql/debian.cnf på slaven och se till att den har samma lösenord som motsvarande fil på master.

Starta replikering på slaven

Nu när datakatalogerna på master och slav är identiska kan vi starta mysql på slaven och ställa in replikeringen. Det är nu som direktivet skip-slave-start i slavens /etc/mysql/my.cnf är nödvändigt eftersom vi första gången vill starta slavtråden manuellt.

service mysql start

Starta ett mysql-skal på slaven som root och kör följande kommandon för att ställa in och starta replikeringen.

mysql> change master to master_host='linuxlab01', master_user='replication', master_password='mittSlavLösenord', master_log_file='mariadb-bin.000018', master_log_pos=245;
mysql> start slave;

Notera att värdena kommer från show master status; kommandot vi körde på mastern tidigare, samt lösenordet för replikeringsanvändaren och värdnamnet av master. Dessa kan självklart variera beroende på hur mycket er master har loggat.

Nu ska vi till sist komma ihåg att kommentera bort skip-slave-start direktivet i /etc/mysql/my.cnf, och stänga mysql-skalet vi startade tidigare där vi körde flush tables with read lock; kommandot, så att skrivningar återupptas i databasen.

Kontrollera replikering

Se så att slaven är ansluten till master med lsof.

lsof -ni|grep mysql
mysqld    14035  mysql   14u  IPv4  24614      0t0  TCP *:mysql (LISTEN)
mysqld    14035  mysql   18u  IPv4  25191      0t0  TCP 192.168.22.111:mysql->192.168.22.112:54328 (ESTABLISHED)

Här ser vi en etablerad anslutning, vi kan även bekräfta replikeringstrafik med tcpdump om vi vill.

Än bättre är att jämföra vilken position i replikeringen vardera nod har för tillfället. Först på master genom det kända kommandot show master status;.

Sedan på slaven genom att jämföra det mot innehållet av filen /var/lib/mysql/master.info. Den filen ska visa samma information som kommandot vi körde på master, och informationen ska uppdateras i takt med att masterdatabasen växer och skapar nya logsegment av transaktioner.

Konfigurera HA

Nu har vi fungerande replikering men om den första noden försvinner så finns det inget som säger till vår applikation att använda den andra noden, det finns heller inget som säger till slaven att bli en master och tillåta skrivningar till databasen.

Detta är vad som kallas HA och det ska vi konfigurera nu med hjälp av Pacemaker. Från och med nu, alltså konfigurationen vi gör i CRM, behöver vi bara göra konfigurationen på en av noderna så propageras den ut till resten genom corosync.

VIP-adress med Pacemaker

Först vill vi kunna ansluta till en gemensam ip-adress för att nå databasen, den ip-adressen blir en VIP som kan växlas mellan noder beroende på vilken som är master för tillfället.

Detta är vår första resurs i Pacemaker, den görs i crm-skalet och lagras i en cib. Allt detta är termer som man bör läsa mer om på clusterlabs.org. Jag tänker relativt snabbt gå igenom hur jag personligen skapar dessa resurser.

Det första vi gör är att stänga av STONITH och ignorerar quorum-policy eftersom vi bygger ett kluster med enbart två noder och inget delat filsystem.

crm configure property no-quorum-policy=ignore stonith-enabled=false
crm configure primitive resVIP0 ocf:heartbeat:IPaddr2 params ip=192.168.22.100 op monitor interval=30s

IP-adressen vi angav som parameter blir den VIP som ska anropas av applikationer som använder sig av den replikerade databasen.

Kikar vi på crm_mon nu så ser vi att vår VIP är startad på linuxlab01, vilket betyder att all trafik mot adressen egentligen går mot den noden.

crm_mon -1
============
Last updated: Sun Jan 13 10:52:45 2013
Last change: Sun Jan 13 10:50:28 2013 via cibadmin on linuxlab01
Stack: openais
Current DC: linuxlab01 - partition with quorum
Version: 1.1.6-9971ebba4494012a93c03b40a2c58ec0eb60f50c
2 Nodes configured, 2 expected votes
1 Resources configured.
============

Online: [ linuxlab02 linuxlab01 ]

 resVIP0      (ocf::heartbeat:IPaddr2):       Started linuxlab01

MySQL resurs i Pacemaker

MySQL är en active/standby konfiguration, eller en master/slave konfiguration, för det har vi ett direktiv i CRM som heter just ms (multi-state) och används för att skapa sådana resurser.

Eftersom detta är en lite större konfiguration i CRM så passar jag på att visa ett knep som jag anser vara bra praxis.

Nämligen att göra en kopia av din aktuella cib där ändringarna görs, varje kopia lämnar efter sig en backup av den föregående cib-databasen.

crm
crm(live)# cib new ms20130113
crm(ms20130113)# configure

Nu är vi i samma läge som vi annars använder för att konfigurera en cib, kör vi show kommandot så ser vi den aktuella konfigurationen.

crm(ms20130113)configure# primitive resMySQL ocf:heartbeat:mysql \
> op monitor id="mysql-slave-monitor" role="Slave" interval=60s \                             
> op monitor id="mysql-master-monitor" role="Master" interval=61s \
> params config="/etc/mysql/my.cnf" socket="/var/run/mysqld/mysqld.sock" binary="/usr/bin/mysqld_safe" \
> replication_user="replication" replication_passwd="mittSlavLösenord" \
> test_user="debian-sys-maint" test_passwd="lösenordFrånDebian.cnf" \
> evict_outdated_slaves="false"

Test-kontot i detta fallet ska vara ett med hög behörighet, jag har funnit att debian-sys-maint från /etc/mysql/debian.cnf fungerar lika bra som root.

Det är väldigt viktigt att monitor operationerna för slav och master har olika tidsintervall så att Pacemaker kan skilja på dem.

Sedan skapar vi ms-resursen ovanpå den MySQL-resurs vi precis skapade.

crm(ms20130113)configure# ms msMySQL resMySQL \
> meta master-max=1 master-node-max=1 notify="true" globally-unique="false" target-role="Master"
crm(ms20130113)configure# colocation colVIP_on_MySQL inf: resVIP0 msMySQL:Master
crm(ms20130113)configure# end
There are changes pending. Do you want to commit them? y
WARNING: resMySQL: default timeout 20s for start is smaller than the advised 120
WARNING: resMySQL: default timeout 20s for stop is smaller than the advised 120
WARNING: resMySQL: default timeout 20s for monitor_Master is smaller than the advised 30
crm(ms20130113)# cib commit ms20130113
INFO: commited 'ms20130113' shadow CIB to the cluster

Colocation direktivet anger förenklat att man ska placera resurs A på en nod och sedan placera resurs B där resurs A hamnade. Dessutom anger det att om resurs A inte kan starta så ska inte heller resurs B starta.

De sista raderna visar hur en kopierad cib kan skickas ut till klustrets aktiva cib med cib commit kommandot.

Tyvärr får man vänja sig vid varningarna, servrar som har väldigt mycket last kan t.ex. behöva betydligt högre timeout-värden. Så det är helt beroende på miljön man bygger.

I crm_mon ska man omedelbart se MySQL startas som en master/slave resurs, annars är något fel.

============
Last updated: Sun Jan 13 15:27:31 2013
Last change: Sun Jan 13 14:43:01 2013 via cibadmin on linuxlab01
Stack: openais
Current DC: linuxlab01 - partition with quorum
Version: 1.1.6-9971ebba4494012a93c03b40a2c58ec0eb60f50c
2 Nodes configured, 2 expected votes
3 Resources configured.
============

Online: [ linuxlab02 linuxlab01 ]

 resVIP0      (ocf::heartbeat:IPaddr2):       Started linuxlab01
 Master/Slave Set: msMySQL [resMySQL]
     Masters: [ linuxlab01 ]
     Slaves: [ linuxlab02 ]

Den slutgiltiga konfigurationen kan se ut så här.

node linuxlab01
node linuxlab02 \
      attributes linuxlab01-log-file-resMySQL="mariadb-bin.000017" linuxlab01-log-pos-resMySQL="245"
primitive resMySQL ocf:heartbeat:mysql \
      op monitor interval="60s" role="Slave" \
      op monitor interval="61s" role="Master" \
      params config="/etc/mysql/my.cnf" socket="/var/run/mysqld/mysqld.sock" binary="/usr/bin/mysqld_safe" replication_user="replication" replication_passwd="hemligt" test_user="debian-sys-maint" test_passwd="hemligt" evict_outdated_slaves="false"
primitive resVIP0 ocf:heartbeat:IPaddr2 \
      params ip="192.168.22.100" \
      op monitor interval="30s"
ms msMySQL resMySQL \
      meta master-max="1" master-node-max="1" notify="true" globally-unique="false" target-role="Started" is-managed="true"
colocation colVIP_on_MySQL inf: resVIP0 msMySQL:Master
property $id="cib-bootstrap-options" \
      dc-version="1.1.6-9971ebba4494012a93c03b40a2c58ec0eb60f50c" \
      cluster-infrastructure="openais" \
      expected-quorum-votes="2" \
      no-quorum-policy="ignore" \
      stonith-enabled="false" \
      last-lrm-refresh="1358095932"

Lägga till en ny slav

Vare sig man vill balansera ut sina läsfrågor till fler servrar eller ha mer datasäkerhet så kan det vara bra att veta att det är väldigt lätt att lägga till en ny slav i en sådan här konfiguration.

I stort sett följer man stegen för manuell filsynkronisering av en ny slav som nämndes tidigare. Så fort slaven sedan startar upp in i pacemaker klustret kommer den kännas igen som en nod och automatiskt bli en slav.

============
Last updated: Sun Jan 13 19:35:55 2013
Last change: Sun Jan 13 19:35:18 2013 via crm_attribute on linuxlab02
Stack: openais
Current DC: linuxlab01 - partition with quorum
Version: 1.1.6-9971ebba4494012a93c03b40a2c58ec0eb60f50c
3 Nodes configured, 3 expected votes
4 Resources configured.
============

Online: [ linuxlab02 linuxlab01 linuxlab03 ]

 Master/Slave Set: msMySQL [resMySQL]
     Masters: [ linuxlab01 ]
     Slaves: [ linuxlab02 linuxlab03 ]
 resVIP0      (ocf::heartbeat:IPaddr2):       Started linuxlab01

Failover

Vad händer om master-noden plötsligt försvinner? Det kan vi testa i en virtuell miljö genom att helt enkelt stänga ner den.

Bemärk att suspend i en virtuell miljö kan ge oväntade resultat eftersom den virtuella maskinen kommer ta tillbaka sin VIP så fort den återupptas med resume.

Ta shut down på master-noden samtidigt som crm_mon är igång i en terminal på slav-noden så kommer man se att slavnoden blir omedelbart master och VIP flyttas till slavnoden.

Startar man sedan den gamla master-noden så kommer VIP inte flyttas tillbaka automatiskt och den kommer listas i crm_mon som en slav, men egentligen har ingen replikering startat till den eftersom man manuellt måste synkronisera över filerna från den nya master-noden först.

Kan se ut så här efter att den första noden startats om oväntat.

============
Last updated: Sun Jan 13 15:27:31 2013
Last change: Sun Jan 13 14:43:01 2013 via cibadmin on linuxlab01
Stack: openais
Current DC: linuxlab02 - partition with quorum
Version: 1.1.6-9971ebba4494012a93c03b40a2c58ec0eb60f50c
2 Nodes configured, 2 expected votes
3 Resources configured.
============

Online: [ linuxlab02 linuxlab01 ]

 resVIP0      (ocf::heartbeat:IPaddr2):       Started linuxlab02
 Master/Slave Set: msMySQL [resMySQL]
     Masters: [ linuxlab02 ]
     Slaves: [ linuxlab01 ]

Lägg märke till att den andra noden nu är DC, vilket betyder Designated Co-ordinator.

Återställning efter failover

Vid all manuell återställning när pacemaker är inblandad så är det starkt rekommenderat att ange att den aktuella resursen som ska återställas ska vara unmanaged.

crm resource unmanage msMySQL

Då kommer pacemaker inte försöka lägga sig i och starta resursen när du inte vill det.

För att undvika tjänsteavbrott ska vi nu göra linuxlab01 till slav och låta linuxlab02 förbli master.

Då upprepar vi egentligen samma steg som tidigare, och det är nu som det passar att kunna logga in med ssh som root mellan samtliga noder.

Börja med att stänga ner mysql eftersom det förmodligen har startat när maskinen startades upp.

service mysql stop

Sedan raderar vi hela datakatalogen, gör backup på den om ni känner er osäkra.

rm -rf /var/lib/mysql/*

Pausar alla skrivningar och tar fram master-status från den nya master-noden på linuxlab02.

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status;
+--------------------+----------+--------------+------------------+
| File               | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+--------------------+----------+--------------+------------------+
| mariadb-bin.000047 |      245 |              |                  |
+--------------------+----------+--------------+------------------+

Därefter synkar vi över datakatalogen från den gamla slavnoden, alltså andra hållet denna gången.

rsync -rav linuxlab02:/usr/lib/mysql /usr/lib/

Starta MySQL på slaven.

service mysql start

Anslut till ett mysql-skal på slaven och utför samma steg som vi gjorde tidigare för att etablera en ny slavserver.

MariaDB [(none)]> stop slave;
Query OK, 0 rows affected (0.10 sec)

MariaDB [(none)]> change master to master_host='linuxlab02', master_user='replication', master_password='mittSlavLösenord', master_log_file='mariadb-bin.000047', master_log_pos=245;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> start slave;
Query OK, 0 rows affected (0.00 sec)

Bemärk skillnaderna här, vi måste först stoppa slaven eftersom /etc/mysql/my.cnf inte hade skip-slave-start vid uppstart. Sedan upprepar vi stegen från förr med nya värden som vi hämtat från show master status; kommandot. Till sist startar vi slavtråden.

Nu kan vi avsluta mysql-skalet på master där vi körde flush tables with read lock; och kontrollera replikeringen på vår nya slavserver.

Rutiner

Location, location, location

En Master-roll startar på vilken nod som helst om det inte finns ett location-direktiv i CIB. Så när man vet vilken nod som ska vara Master är det bäst att skriva följande i CRM.

location prefer-msMySQL msMySQL \
      rule $id="MySQL-prefer-linuxlab01" inf: #uname eq linuxlab01

Detta är exakt samma konfiguration som automatiskt läggs till när kommandot crm resource move körs på en resurs.

crm resource move msMySQL linuxlab01

Därför är det viktigt att se över sin cib efter sådana kommandon körts, eftersom den konfigurationen är kvar där tills du tar bort den.

Kända fel

Pacemaker visar slavar som slavar även om deras replikering inte är synkad eller igång. Den enda man kan lita på någorlunda är vilken som är Master. Allt ska tas med en nypa salt och övervakning av replikeringen via t.ex. Nagios är en nödvändighet.

Går inte att använda privat replikeringsnät

Detta är inte nödvändigtvis ett fel men jag hade personligen föredragit att driva all replikeringstrafik över ett privat layer-2 nät. Det går inte så vida inte nodernas värdnamn matchar det privata nätets. För Pacemakers RA kommer använda uname -n kommandot för att ta reda på värdnamnet av master-servern.

Dokumentet Corosync och Pacemaker på Debian rekommenderar ett privat Layer-2 nät för corosyncs multicast-trafik, vilket går bra, men inte för MySQL med nuvarande RA.

Replikationsloggar kan fylla disk vid hög last

Det är inte ett känt fel, mer som något att undvika. Placera replikationsloggarna på en volym med gott om utrymme, helst inte /. Självklart helst en logisk volym som kan utökas.

Se också

teknik/mysql_ha_med_pacemaker.txt · Senast uppdaterad: 2014-01-08 10:18 av stemid