Björn Hansson Precis som i framtiden

28Aug/120

Mysqldump server to server

Some Mysqldump kung fu to copy data between 2 servers. Very handy if you have limited disk space and needs to move lots of data.

From localhost to remote host #2:
mysqldump -v -N -u username -p'password' --databases db1 db2 | mysql -C -h hostnr2 -u root -p'password'

Through SSH:
mysqldump -v -u username -p'password' --databases db-name | ssh -C [email protected] mysql -u root -p'password'

Compress to gzip:
mysqldump -v -u username -p'password' --databases db-name | gzip -9 > dump.sql.gz

Add more -vv to mysqldump for increased verbosity. -C, --compress Use compression in server/client protocol.

Downside if the connection dies, which seems to happen quite a lot over distances, you have to start over from beginning (or specify tables) 🙁

21Aug/121

Mysql replikering genom SSH-tunnel

Replikering kan vara en god idé av flera anledningar, dels som komplement till backup men framförallt för en snabb failover till annan server. Det är ett ganska enkelt och kostnadseffektivt sätt att få redundans på din data. Du kan offloada din primära db-server genom att ta backuperna istället på slaven. Jag har skrivit ner steg för steg hur jag satte upp en replikering genom en SSH-tunnel för att kryptera trafiken. MySQL-version som användes vid tillfället var 5.5.17.

SSH Tunnel (på slaven)

1. Skapa nyckel, ange inget lösenord (bara tryck enter):
ssh-keygen -t rsa

2. Kopiera den publika delen av nyckeln till master-servern:
ssh-copy-id master.host.se
ovan förutsätter att du är inloggad med samma användare på slaven som tar emot nyckeln (kan vara bra idé att inte använda root-usern). Själv har jag flyttat sshd till en annan port än default 22 och då jag inte tillåter root att logga in direkt via ssh så använder jag en annan user och port för detta:
ssh-copy-id -i ~/.ssh/id_rsa.pub "-p portnummer [email protected]"

Får du inte över nyckeln på detta sätt kan du alltid kopiera innehållet manuellt i .ssh/id_rsa.pub och lägga till på masterservern i filen /home/användarnamnet/.ssh/authorized_keys

3. Du ska nu kunna ansluta med ssh till masterservern utan att behöva ange lösenordet:
ssh -p portnummmer [email protected]

4. Sätt upp SSH-tunneln till mastern från slaven
ssh -p portnummer -f [email protected] -L 3305:127.0.0.1:3306 -N
OBS: använd 127.0.0.1 och inte localhost, eftersom mysql tolkar att localhost är en lokal socket.

En tunnel är nu öppen från den lokala porten 3305 till masterserverns mysql-port 3306

5. Då SSH-tunneln kan dö och stängas ner av okänd anledning kan det vara en bra idé att göra så att den startar sig själv om det händer, lägg till följande cronjobb:
* * * * * nc -z localhost 3305 > /dev/null || ssh -p portnummer -f [email protected] -L 3305:127.0.0.1:3306 -N
ovan gör att nc varje minut kollar om ssh lyssnar på port 3305, om inte så öppnas tunneln på nytt.

6. Kontrollera att allt fungerar som det ska, anslut till masterns mysql från slaven genom tunneln:
mysql -h 127.0.0.1 -P 3305 -uUSER -p
ange lösenordet för usern du ansluter med till mysql och du ska vara inne

MYSQL-Replikering

Varje serverpart i en replikering måste ha ett unikt server-id. Detta sätts i mysql confen (default /etc/my.cnf)
Min master får: server-id=1 och slaven: server-id=2

fler parametrar på mastern:

# binary logging - not required for slaves, but recommended
log-bin=/var/log/mysql/mysql-bin.log # i denna fil loggar mastern allt som slaven ska replikera, det fysiska filnamnet på disk kommer bli i stil med mysql-bin.000001 osv. /var/log/mysql bör ägas av mysql-usern, med rättigheter 700.

# Jag behövde även sätta basedir:
basedir=/usr/local/mysql

# binary logging format - mixed recommended
binlog_format=mixed

# synchronize binary log to disk after every N writes to the binary log. 1 = safest but slowest.
sync_binlog=1

såvida du inte har en _extremt_ välbesökt applikation blir 1 bra. Om det är ytterst viktigt att minimera dataförlust vid replikering (och använder transactions) så kan det vara en idé att aktivera Semisynkron replikering (mysql doc). Då bekräftar slaven att varje transaktion verkligen blir utförd och skriven till sin lokala logg, detta skapar dock en tillfällig låsning på mastern och rekommenderas inte om det är mycket latency mellan master och slav, t.ex. vid olika geografiska platser.

Motsvarande på slaven

basedir=/usr/local/mysql
server-id=2
sync_binlog=1
# binary logging - not required for slaves, but recommended (kan vara bra om man vid en failover vill låta slaven bli ny master).
log-bin=mysql-bin
binlog_format=mixed

# relay log (slavens lokala logg som håller reda på var den är i replikeringsprocessen)
relay-log=mysqld-relay-bin

# slavens namn om man vill kunna se på mastern vilka slavar som är anslutna
report-host=slave1

# följande kan vara en bra idé så att inte replikeringen startar direkt vid uppstart, sätt till false när allt är klart och snurrar.
skip-slave-start=true

Skapa en user för replikering, vi behöver en user på mastern som slaven ansluter med:
CREATE USER 'repuser'@'127.0.0.1' IDENTIFIED BY 'hemligtlösenord';
GRANT REPLICATION SLAVE ON *.* TO 'repuser'@'127.0.0.1';
FLUSH PRIVILEGES;

Då har vi confat färdigt mysql och de är nu redo för replikering. Dock har vi säkert redan data på mastern som först behöver flyttas till slaven, detta gör vi med en snapshot (mysqldump) och ett positions-id på var vi är i masterns binary-log. För att undvika att data förändras under dumpningen måste vi sätta ett read-lock på alla tabeller. Starta om masterns mysqld för att påbörja binloggning och se att det fungerar med show master status; (position ska öka om där är aktivitet på db).

# Replication howto mysqldump
Anslut till masterns mysql konsol och utför låsning:
mysql> FLUSH TABLES WITH READ LOCK;
Invänta svar på låsning, detta kan ta några minuter i vissa fall.
Query OK, 0 rows affected (1 min 31.50 sec)
låsningen är i effekt, LÄMNA INTE KONSOLLEN FÖRRÄN ALLT ÄR KLART, då släpps nämligen låsningen. Om du har startat om mysql tidigare efter conf så har den redan börjat bin-logga och du kan då se vilken position den är på mysql> SHOW MASTER STATUS \G;
*************************** 1. row ***************************
File: mysql-bin.000001
Position: 178
Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.00 sec)

# För att radera masterns binlogg och börja om kan du köra
mysql> RESET MASTER;
GÖR INTE DETTA när replikeringen sedan är igång och fungerar, eftersom slaven då inte har en aning längre vad som ska replikeras. Alla binloggar raderas och position bör bli 0 eller ett lågt värde. Om låsningen fungerar som den ska så ska inte positionen förändras, kontrollera detta genom att köra show master status; några gånger. Kan vara en bra idé att stänga ner sådant som använder mysql, i mitt fall stängde jag ner httpd, crond, monit, screens etc.

Kör nu mysqldump i shellet (i en annan session då).Du kan självklart även välja specifika databaser om du inte vill replikera allt, eller specifika tabeller i en databas. Se manualen för mer info.
shell> mysqldump --all-databases --master-data >dbdump.db

När dumpen är klar noterar du positionen på binloggen, om du körde en reset bör denna siffra vara ganska låg
mysql> UNLOCK TABLES;
mastern kan nu fortsätta arbeta vidare medan vi fortsätter med slaven.

Flytta över dumpen till slaven med t.ex. SCP (kan vara en bra idé att komprimera dumpen först om det är mycket data).
scp dbdump.db [email protected]:.
Importera dumpen:
mysql -u root -p < dbdump.db

# confa slaven med masterns uppgifter:
mysql>
RESET SLAVE;
CHANGE MASTER TO
MASTER_HOST='127.0.0.1',
MASTER_PORT=3305,
MASTER_USER='repuser',
MASTER_PASSWORD='hemligtlösenord',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=positionen_som_du_noterat;

MASTER_LOG_FILE ska vara samma som du får fram med show master status; på mastern.

# Starta slavens replikering!
START SLAVE;

# kolla så att det fungerar:
SHOW SLAVE STATUS \G;

Du kan resetta slavens egna master-binlogg (för att frigöra det som ev. loggats vid importen) om du nu valde att slaven ska masterlogga:
RESET MASTER;
kör detta på SLAVEN ENDAST, annars får du göra om alltihop 🙂

Alles klar. Det kan vara en bra idé sen att sätta en monitor så man vet att replikeringen verkligen fungerar och inte lägger av. Jag använder själv perconas heartbeat för detta.