sql >> Database >  >> RDS >> Mysql

Hoe u uw MySQL-instanties kunt laten mislukken of crashen voor testen

U kunt op meerdere manieren een MySQL-database verwijderen. Enkele voor de hand liggende manieren zijn om de host uit te schakelen, de stroomkabel eruit te trekken of het mysqld-proces hard te beëindigen met SIGKILL om een ​​onrein MySQL-afsluitgedrag te simuleren. Maar er zijn ook minder subtiele manieren om je MySQL-server opzettelijk te laten crashen en vervolgens te kijken wat voor soort kettingreactie het veroorzaakt. Waarom zou je dit willen doen? Mislukking en herstel kunnen veel hoekgevallen hebben, en het begrijpen ervan kan het verrassingselement helpen verminderen wanneer er dingen gebeuren in de productie. In het ideale geval wilt u storingen in een gecontroleerde omgeving simuleren en vervolgens databasefailoverprocedures ontwerpen en testen.

Er zijn verschillende gebieden in MySQL die we kunnen aanpakken, afhankelijk van hoe je wilt dat het faalt of crasht. U kunt de tabelruimte beschadigen, de MySQL-buffers en caches overlopen, de bronnen beperken om de server uit te hongeren en ook rommelen met machtigingen. In deze blogpost laten we je enkele voorbeelden zien van hoe je een MySQL-server crasht in een Linux-omgeving. Sommigen van hen zouden geschikt zijn voor b.v. Amazon RDS-instanties, waar u geen toegang zou hebben tot de onderliggende host.

Dood, dood, dood, sterf, sterf, sterf

De gemakkelijkste manier om een ​​MySQL-server te laten mislukken, is door simpelweg het proces of de host te beëindigen en MySQL niet de kans te geven om netjes af te sluiten. Om een ​​mysqld-crash te simuleren, stuurt u signaal 4, 6, 7, 8 of 11 naar het proces:

$ kill -11 $(pidof mysqld)

Als u naar het MySQL-foutlogboek kijkt, ziet u de volgende regels:

11:06:09 UTC - mysqld got signal 11 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
Attempting to collect some information that could help diagnose the problem.
As this is a crash and something is definitely wrong, the information
collection process might fail.
..
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...

Je kunt ook kill -9 (SIGKILL) gebruiken om het proces onmiddellijk te beëindigen. Meer details over het Linux-signaal zijn hier te vinden. Als alternatief kunt u een gemene manier aan de hardwarekant gebruiken, zoals het lostrekken van de stroomkabel, het indrukken van de harde resetknop of het gebruik van een hekwerk naar STONITH.

OOM activeren

Populaire MySQL in de cloud-aanbiedingen zoals Amazon RDS en Google Cloud SQL hebben geen eenvoudige manier om ze te laten crashen. Ten eerste omdat u geen toegang op OS-niveau tot de database-instantie krijgt, en ten tweede omdat de provider een eigen gepatchte MySQL-server gebruikt. Een manier is om een ​​aantal buffers over te laten lopen, en de out-of-memory (OOM) manager het MySQL-proces te laten stoppen.

U kunt de grootte van de sorteerbuffer vergroten tot iets dat groter is dan wat het RAM aankan, en een aantal mysql-sorteerquery's opnemen tegen de MySQL-server. Laten we een tabel met 10 miljoen rijen maken met sysbench op onze Amazon RDS-instantie, zodat we een enorme sortering kunnen bouwen:

$ sysbench \
--db-driver=mysql \
--oltp-table-size=10000000 \
--oltp-tables-count=1 \
--threads=1 \
--mysql-host=dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com \
--mysql-port=3306 \
--mysql-user=rdsroot \
--mysql-password=password \
/usr/share/sysbench/tests/include/oltp_legacy/parallel_prepare.lua \
run

Wijzig de sort_buffer_size naar 5G (onze testinstantie is db.t2.micro - 1GB, 1vCPU) door naar Amazon RDS Dashboard -> Parameter Groups -> Create Parameter Group -> specificeer de groepsnaam -> Edit Parameters -> kies "sort_buffer_size" en specificeer de waarde als 5368709120.

Pas de parametergroepwijzigingen toe door naar Instances -> Instance Action -> Modify -> Database Options -> Database Parameter Group -> te gaan en onze nieuw gemaakte parametergroep te kiezen. Start vervolgens de RDS-instantie opnieuw op om de wijzigingen toe te passen.

Eenmaal omhoog, verifieer de nieuwe waarde van sort_buffer_size :

MySQL [(none)]> select @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
|         5368709120 |
+--------------------+

Vuur vervolgens 48 eenvoudige zoekopdrachten af ​​die moeten worden gesorteerd van een klant:

$ for i in {1..48}; do (mysql -urdsroot -ppassword -h dbtest.cdw9q2wnb00s.ap-tokyo-1.rds.amazonaws.com -e 'SELECT * FROM sbtest.sbtest1 ORDER BY c DESC >/dev/null &); done

Als u het bovenstaande op een standaardhost uitvoert, zult u merken dat de MySQL-server wordt beëindigd en kunt u de volgende regels zien verschijnen in de syslog of dmesg van het besturingssysteem:

[164199.868060] Out of memory: Kill process 47060 (mysqld) score 847 or sacrifice child
[164199.868109] Killed process 47060 (mysqld) total-vm:265264964kB, anon-rss:3257400kB, file-rss:0kB

Met systemd wordt MySQL of MariaDB automatisch opnieuw opgestart, net als Amazon RDS. U kunt zien dat de uptime voor onze RDS-instantie wordt teruggezet naar 0 (onder mysqladmin-status) en dat de waarde voor 'Laatste hersteltijd' (onder RDS-dashboard) wordt bijgewerkt tot het moment waarop deze uitvalt.

De gegevens bederven

InnoDB heeft zijn eigen systeemtabelruimte om datadictionary, buffers en rollback-segmenten op te slaan in een bestand met de naam ibdata1. Het slaat ook de gedeelde tablespace op als je innodb_file_per_table niet configureert (standaard ingeschakeld in MySQL 5.6.6+). We kunnen dit bestand gewoon op nul zetten, een schrijfbewerking sturen en tabellen leegmaken om mysqld te laten crashen:

# empty ibdata1
$ cat /dev/null > /var/lib/mysql/ibdata1
# send a write
$ mysql -uroot -p -e 'CREATE TABLE sbtest.test (id INT)'
# flush tables
$ mysql -uroot -p -e 'FLUSH TABLES WITH READ LOCK; UNLOCK TABLES'

Nadat u een schrijven hebt verzonden, zult u in het foutenlogboek het volgende opmerken:

2017-11-15T06:01:59.345316Z 0 [ERROR] InnoDB: Tried to read 16384 bytes at offset 98304, but was only able to read 0
2017-11-15T06:01:59.345332Z 0 [ERROR] InnoDB: File (unknown): 'read' returned OS error 0. Cannot continue operation
2017-11-15T06:01:59.345343Z 0 [ERROR] InnoDB: Cannot continue operation.

Op dit punt blijft mysql hangen omdat het geen bewerking kan uitvoeren, en na het doorspoelen krijgt u "mysqld got signal 11"-regels en mysqld wordt afgesloten. Om op te ruimen, moet u de beschadigde ibdata1 en ib_logfile* verwijderen omdat de logbestanden voor opnieuw uitvoeren niet kunnen worden gebruikt met een nieuwe systeemtabelruimte die bij de volgende herstart door mysqld wordt gegenereerd. Gegevensverlies wordt verwacht.

Voor MyISAM-tabellen kunnen we rommelen met .MYD (MyISAM-gegevensbestand) en .MYI (MyISAM-index) onder de MySQL-datadir. Bijvoorbeeld, het volgende commando vervangt elk voorkomen van string "F" door "9" in een bestand:

$ replace F 9 -- /var/lib/mysql/sbtest/sbtest1.MYD

Stuur vervolgens enkele schrijfacties (bijv. met sysbench) naar de doeltabel en voer de flushing uit:

mysql> FLUSH TABLE sbtest.sbtest1;

Het volgende zou in het MySQL-foutlogboek moeten verschijnen:

2017-11-15T06:56:15.021564Z 448 [ERROR] /usr/sbin/mysqld: Incorrect key file for table './sbtest/sbtest1.MYI'; try to repair it
2017-11-15T06:56:15.021572Z 448 [ERROR] Got an error from thread_id=448, /export/home/pb2/build/sb_0-24964902-1505318733.42/rpm/BUILD/mysql-5.7.20/mysql-5.7.20/storage/myisam/mi_update.c:227

De MyISAM-tabel wordt gemarkeerd als gecrasht en het uitvoeren van de instructie REPAIR TABLE is nodig om deze weer toegankelijk te maken.

De bronnen beperken

We kunnen ook de resourcelimiet van het besturingssysteem toepassen op ons mysqld-proces, bijvoorbeeld het aantal open bestandsdescriptors. Door de variabele open_file_limit te gebruiken (standaard is 5000) kan mysqld bestandsdescriptors reserveren met de opdracht setrlimit(). U kunt deze variabele relatief klein instellen (net genoeg om mysqld op te starten) en vervolgens meerdere query's naar de MySQL-server sturen totdat deze de limiet bereikt.

Als mysqld op een systemd-server draait, kunnen we het instellen in het systemd unit-bestand op /usr/lib/systemd/system/mysqld.service, en de volgende waarde wijzigen in iets lager (systemd-standaard is 6000):

# Sets open_files_limit
LimitNOFILE = 30

Pas de wijzigingen toe op systemd en start de MySQL-server opnieuw:

$ systemctl daemon-reload
$ systemctl restart mysqld

Begin dan met het verzenden van nieuwe verbindingen/query's die in verschillende databases en tabellen tellen, zodat mysqld meerdere bestanden moet openen. U zult de volgende fout opmerken:

2017-11-16T04:43:26.179295Z 4 [ERROR] InnoDB: Operating system error number 24 in a file operation.
2017-11-16T04:43:26.179342Z 4 [ERROR] InnoDB: Error number 24 means 'Too many open files'
2017-11-16T04:43:26.179354Z 4 [Note] InnoDB: Some operating system error numbers are described at http://dev.mysql.com/doc/refman/5.7/en/operating-system-error-codes.html
2017-11-16T04:43:26.179363Z 4 [ERROR] InnoDB: File ./sbtest/sbtest9.ibd: 'open' returned OS error 124. Cannot continue operation
2017-11-16T04:43:26.179371Z 4 [ERROR] InnoDB: Cannot continue operation.
2017-11-16T04:43:26.372605Z 0 [Note] InnoDB: FTS optimize thread exiting.
2017-11-16T04:45:06.816056Z 4 [Warning] InnoDB: 3 threads created by InnoDB had not exited at shutdown!

Op dit punt, wanneer de limiet is bereikt, zal MySQL bevriezen en kan het geen enkele bewerking meer uitvoeren. Wanneer u probeert verbinding te maken, ziet u na een tijdje het volgende:

$ mysql -uroot -p
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104

Knoeien met machtigingen

Het mysqld-proces wordt uitgevoerd door de "mysql" -gebruiker, wat betekent dat alle bestanden en directory's die het nodig heeft, eigendom zijn van mysql-gebruiker/groep. Door de toestemming en eigendom te verknoeien, kunnen we de MySQL-server onbruikbaar maken:

$ chown root:root /var/lib/mysql
$ chmod 600 /var/lib/mysql

Genereer wat belastingen naar de server en maak vervolgens verbinding met de MySQL-server en spoel alle tabellen naar schijf:

mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;

Op dit moment is mysqld nog steeds actief, maar het is een beetje nutteloos. Je hebt er toegang toe via een mysql-client, maar je kunt geen enkele bewerking uitvoeren:

mysql> SHOW DATABASES;
ERROR 1018 (HY000): Can't read dir of '.' (errno: 13 - Permission denied)

Stel de juiste rechten in om de rommel op te ruimen:

$ chown mysql:mysql /var/lib/mysql
$ chmod 750 /var/lib/mysql
$ systemctl restart mysqld

Vergrendel het

SPOELTAFEL MET READ LOCK (FTWRL) kan onder een aantal omstandigheden destructief zijn. Zoals bijvoorbeeld in een Galera-cluster waar alle knooppunten schrijfbewerkingen kunnen verwerken, kunt u deze instructie gebruiken om het cluster vanuit een van de knooppunten te vergrendelen. Deze instructie stopt gewoon andere query's die door mysqld moeten worden verwerkt tijdens het leegmaken totdat de vergrendeling wordt vrijgegeven, wat erg handig is voor back-upprocessen (MyISAM-tabellen) en momentopnamen van bestandssystemen.

Hoewel deze actie uw databaseserver niet zal crashen of uitschakelen tijdens de vergrendeling, kan het gevolg enorm zijn als de sessie die de vergrendeling vasthoudt, deze niet vrijgeeft. Om dit te proberen:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit

Stuur dan een heleboel nieuwe vragen naar de mysqld totdat deze de max_connections . bereikt waarde. Het is duidelijk dat je dezelfde sessie als de vorige niet terug kunt krijgen als je eenmaal weg bent. Het slot zal dus oneindig actief zijn en de enige manier om het slot te ontgrendelen is door de query te beëindigen door een andere SUPER privilege gebruiker (met behulp van een andere sessie). Of stop het mysqld-proces zelf, of voer een harde reboot uit.

Disclaimer

Deze blog is geschreven om alternatieven te bieden voor sysadmins en DBA's om faalscenario's met MySQL te simuleren. Probeer deze niet op uw productieserver :-)


  1. MySQL-prestaties optimaliseren met MySQLTuner

  2. 3 manieren om het jaar uit een datum te extraheren in SQL Server (T-SQL)

  3. Problemen met MySQL-definer oplossen

  4. ACOS() Functie in Oracle