Anda dapat menghapus database MySQL dengan berbagai cara. Beberapa cara yang jelas adalah dengan mematikan host, mencabut kabel daya, atau mematikan proses mysqld dengan SIGKILL untuk mensimulasikan perilaku shutdown MySQL yang tidak bersih. Tetapi ada juga cara yang lebih halus untuk secara sengaja merusak server MySQL Anda, dan kemudian melihat reaksi berantai seperti apa yang dipicunya. Mengapa Anda ingin melakukan ini? Kegagalan dan pemulihan dapat memiliki banyak kasus sudut, dan memahaminya dapat membantu mengurangi unsur kejutan ketika sesuatu terjadi dalam produksi. Idealnya, Anda ingin mensimulasikan kegagalan dalam lingkungan yang terkendali, lalu merancang dan menguji prosedur failover database.
Ada beberapa area di MySQL yang bisa kami tangani, tergantung bagaimana Anda ingin gagal atau crash. Anda dapat merusak tablespace, membanjiri buffer dan cache MySQL, membatasi sumber daya untuk membuat server kelaparan, dan juga mengacaukan izin. Dalam posting blog ini, kami akan menunjukkan beberapa contoh bagaimana crash server MySQL di lingkungan Linux. Beberapa dari mereka akan cocok untuk mis. Instans Amazon RDS, di mana Anda tidak akan memiliki akses ke host pokok.
Bunuh, Bunuh, Bunuh, Mati, Mati, Mati
Cara termudah untuk menggagalkan server MySQL adalah dengan mematikan proses atau host, dan tidak memberikan kesempatan kepada MySQL untuk melakukan shutdown dengan baik. Untuk mensimulasikan crash mysqld, cukup kirim sinyal 4, 6, 7, 8 atau 11 ke proses:
$ kill -11 $(pidof mysqld)
Saat melihat log kesalahan MySQL, Anda dapat melihat baris berikut:
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...
Anda juga dapat menggunakan kill -9 (SIGKILL) untuk menghentikan proses dengan segera. Detail lebih lanjut tentang sinyal Linux dapat ditemukan di sini. Atau, Anda dapat menggunakan cara yang lebih kejam di sisi perangkat keras seperti mencabut kabel daya, menekan tombol hard reset, atau menggunakan perangkat pagar ke STONITH.
Memicu OOM
MySQL populer di penawaran cloud seperti Amazon RDS dan Google Cloud SQL tidak memiliki cara langsung untuk menghancurkannya. Pertama karena Anda tidak akan mendapatkan akses tingkat OS apa pun ke instance database, dan kedua karena penyedia menggunakan server MySQL yang ditambal. Salah satu caranya adalah dengan membanjiri beberapa buffer, dan membiarkan manajer yang kehabisan memori (OOM) untuk memulai proses MySQL.
Anda dapat meningkatkan ukuran buffer pengurutan menjadi sesuatu yang lebih besar dari yang dapat ditangani oleh RAM, dan menembak sejumlah kueri pengurutan mysql terhadap server MySQL. Mari buat tabel 10 juta baris menggunakan sysbench pada instans Amazon RDS, sehingga kita dapat membuat semacam besar:
$ 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
Ubah sort_buffer_size ke 5G (contoh pengujian kami adalah db.t2.micro - 1GB, 1vCPU) dengan membuka Dasbor Amazon RDS -> Grup Parameter -> Buat Grup Parameter -> tentukan nama grup -> Edit Parameter -> pilih "sort_buffer_size" dan tentukan nilainya sebagai 5368709120.
Terapkan perubahan grup parameter dengan masuk ke Instances -> Instance Action -> Modify -> Database Options -> Database Parameter Group -> dan pilih grup parameter kami yang baru dibuat. Kemudian, reboot instance RDS untuk menerapkan perubahan.
Setelah aktif, verifikasi nilai baru sort_buffer_size :
MySQL [(none)]> select @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
| 5368709120 |
+--------------------+
Kemudian jalankan 48 kueri sederhana yang memerlukan pengurutan dari klien:
$ 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
Jika Anda menjalankan di atas pada host standar, Anda akan melihat server MySQL akan dihentikan dan Anda dapat melihat baris berikut muncul di syslog atau dmesg OS:
[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
Dengan systemd, MySQL atau MariaDB akan dimulai ulang secara otomatis, begitu juga dengan Amazon RDS. Anda dapat melihat waktu aktif untuk instans RDS kami akan disetel ulang kembali ke 0 (di bawah status mysqladmin), dan nilai 'Waktu pemulihan terbaru' (di bawah Dasbor RDS) akan diperbarui saat turun.
Merusak Data
InnoDB memiliki tablespace sistemnya sendiri untuk menyimpan kamus data, buffer, dan segmen rollback di dalam file bernama ibdata1. Ini juga menyimpan tablespace bersama jika Anda tidak mengonfigurasi innodb_file_per_table (diaktifkan secara default di MySQL 5.6.6+). Kami hanya dapat menghapus file ini, mengirim operasi tulis, dan membersihkan tabel untuk membuat crash 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'
Setelah Anda mengirim tulisan, di log kesalahan, Anda akan melihat:
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.
Pada titik ini, mysql akan hang karena tidak dapat melakukan operasi apa pun, dan setelah pembilasan, Anda akan mendapatkan baris "mysqld got signal 11" dan mysqld akan dimatikan. Untuk membersihkan, Anda harus menghapus ibdata1, serta ib_logfile* yang rusak karena file log redo tidak dapat digunakan dengan tablespace sistem baru yang akan dihasilkan oleh mysqld pada restart berikutnya. Kehilangan data diperkirakan terjadi.
Untuk tabel MyISAM, kita bisa bermain-main dengan .MYD (file data MyISAM) dan .MYI (indeks MyISAM) di bawah direktori data MySQL. Misalnya, perintah berikut menggantikan kemunculan string "F" dengan "9" di dalam file:
$ replace F 9 -- /var/lib/mysql/sbtest/sbtest1.MYD
Kemudian, kirim beberapa penulisan (misalnya, menggunakan sysbench) ke tabel target dan lakukan pembilasan:
mysql> FLUSH TABLE sbtest.sbtest1;
Berikut ini akan muncul di log kesalahan 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
Tabel MyISAM akan ditandai sebagai crash dan pernyataan REPAIR TABLE yang dijalankan diperlukan untuk membuatnya dapat diakses kembali.
Membatasi Sumber Daya
Kami juga dapat menerapkan batas sumber daya sistem operasi untuk proses mysqld kami, misalnya jumlah deskriptor file yang terbuka. Menggunakan variabel open_file_limit (default adalah 5000) memungkinkan mysqld untuk memesan deskriptor file menggunakan perintah setrlimit(). Anda dapat mengatur variabel ini relatif kecil (cukup untuk memulai mysqld) dan kemudian mengirim beberapa kueri ke server MySQL hingga mencapai batas.
Jika mysqld berjalan di server systemd, kita dapat mengaturnya di file unit systemd yang terletak di /usr/lib/systemd/system/mysqld.service, dan mengubah nilai berikut menjadi sesuatu yang lebih rendah (default systemd adalah 6000):
# Sets open_files_limit
LimitNOFILE = 30
Terapkan perubahan ke systemd dan mulai ulang server MySQL:
$ systemctl daemon-reload
$ systemctl restart mysqld
Kemudian, mulailah mengirim koneksi/kueri baru yang dihitung dalam database dan tabel yang berbeda sehingga mysqld harus membuka banyak file. Anda akan melihat kesalahan berikut:
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!
Pada titik ini, ketika batas tercapai, MySQL akan membeku dan tidak akan dapat melakukan operasi apa pun. Saat mencoba menyambung, Anda akan melihat yang berikut ini setelah beberapa saat:
$ mysql -uroot -p
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104
Mengacaukan Izin
Proses mysqld dijalankan oleh pengguna "mysql", yang berarti semua file dan direktori yang perlu diakses dimiliki oleh pengguna/grup mysql. Dengan mengacaukan izin dan kepemilikan, kita dapat membuat server MySQL tidak berguna:
$ chown root:root /var/lib/mysql
$ chmod 600 /var/lib/mysql
Buat beberapa beban ke server dan kemudian sambungkan ke server MySQL dan pindahkan semua tabel ke disk:
mysql> FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;
Saat ini, mysqld masih berjalan tetapi tidak berguna. Anda dapat mengaksesnya melalui klien mysql tetapi Anda tidak dapat melakukan operasi apa pun:
mysql> SHOW DATABASES;
ERROR 1018 (HY000): Can't read dir of '.' (errno: 13 - Permission denied)
Untuk membersihkan kekacauan, setel izin yang benar:
$ chown mysql:mysql /var/lib/mysql
$ chmod 750 /var/lib/mysql
$ systemctl restart mysqld
Kunci
FLUSH TABLE WITH READ LOCK (FTWRL) dapat merusak dalam beberapa kondisi. Seperti misalnya, dalam cluster Galera di mana semua node dapat memproses penulisan, Anda dapat menggunakan pernyataan ini untuk mengunci cluster dari dalam salah satu node. Pernyataan ini hanya menghentikan kueri lain untuk diproses oleh mysqld selama pembilasan sampai kunci dilepaskan, yang sangat berguna untuk proses pencadangan (tabel MyISAM) dan snapshot sistem file.
Meskipun tindakan ini tidak akan mogok atau menjatuhkan server database Anda selama penguncian, konsekuensinya bisa sangat besar jika sesi yang menahan kunci tidak melepaskannya. Untuk mencobanya, cukup:
mysql> FLUSH TABLES WITH READ LOCK;
mysql> exit
Kemudian kirim banyak kueri baru ke mysqld hingga mencapai max_connections nilai. Jelas, Anda tidak bisa mendapatkan kembali sesi yang sama seperti sebelumnya setelah Anda keluar. Jadi kunci akan berjalan tanpa batas dan satu-satunya cara untuk melepaskan kunci adalah dengan mematikan kueri, oleh pengguna hak istimewa SUPER lain (menggunakan sesi lain). Atau matikan proses mysqld itu sendiri, atau lakukan hard reboot.
Penafian
Blog ini ditulis untuk memberikan alternatif bagi sysadmin dan DBA untuk mensimulasikan skenario kegagalan dengan MySQL. Jangan coba ini di server produksi Anda :-)