Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak zawieść lub zawiesić instancje MySQL w celach testowych?

Bazę danych MySQL można usunąć na wiele sposobów. Niektóre oczywiste sposoby to wyłączenie hosta, odłączenie kabla zasilającego lub twarde zabicie procesu mysqld za pomocą SIGKILL, aby zasymulować nieczyste zachowanie podczas zamykania MySQL. Ale są też mniej subtelne sposoby na celowe zawieszenie serwera MySQL, a następnie sprawdzenie, jaki rodzaj reakcji łańcuchowej wywołuje. Dlaczego chcesz to zrobić? Awarie i powrót do zdrowia mogą mieć wiele przypadków krytycznych, a ich zrozumienie może pomóc w zmniejszeniu elementu zaskoczenia, gdy coś się dzieje w produkcji. Najlepiej byłoby symulować awarie w kontrolowanym środowisku, a następnie zaprojektować i przetestować procedury przełączania awaryjnego bazy danych.

Istnieje kilka obszarów w MySQL, którymi możemy się zająć, w zależności od tego, w jaki sposób chcesz, aby się nie powiódł lub uległ awarii. Możesz uszkodzić przestrzeń tabel, przepełnić bufory i pamięci podręczne MySQL, ograniczyć zasoby, aby zagłodzić serwer, a także zadzierać z uprawnieniami. W tym poście na blogu pokażemy kilka przykładów awarii serwera MySQL w środowisku Linux. Niektóre z nich nadawałyby się m.in. Instancje Amazon RDS, w których nie miałbyś dostępu do podstawowego hosta.

Zabij, zabij, zabij, zgiń, zgiń, zgiń

Najłatwiejszym sposobem na awarię serwera MySQL jest po prostu zabicie procesu lub hosta i nie danie MySQL szansy na bezpieczne zamknięcie. Aby zasymulować awarię mysqld, po prostu wyślij sygnał 4, 6, 7, 8 lub 11 do procesu:

$ kill -11 $(pidof mysqld)

Patrząc na dziennik błędów MySQL, możesz zobaczyć następujące wiersze:

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

Możesz także użyć kill -9 (SIGKILL), aby natychmiast zabić proces. Więcej szczegółów na temat sygnału Linuksa można znaleźć tutaj. Alternatywnie możesz użyć bardziej złośliwego sposobu po stronie sprzętu, takiego jak odłączenie kabla zasilającego, naciśnięcie przycisku twardego resetu lub użycie urządzenia ogrodzeniowego do STONITH.

Wyzwalanie OOM

Popularne rozwiązania MySQL w chmurze, takie jak Amazon RDS i Google Cloud SQL, nie mają prostego sposobu na ich awarię. Po pierwsze dlatego, że nie uzyskasz dostępu do instancji bazy danych na poziomie systemu operacyjnego, a po drugie dlatego, że dostawca używa zastrzeżonego, załatanego serwera MySQL. Jednym ze sposobów jest przepełnienie niektórych buforów i pozwolenie menedżerowi braku pamięci (OOM) na wyrzucenie procesu MySQL.

Możesz zwiększyć rozmiar bufora sortowania do wartości większej niż ta, którą może obsłużyć pamięć RAM, i wykonać kilka zapytań sortujących mysql do serwera MySQL. Stwórzmy tabelę z 10 milionami wierszy za pomocą sysbench na naszej instancji Amazon RDS, abyśmy mogli zbudować ogromny sortowanie:

$ 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

Zmień sort_buffer_size do 5G (nasza instancja testowa to db.t2.micro - 1GB, 1vCPU) przechodząc do Amazon RDS Dashboard -> Parameter Groups -> Create Parameter Group -> podaj nazwę grupy -> Edit Parameters -> wybierz "sort_buffer_size" i określ wartość 5368709120.

Zastosuj zmiany grupy parametrów przechodząc do Instances -> Instance Action -> Modify -> Database Options -> Database Parameter Group -> i wybierz naszą nowo utworzoną grupę parametrów. Następnie zrestartuj instancję RDS, aby zastosować zmiany.

Po zakończeniu zweryfikuj nową wartość sort_buffer_size :

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

Następnie uruchom 48 prostych zapytań, które wymagają sortowania od klienta:

$ 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

Jeśli uruchomisz powyższe na standardowym hoście, zauważysz, że serwer MySQL zostanie zamknięty i zobaczysz następujące wiersze pojawiające się w dzienniku systemowym lub dmesg systemu operacyjnego:

[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

W przypadku systemd MySQL lub MariaDB zostaną automatycznie zrestartowane, podobnie jak Amazon RDS. Możesz zobaczyć, że czas pracy naszej instancji RDS zostanie zresetowany do 0 (w statusie mysqladmin), a wartość „Ostatni czas przywracania” (w panelu RDS Dashboard) zostanie zaktualizowana do momentu awarii.

Uszkodzenie danych

InnoDB ma swój własny systemowy obszar tabel do przechowywania słownika danych, buforów i segmentów wycofywania w pliku o nazwie ibdata1. Przechowuje również współdzielony obszar tabel, jeśli nie skonfigurujesz innodb_file_per_table (domyślnie włączone w MySQL 5.6.6+). Możemy po prostu wyzerować ten plik, wysłać operację zapisu i opróżnić tabele, aby zawiesić 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'

Po wysłaniu zapisu w dzienniku błędów zauważysz:

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.

W tym momencie mysql zawiesi się, ponieważ nie może wykonać żadnej operacji, a po spłukaniu otrzymasz wiersze "mysqld dostał sygnał 11" i mysqld się wyłączy. Aby wyczyścić, musisz usunąć uszkodzony ibdata1, a także ib_logfile*, ponieważ pliki dziennika ponownego wykonania nie mogą być używane z nowym obszarem tabel systemowych, który zostanie wygenerowany przez mysqld przy następnym restarcie. Spodziewana jest utrata danych.

W przypadku tabel MyISAM możemy bawić się plikami .MYD (plik danych MyISAM) i .MYI (indeks MyISAM) w katalogu danych MySQL. Na przykład poniższe polecenie zastępuje każde wystąpienie ciągu „F” na „9” w pliku:

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

Następnie wyślij kilka zapisów (np. za pomocą sysbench) do tabeli docelowej i wykonaj opróżnianie:

mysql> FLUSH TABLE sbtest.sbtest1;

W dzienniku błędów MySQL powinny pojawić się następujące informacje:

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

Tabela MyISAM zostanie oznaczona jako uszkodzona i konieczne jest uruchomienie instrukcji REPAIR TABLE, aby ponownie była dostępna.

Ograniczanie zasobów

Możemy również zastosować limit zasobów systemu operacyjnego do naszego procesu mysqld, na przykład liczbę otwartych deskryptorów plików. Użycie zmiennej open_file_limit (domyślnie 5000) umożliwia mysqld rezerwowanie deskryptorów plików za pomocą polecenia setrlimit(). Możesz ustawić tę zmienną stosunkowo małą (wystarczającą do uruchomienia mysqld), a następnie wysyłać wiele zapytań do serwera MySQL, aż osiągnie limit.

Jeśli mysqld działa na serwerze systemd, możemy ustawić go w pliku jednostki systemd znajdującym się w /usr/lib/systemd/system/mysqld.service i zmienić następującą wartość na niższą (domyślnie systemd to 6000):

# Sets open_files_limit
LimitNOFILE = 30

Zastosuj zmiany do systemd i zrestartuj serwer MySQL:

$ systemctl daemon-reload
$ systemctl restart mysqld

Następnie zacznij wysyłać nowe połączenia/zapytania, które liczą się w różnych bazach danych i tabelach, aby mysqld musiał otwierać wiele plików. Zauważysz następujący błąd:

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!

W tym momencie, gdy limit zostanie osiągnięty, MySQL zawiesi się i nie będzie mógł wykonać żadnej operacji. Podczas próby połączenia po chwili zobaczysz następujące informacje:

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

Pomieszanie z uprawnieniami

Proces mysqld jest uruchamiany przez użytkownika „mysql”, co oznacza, że ​​wszystkie pliki i katalogi, do których musi uzyskać dostęp, są własnością użytkownika/grupy mysql. Zamieszanie w uprawnieniach i prawach własności może sprawić, że serwer MySQL stanie się bezużyteczny:

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

Wygeneruj obciążenia na serwerze, a następnie połącz się z serwerem MySQL i opróżnij wszystkie tabele na dysk:

mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;

W tej chwili mysqld nadal działa, ale jest trochę bezużyteczny. Możesz uzyskać do niego dostęp przez klienta mysql, ale nie możesz wykonać żadnej operacji:

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

Aby posprzątać bałagan, ustaw odpowiednie uprawnienia:

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

Zablokuj go

STÓŁ DO PŁUKANIA Z BLOKADĄ ODCZYTU (FTWRL) może być niszczący w wielu warunkach. Podobnie jak na przykład w klastrze Galera, w którym wszystkie węzły mogą przetwarzać zapisy, możesz użyć tej instrukcji, aby zablokować klaster z poziomu jednego z węzłów. To stwierdzenie po prostu zatrzymuje inne zapytania, które mają być przetwarzane przez mysqld podczas opróżniania do momentu zwolnienia blokady, co jest bardzo przydatne w przypadku procesów tworzenia kopii zapasowych (tabele MyISAM) i migawek systemu plików.

Chociaż ta akcja nie spowoduje awarii ani wyłączenia serwera bazy danych podczas blokowania, konsekwencje mogą być ogromne, jeśli sesja, która utrzymuje blokadę, nie zwolni jej. Aby tego spróbować, po prostu:

mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit

Następnie wyślij kilka nowych zapytań do mysqld, aż dotrze do max_connections wartość. Oczywiście nie możesz wrócić do tej samej sesji, co poprzednia, gdy jesteś poza domem. Tak więc blokada będzie działała w nieskończoność, a jedynym sposobem na jej zwolnienie jest zabicie zapytania przez innego użytkownika z uprawnieniami SUPER (przy użyciu innej sesji). Lub zabij sam proces mysqld lub wykonaj twardy restart.

Zastrzeżenie

Ten blog został napisany, aby dać alternatywy dla administratorów i administratorów baz danych do symulowania scenariuszy awarii za pomocą MySQL. Nie próbuj ich na serwerze produkcyjnym :-)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jaka jest korzyść z zerofill w MySQL?

  2. Jak przechowywać datę i godzinę w MySQL z informacją o strefie czasowej?

  3. Funkcja konwersji MySQL

  4. MONTH() Przykłady – MySQL

  5. Korzystanie z funkcji agregujących (SUM, AVG, MAX, MIN, COUNT, DISTINCT) w MySQL