Säkerhetskopiering är avgörande när det gäller datasäkerhet. De är den ultimata katastrofåterställningslösningen - du har inga databasnoder tillgängliga och ditt datacenter kunde bokstavligen ha gått upp i rök, men så länge du har en säkerhetskopia av dina data kan du fortfarande återhämta dig från en sådan situation.
Vanligtvis kommer du att använda säkerhetskopior för att återställa från olika typer av fall:
- Oavsiktlig DROP TABLE eller DELETE utan en WHERE-sats, eller med en WHERE-sats som inte var tillräckligt specifik.
- en databasuppgradering som misslyckas och korrumperar data
- lagringsmediafel/korruption
Räcker det inte med att återställa från säkerhetskopia? Vad måste det vara tidpunkt? Vi måste komma ihåg att en säkerhetskopia är en ögonblicksbild av data som tagits vid en given tidpunkt. Om du tar en säkerhetskopia klockan 1:00 och ett bord togs bort av misstag klockan 11:00, kan du återställa dina data fram till klockan 01:00, men hur är det med ändringar som hände mellan 01:00 och 11:00? Dessa ändringar skulle gå förlorade om du inte kan spela upp ändringar som hände däremellan. Som tur är har MySQL en sådan mekanism för att lagra ändringar - binära loggar. Du kanske vet att de här loggarna används för replikering - MySQL använder dem för att lagra alla ändringar som hände på mastern, och en slav använder dem för att spela upp dessa ändringar och tillämpa dem på dess dataset. Eftersom binloggarna lagrar alla ändringar kan du också använda dem för att spela om trafik. I det här blogginlägget kommer vi att ta en titt på hur ClusterControl kan hjälpa dig att utföra Point-In-Time Recovery (PITR).
Skapa säkerhetskopia som är kompatibel med punkt-i-tid-återställning
Först och främst, låt oss prata om förutsättningar. En värd som du tar säkerhetskopior ifrån måste ha binära loggar aktiverade. Utan dem är PITR inte möjligt. Andra kravet - en värd som du tar säkerhetskopior ifrån bör ha alla binära loggar som krävs för att återställa till en given tidpunkt. Om du använder för aggressiv binär loggrotation kan detta bli ett problem.
Så låt oss se hur man använder den här funktionen i ClusterControl. Först och främst måste du ta en säkerhetskopia som är kompatibel med PITR. Sådan säkerhetskopiering måste vara fullständig, komplett och konsekvent. För xtrabackup, så länge den innehåller fullständig datauppsättning (du inkluderade inte bara en delmängd av scheman), kommer den att vara PITR-kompatibel.
För mysqldump finns det ett alternativ att göra det PITR-kompatibelt. När du aktiverar det här alternativet kommer alla nödvändiga alternativ att konfigureras (du kommer till exempel inte att kunna välja separata scheman att inkludera i dumpningen) och säkerhetskopiering kommer att markeras som tillgänglig för återställning vid tidpunkten.
Återställning i tid från en säkerhetskopia
Först måste du välja en säkerhetskopia att återställa.
Om säkerhetskopieringen är kompatibel med PITR, kommer ett alternativ att presenteras för att utföra en punkt-i-tid-återställning. Du kommer att ha två alternativ för det - "Tidsbaserat" och "Positionsbaserat". Låt oss diskutera skillnaden mellan dessa två alternativ.
”Tidsbaserad” PITR
Med det här alternativet kan du skicka ett datum och en tid som säkerhetskopian ska återställas till. Det kan definieras inom en sekunds upplösning. Det garanterar inte att all data kommer att återställas eftersom, även om du är mycket exakt i att definiera tiden, under en sekund kan flera händelser registreras i den binära loggen. Låt oss säga att du vet att dataförlusten inträffade den 18 april kl. 10:00:01. Du skickar följande datum och tid till formuläret:'2018-04-18 10:00:00'. Tänk på att du bör använda en tid som är baserad på tidszoninställningarna på databasservern som säkerhetskopian skapades på.
Det kan fortfarande hända att dataförlusten inte ens var den första som hände klockan 10:00:01 så några av händelserna kommer att gå förlorade under processen. Låt oss titta på vad det betyder.
Under en sekund kan flera händelser loggas i binlogs. Låt oss överväga ett sådant fall:
10:00:00 - händelser A,B,C,D,E,F
10:00:01 - händelser V,W,X,Y,Z
där X är dataförlusthändelsen. Med en granularitet på en sekund kan du antingen återställa upp till allt som hände klockan 10:00:00 (så upp till F) eller upp till 10:00:01 (upp till Z). Det senare fallet är till ingen nytta eftersom X skulle köras om. I det förra fallet saknar vi V och W.
Det är därför positionsbaserad återställning är mer exakt. Du kan säga "Jag vill återställa upp till W".
Tidsbaserad återställning är den mest exakta du kan få utan att behöva gå till de binära loggarna och definiera den exakta positionen där du vill återställa. Detta leder oss till den andra metoden att göra PITR.
"Positionsbaserad" PITR
Här krävs viss erfarenhet av kommandoradsverktyg för MySQL, nämligen verktyget mysqlbinlog. Å andra sidan kommer du att ha den bästa kontrollen över hur återställningen kommer att göras.
Låt oss gå igenom ett enkelt exempel. Som du kan se i skärmdumpen ovan måste du skicka ett binärt loggnamn och binär loggposition fram till vilken punkt säkerhetskopian ska återställas. För det mesta bör detta vara den sista positionen före dataförlusthändelsen.
Någon körde ett SQL-kommando som resulterade i en allvarlig dataförlust:
mysql> DROP TABLE sbtest1;
Query OK, 0 rows affected (0.02 sec)
Vår ansökan började genast klaga:
sysbench 1.1.0-ecf1191 (using bundled LuaJIT 2.1.0-beta3)
Running the test with following options:
Number of threads: 2
Report intermediate results every 1 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
FATAL: mysql_drv_query() returned error 1146 (Table 'sbtest.sbtest1' doesn't exist) for query 'DELETE FROM sbtest1 WHERE id=5038'
FATAL: `thread_run' function failed: /usr/local/share/sysbench/oltp_common.lua:490: SQL error, errno = 1146, state = '42S02': Table 'sbtest.sbtest1' doesn't exist
Vi har en säkerhetskopia men vi vill återställa all data fram till det ödesdigra ögonblicket. Först och främst antar vi att applikationen inte fungerar så vi kan ignorera alla skrivningar som hände efter DROP TABLE som oviktiga. Om din applikation fungerar till viss del måste du slå samman de återstående ändringarna senare. Ok, låt oss undersöka de binära loggarna för att hitta positionen för DROP TABLE-satsen. Eftersom vi vill undvika att analysera alla binära loggar, låt oss ta reda på vilken position vår senaste säkerhetskopia täckte. Du kan kontrollera det genom att undersöka loggar för den senaste säkerhetskopian och leta efter en rad som liknar denna:
Så vi pratar om filnamnet 'binlog.000008' och positionen '16184120'. Låt oss använda detta som vår utgångspunkt. Låt oss kontrollera vilka binära loggfiler vi har:
[email protected]:~# ls -alh /var/lib/mysql/binlog.*
-rw-r----- 1 mysql mysql 58M Apr 17 08:31 /var/lib/mysql/binlog.000001
-rw-r----- 1 mysql mysql 116M Apr 17 08:59 /var/lib/mysql/binlog.000002
-rw-r----- 1 mysql mysql 379M Apr 17 09:30 /var/lib/mysql/binlog.000003
-rw-r----- 1 mysql mysql 344M Apr 17 10:54 /var/lib/mysql/binlog.000004
-rw-r----- 1 mysql mysql 892K Apr 17 10:56 /var/lib/mysql/binlog.000005
-rw-r----- 1 mysql mysql 74M Apr 17 11:03 /var/lib/mysql/binlog.000006
-rw-r----- 1 mysql mysql 5.2M Apr 17 11:06 /var/lib/mysql/binlog.000007
-rw-r----- 1 mysql mysql 21M Apr 18 11:35 /var/lib/mysql/binlog.000008
-rw-r----- 1 mysql mysql 59K Apr 18 11:35 /var/lib/mysql/binlog.000009
-rw-r----- 1 mysql mysql 144 Apr 18 11:35 /var/lib/mysql/binlog.index
Så, förutom 'binlog.000008' har vi också 'binlog.000009' att undersöka. Låt oss köra kommandot som kommer att konvertera binära loggar till SQL-format från den position vi hittade i backuploggen:
[email protected]:~# mysqlbinlog --start-position='16184120' --verbose /var/lib/mysql/binlog.000008 /var/lib/mysql/binlog.000009 > binlog.out
Vänligen noden "--verbose" krävs för att avkoda radbaserade händelser. Detta krävs inte nödvändigtvis för DROP TABLE vi letar efter, men för andra typer av evenemang kan det behövas.
Låt oss söka i vår utdata efter DROP TABLE-frågan:
[email protected]:~# grep -B 7 -A 1 "DROP TABLE" binlog.out
# at 20885489
#180418 11:24:32 server id 1 end_log_pos 20885554 CRC32 0xb89f2e66 GTID last_committed=38168 sequence_number=38170 rbr_only=no
SET @@SESSION.GTID_NEXT= '7fe29cb7-422f-11e8-b48d-0800274b240e:38170'/*!*/;
# at 20885554
#180418 11:24:32 server id 1 end_log_pos 20885678 CRC32 0xb38a427b Query thread_id=54 exec_time=0 error_code=0
use `sbtest`/*!*/;
SET TIMESTAMP=1524050672/*!*/;
DROP TABLE `sbtest1` /* generated by server */
/*!*/;
I detta exempel kan vi se två händelser. Först, vid positionen 20885489, anger variabeln GTID_NEXT.
# at 20885489
#180418 11:24:32 server id 1 end_log_pos 20885554 CRC32 0xb89f2e66 GTID last_committed=38168 sequence_number=38170 rbr_only=no
SET @@SESSION.GTID_NEXT= '7fe29cb7-422f-11e8-b48d-0800274b240e:38170'/*!*/;
För det andra, på positionen 20885554 är vårt DROP TABLE-evenemang. Detta leder till slutsatsen att vi bör utföra PITR upp till positionen 20885489. Den enda frågan att svara på är vilken binär logg vi pratar om. Vi kan kontrollera det genom att söka efter binlogrotationsposter:
[email protected]:~# grep "Rotate to binlog" binlog.out
#180418 11:35:46 server id 1 end_log_pos 21013114 CRC32 0x2772cc18 Rotate to binlog.000009 pos: 4
Som det tydligt kan ses genom att jämföra datum skedde rotation till binlog.000009 senare, därför vill vi skicka binlog.000008 som binlog-filen i formuläret.
Därefter måste vi bestämma om vi ska återställa säkerhetskopian på klustret eller om vi vill använda extern server för att återställa den. Det här andra alternativet kan vara användbart om du bara vill återställa en delmängd av data. Du kan återställa fullständig fysisk säkerhetskopia på en separat värd och sedan använda mysqldump för att dumpa den saknade data och ladda upp den på produktionsservern.
Tänk på att när du återställer säkerhetskopian på ditt kluster måste du bygga om andra noder än den du återställde. I master-slav-scenariot vill du vanligtvis återställa backup på mastern och sedan bygga om slavar från den.
Som ett sista steg kommer du att se en sammanfattning av åtgärder ClusterControl kommer att vidta.
Slutligen, efter att säkerhetskopian återställts, kommer vi att testa om den saknade tabellen har återställts eller inte:
mysql> show tables from sbtest like 'sbtest1'\G
*************************** 1. row ***************************
Tables_in_sbtest (sbtest1): sbtest1
1 row in set (0.00 sec)
Allt verkar ok, vi lyckades återställa saknade data.
Det sista steget vi måste ta är att återuppbygga vår slav. Observera att det finns ett alternativ att använda en PITR-backup. I exemplet här är detta inte möjligt eftersom slaven skulle replikera DROP TABLE-händelsen och det skulle sluta med att det inte överensstämmer med mastern.