Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да провалите или сринете вашите MySQL екземпляри за тестване

Можете да премахнете MySQL база данни по няколко начина. Някои очевидни начини са да изключите хоста, да издърпате захранващия кабел или силно да убиете процеса на mysqld със SIGKILL, за да симулирате нечисто поведение при изключване на MySQL. Но има и по-малко фини начини за умишлено срива на вашия MySQL сървър и след това да видите какъв вид верижна реакция задейства. Защо бихте искали да направите това? Неуспехът и възстановяването могат да имат много ъглови случаи и разбирането им може да помогне за намаляване на елемента на изненада, когато нещата се случват в производството. В идеалния случай бихте искали да симулирате неуспехи в контролирана среда и след това да проектирате и тествате процедури за преодоляване на срив в базата данни.

Има няколко области в MySQL, с които можем да се справим, в зависимост от това как искате да се провали или да се срине. Можете да повредите пространството за таблици, да препълвате MySQL буферите и кеша, да ограничите ресурсите за гладуване на сървъра и също така да се забърквате с разрешенията. В тази публикация в блога ще ви покажем някои примери за това как да сринете MySQL сървър в Linux среда. Някои от тях биха били подходящи за напр. Amazon RDS екземпляри, където няма да имате достъп до основния хост.

Убий, убий, убий, умри, умри, умри

Най-лесният начин да повредите MySQL сървър е просто да убиете процеса или хоста и да не дадете на MySQL шанс да извърши грациозно изключване. За да симулирате срив на mysqld, просто изпратете сигнал 4, 6, 7, 8 или 11 към процеса:

$ kill -11 $(pidof mysqld)

Когато разглеждате регистъра на грешките на MySQL, можете да видите следните редове:

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...

Можете също да използвате kill -9 (SIGKILL), за да прекратите процеса незабавно. Повече подробности за Linux сигнала можете да намерите тук. Като алтернатива можете да използвате по-лош начин от страна на хардуера, като издърпване на захранващия кабел, натискане на бутона за твърдо нулиране или използване на ограждащо устройство за STONITH.

Задействане на OOM

Популярните MySQL в облачните предложения като Amazon RDS и Google Cloud SQL нямат лесен начин да ги сринат. Първо, защото няма да получите никакъв достъп на ниво операционна система до екземпляра на базата данни, и второ, защото доставчикът използва собствен пачкан MySQL сървър. Един от начините е да препълните някои буфери и да оставите мениджъра на липсата на памет (OOM) да изхвърли процеса на MySQL.

Можете да увеличите размера на буфера за сортиране до нещо по-голямо от това, което RAM паметта може да поеме, и да застреляте редица заявки за сортиране на mysql срещу MySQL сървъра. Нека създадем таблица с 10 милиона реда, използвайки sysbench на нашия екземпляр на Amazon RDS, за да можем да изградим огромно сортиране:

$ 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

Променете sort_buffer_size към 5G (нашият тестов екземпляр е db.t2.micro - 1GB, 1vCPU), като отидете на Amazon RDS Dashboard -> Групи параметри -> Създаване на група параметри -> посочете името на групата -> Редактиране на параметри -> изберете "sort_buffer_size" и посочете стойността като 5368709120.

Приложете промените в групата параметри, като отидете на Инстанции -> Действие на екземпляра -> Промяна -> Опции на базата данни -> Група параметри на базата данни -> и изберете нашата новосъздадена група параметри. След това рестартирайте RDS екземпляра, за да приложите промените.

След като се появи, проверете новата стойност на sort_buffer_size :

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

След това задействайте 48 прости заявки, които изискват сортиране от клиент:

$ 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

Ако стартирате горното на стандартен хост, ще забележите, че MySQL сървърът ще бъде прекратен и ще видите следните редове да се появяват в syslog или dmesg на операционната система:

[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

С systemd MySQL или MariaDB ще се рестартира автоматично, както и Amazon RDS. Можете да видите, че времето за работа за нашия RDS екземпляр ще бъде нулирано обратно на 0 (при състояние на mysqladmin), а стойността „Последно време за възстановяване“ (под RDS Dashboard) ще бъде актуализирана до момента, в който е паднал.

Повреда на данните

InnoDB има собствено системно пространство за таблици за съхранение на речник на данни, буфери и сегменти за връщане във файл с име ibdata1. Той също така съхранява споделеното пространство за таблици, ако не конфигурирате innodb_file_per_table (разрешено по подразбиране в MySQL 5.6.6+). Можем просто да нулираме този файл, да изпратим операция за запис и да изчистим таблиците за срив на mysqld:

# 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'

След като изпратите запис, в регистъра на грешките ще забележите:

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.

В този момент mysql ще увисне, защото не може да извърши никаква операция и след изчистването ще получите редове "mysqld got signal 11" и mysqld ще се изключи. За да почистите, трябва да премахнете повредените ibdata1, както и ib_logfile*, тъй като регистрационните файлове за повторно изпълнение не могат да се използват с ново системно пространство за таблици, което ще бъде генерирано от mysqld при следващото рестартиране. Очаква се загуба на данни.

За MyISAM таблици можем да се забърквам с .MYD (файл с данни MyISAM) и .MYI (индекс на MyISAM) под MySQL datadir. Например, следната команда замества всяко появяване на низ "F" с "9" във файл:

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

След това изпратете някои записи (например с помощта на sysbench) до целевата таблица и извършете изчистването:

mysql> FLUSH TABLE sbtest.sbtest1;

Следното трябва да се появи в регистъра за грешки на MySQL:

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

Таблицата MyISAM ще бъде маркирана като повредена и е необходимо да се изпълнява оператор REPAIR TABLE, за да стане отново достъпна.

Ограничаване на ресурсите

Можем също да приложим ограничението на ресурсите на операционната система към нашия mysqld процес, например брой отворени файлови дескриптори. Използването на променлива open_file_limit (по подразбиране е 5000) позволява на mysqld да резервира файлови дескриптори с помощта на команда setrlimit(). Можете да зададете тази променлива сравнително малка (само достатъчно, за да стартира mysqld) и след това да изпратите множество заявки към MySQL сървъра, докато достигне лимита.

Ако mysqld работи на systemd сървър, можем да го зададем във файла systemd unit, намиращ се в /usr/lib/systemd/system/mysqld.service, и да променим следната стойност на нещо по-ниско (systemd по подразбиране е 6000):

# Sets open_files_limit
LimitNOFILE = 30

Приложете промените към systemd и рестартирайте MySQL сървъра:

$ systemctl daemon-reload
$ systemctl restart mysqld

След това започнете да изпращате нови връзки/заявки, които се броят в различни бази данни и таблици, така че mysqld да отваря множество файлове. Ще забележите следната грешка:

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!

В този момент, когато се достигне ограничението, MySQL ще замръзне и няма да може да извърши никаква операция. Когато се опитвате да се свържете, след известно време ще видите следното:

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

Забърквам се с разрешенията

Процесът mysqld се изпълнява от потребител "mysql", което означава, че всички файлове и директория, до които трябва да има достъп, са собственост на потребител/група на mysql. Като се объркаме с разрешението и собствеността, можем да направим MySQL сървъра безполезен:

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

Генерирайте някои натоварвания към сървъра и след това се свържете с MySQL сървъра и изтрийте всички таблици на диск:

mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;

В този момент mysqld все още работи, но е някак безполезен. Можете да получите достъп до него чрез mysql клиент, но не можете да извършвате никакви операции:

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

За да почистите бъркотията, задайте правилните разрешения:

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

Заключете го

FLUSH TABLE С ЧЕТЕНЕ LOCK (FTWRL) може да бъде разрушителна при редица условия. Както например в клъстер на Galera, където всички възли могат да обработват записи, можете да използвате този израз, за ​​да заключите клъстера от един от възлите. Това изявление просто спира други заявки, които да бъдат обработени от mysqld по време на изчистването, докато заключването не бъде освободено, което е много удобно за архивиране на процеси (MyISAM таблици) и моментни снимки на файловата система.

Въпреки че това действие няма да се срине или да свали вашия сървър на база данни по време на заключването, последствията могат да бъдат огромни, ако сесията, която държи заключването, не го освободи. За да опитате това, просто:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit

След това изпратете куп нови заявки към mysqld, докато достигне max_connections стойност. Очевидно не можете да се върнете към същата сесия като предишната, след като сте навън. Така че заключването ще работи безкрайно и единственият начин да освободите заключването е като убиете заявката от друг потребител с SUPER привилегия (използвайки друга сесия). Или убийте самия процес на mysqld или извършете твърдо рестартиране.

Отказ от отговорност

Този блог е написан, за да даде алтернативи на системните администратори и DBA за симулиране на сценарии на отказ с MySQL. Не ги опитвайте на вашия производствен сървър :-)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL REPLACE() – Заменете всички екземпляри на подниз с друг низ

  2. Предупреждение:mysqli_query() очаква параметър 1 да бъде mysqli, ресурс е даден

  3. Примери за MySQL SOUNDEX().

  4. MySQL, актуализирайте множество таблици с една заявка

  5. Попълнете падащо меню от mySQL таблица в PHP