Cadangan sangat penting dalam hal keamanan data. Mereka adalah solusi pemulihan bencana terbaik - Anda tidak memiliki node basis data yang dapat dijangkau dan pusat data Anda benar-benar dapat hangus, tetapi selama Anda memiliki cadangan data, Anda masih dapat pulih dari situasi seperti itu.
Biasanya, Anda akan menggunakan cadangan untuk memulihkan dari berbagai jenis kasus:
- tidak disengaja DROP TABLE atau DELETE tanpa klausa WHERE, atau dengan klausa WHERE yang tidak cukup spesifik.
- pembaruan basis data yang gagal dan merusak data
- kegagalan/korupsi media penyimpanan
Apakah memulihkan dari cadangan tidak cukup? Apa yang harus menjadi point-in-time? Kita harus ingat bahwa cadangan adalah snapshot data yang diambil pada titik waktu tertentu. Jika Anda membuat cadangan pada pukul 1:00 dan sebuah tabel terhapus secara tidak sengaja pada pukul 11:00, Anda dapat memulihkan data hingga pukul 1:00, tetapi bagaimana dengan perubahan yang terjadi antara pukul 1:00 hingga 11:00? Perubahan tersebut akan hilang kecuali Anda dapat memutar ulang modifikasi yang terjadi di antaranya. Untungnya, MySQL memiliki mekanisme untuk menyimpan perubahan - log biner. Anda mungkin tahu bahwa log tersebut digunakan untuk replikasi - MySQL menggunakannya untuk menyimpan semua perubahan yang terjadi pada master, dan seorang budak menggunakannya untuk memutar ulang perubahan tersebut dan menerapkannya ke kumpulan datanya. Karena binlog menyimpan semua perubahan, Anda juga dapat menggunakannya untuk memutar ulang lalu lintas. Dalam posting blog ini, kita akan melihat bagaimana ClusterControl dapat membantu Anda melakukan Point-In-Time Recovery (PITR).
Membuat Cadangan yang Kompatibel dengan Pemulihan Point-In-Time
Pertama-tama, mari kita bicara tentang prasyarat. Host tempat Anda mengambil cadangan harus mengaktifkan log biner. Tanpa mereka, PITR tidak mungkin. Persyaratan kedua - host tempat Anda mengambil cadangan harus memiliki semua log biner yang diperlukan untuk memulihkan ke titik waktu tertentu. Jika Anda menggunakan rotasi log biner yang terlalu agresif, ini bisa menjadi masalah.
Jadi, mari kita lihat bagaimana menggunakan fitur ini di ClusterControl. Pertama-tama, Anda harus mengambil cadangan yang kompatibel dengan PITR. Cadangan tersebut harus lengkap, lengkap, dan konsisten. Untuk xtrabackup, selama berisi kumpulan data lengkap (Anda tidak menyertakan hanya sebagian skema), itu akan kompatibel dengan PITR.
Untuk mysqldump, ada opsi untuk membuatnya kompatibel dengan PITR. Saat Anda mengaktifkan opsi ini, semua opsi yang diperlukan akan dikonfigurasi (misalnya, Anda tidak akan dapat memilih skema terpisah untuk disertakan dalam dump) dan cadangan akan ditandai sebagai tersedia untuk pemulihan tepat waktu.
Pemulihan Point-In-Time Dari Cadangan
Pertama, Anda harus memilih cadangan untuk dipulihkan.
Jika pencadangan kompatibel dengan PITR, opsi akan ditampilkan untuk melakukan Pemulihan Point-In-Time. Anda akan memiliki dua opsi untuk itu - "Berbasis Waktu" dan "Berbasis Posisi". Mari kita bahas perbedaan antara kedua opsi tersebut.
PITR “Berbasis Waktu”
Dengan opsi ini Anda dapat melewati tanggal dan waktu, hingga cadangan harus dipulihkan. Hal ini dapat didefinisikan dalam satu resolusi detik. Ini tidak menjamin bahwa semua data akan dipulihkan karena, bahkan jika Anda sangat tepat dalam menentukan waktu, selama satu detik beberapa peristiwa dapat direkam dalam log biner. Katakanlah Anda tahu bahwa kehilangan data terjadi pada tanggal 18 April, pukul 10:00:01. Anda memasukkan tanggal dan waktu berikut ke formulir:'2018-04-18 10:00:00'. Harap diingat bahwa Anda harus menggunakan waktu yang didasarkan pada pengaturan zona waktu di server database tempat cadangan dibuat.
Masih mungkin terjadi kehilangan data bahkan bukan yang pertama yang terjadi pada pukul 10:00:01 sehingga beberapa peristiwa akan hilang dalam prosesnya. Mari kita lihat apa artinya.
Selama satu detik, beberapa peristiwa dapat dicatat dalam binlog. Mari kita perhatikan kasus seperti ini:
10:00:00 - kejadian A,B,C,D,E,F
10:00:01 - kejadian V,W,X,Y,Z
di mana X adalah peristiwa kehilangan data. Dengan perincian satu detik, Anda dapat memulihkan hingga semua yang terjadi pada 10:00:00 (hingga F) atau hingga 10:00:01 (hingga Z). Kasus selanjutnya tidak ada gunanya karena X akan dieksekusi ulang. Dalam kasus sebelumnya, kami merindukan V dan W.
Itu sebabnya pemulihan berbasis posisi lebih tepat. Anda dapat memberi tahu "Saya ingin memulihkan hingga W".
Pemulihan berbasis waktu adalah yang paling tepat yang bisa Anda dapatkan tanpa harus membuka log biner dan menentukan posisi yang tepat ke tempat yang ingin Anda pulihkan. Ini membawa kita ke metode kedua dalam melakukan PITR.
PITR “Berbasis Posisi”
Di sini beberapa pengalaman dengan alat baris perintah untuk MySQL, yaitu utilitas mysqlbinlog, diperlukan. Di sisi lain, Anda akan memiliki kendali terbaik atas bagaimana pemulihan akan dilakukan.
Mari kita lihat contoh sederhana. Seperti yang Anda lihat pada tangkapan layar di atas, Anda harus memberikan nama log biner dan posisi log biner hingga titik mana cadangan harus dipulihkan. Biasanya, ini harus menjadi posisi terakhir sebelum peristiwa kehilangan data.
Seseorang menjalankan perintah SQL yang mengakibatkan kehilangan data yang serius:
mysql> DROP TABLE sbtest1;
Query OK, 0 rows affected (0.02 sec)
Aplikasi kami segera mulai mengeluh:
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
Kami memiliki cadangan tetapi kami ingin memulihkan semua data hingga saat yang fatal itu. Pertama-tama, kami berasumsi bahwa aplikasi tidak berfungsi sehingga kami dapat membuang semua penulisan yang terjadi setelah DROP TABLE sebagai tidak penting. Jika aplikasi Anda berfungsi sampai batas tertentu, Anda harus menggabungkan perubahan yang tersisa nanti. Ok, mari kita periksa log biner untuk menemukan posisi pernyataan DROP TABLE. Karena kami ingin menghindari penguraian semua log biner, mari temukan posisi yang dicakup oleh cadangan terbaru kami. Anda dapat memeriksanya dengan memeriksa log untuk kumpulan cadangan terbaru dan mencari baris yang mirip dengan ini:
Jadi, kita berbicara tentang nama file 'binlog.000008' dan posisi '16184120'. Mari kita gunakan ini sebagai titik awal kita. Mari kita periksa file log biner apa yang kita miliki:
[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
Jadi, selain 'binlog.000008' kami juga memiliki 'binlog.000009' untuk diperiksa. Mari kita jalankan perintah yang akan mengubah log biner menjadi format SQL mulai dari posisi yang kita temukan di log cadangan:
[email protected]:~# mysqlbinlog --start-position='16184120' --verbose /var/lib/mysql/binlog.000008 /var/lib/mysql/binlog.000009 > binlog.out
Harap simpul '--verbose' diperlukan untuk memecahkan kode acara berbasis baris. Ini tidak selalu diperlukan untuk DROP TABLE yang kami cari, tetapi untuk jenis acara lain mungkin diperlukan.
Mari cari keluaran kita untuk kueri DROP TABLE:
[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 */
/*!*/;
Dalam contoh ini kita dapat melihat dua peristiwa. Pertama, pada posisi 20885489, setel variabel 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'/*!*/;
Kedua, pada posisi 20885554 adalah acara DROP TABLE kami. Ini mengarah pada kesimpulan bahwa kita harus melakukan PITR hingga posisi 20885489. Satu-satunya pertanyaan yang harus dijawab adalah log biner mana yang sedang kita bicarakan. Kami dapat memeriksanya dengan mencari entri rotasi binlog:
[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
Seperti dapat dilihat dengan jelas dengan membandingkan tanggal, rotasi ke binlog.000009 terjadi kemudian oleh karena itu kami ingin meneruskan binlog.000008 sebagai file binlog dalam formulir.
Selanjutnya, kita harus memutuskan apakah kita akan memulihkan cadangan di cluster atau apakah kita ingin menggunakan server eksternal untuk memulihkannya. Opsi kedua ini dapat berguna jika Anda ingin memulihkan hanya sebagian data. Anda dapat memulihkan cadangan fisik lengkap pada host terpisah dan kemudian menggunakan mysqldump untuk membuang data yang hilang dan memuatnya di server produksi.
Ingatlah bahwa ketika Anda memulihkan cadangan di kluster Anda, Anda harus membangun kembali node selain yang Anda pulihkan. Dalam skenario master - slave, Anda biasanya ingin memulihkan cadangan pada master dan kemudian membangun kembali slave darinya.
Sebagai langkah terakhir, Anda akan melihat ringkasan tindakan yang akan dilakukan ClusterControl.
Terakhir, setelah backup dipulihkan, kami akan menguji apakah tabel yang hilang telah dipulihkan atau tidak:
mysql> show tables from sbtest like 'sbtest1'\G
*************************** 1. row ***************************
Tables_in_sbtest (sbtest1): sbtest1
1 row in set (0.00 sec)
Semuanya tampak baik-baik saja, kami berhasil memulihkan data yang hilang.
Langkah terakhir yang harus kita ambil adalah membangun kembali budak kita. Harap dicatat bahwa ada opsi untuk menggunakan cadangan PITR. Dalam contoh di sini, ini tidak mungkin karena slave akan mereplikasi acara DROP TABLE dan akhirnya tidak konsisten dengan master.