Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Pemecahan Masalah Replikasi MySQL:Bagian Kedua

Pada postingan sebelumnya, kita telah membahas cara memverifikasi bahwa Replikasi MySQL dalam kondisi baik. Kami juga melihat beberapa masalah khas. Dalam postingan ini, kita akan melihat beberapa masalah lain yang mungkin Anda lihat saat menangani replikasi MySQL.

Entri Hilang atau Duplikat

Ini adalah sesuatu yang seharusnya tidak terjadi, namun sering terjadi - situasi di mana pernyataan SQL yang dieksekusi pada master berhasil tetapi pernyataan yang sama yang dieksekusi pada salah satu budak gagal. Alasan utamanya adalah slave drift - sesuatu (biasanya transaksi yang salah tetapi juga masalah atau bug lain dalam replikasi) menyebabkan slave berbeda dari masternya. Misalnya, baris yang ada pada master tidak ada pada slave dan tidak dapat dihapus atau diperbarui. Seberapa sering masalah ini muncul sebagian besar tergantung pada pengaturan replikasi Anda. Singkatnya, ada tiga cara di mana MySQL menyimpan peristiwa log biner. Pertama, "pernyataan", berarti SQL ditulis dalam teks biasa, sama seperti yang telah dieksekusi pada master. Pengaturan ini memiliki toleransi tertinggi pada slave drift tetapi juga tidak dapat menjamin konsistensi slave - sulit untuk merekomendasikan untuk menggunakannya dalam produksi. Format kedua, "baris", menyimpan hasil kueri alih-alih pernyataan kueri. Misalnya, sebuah acara mungkin terlihat seperti di bawah ini:

### UPDATE `test`.`tab`
### WHERE
###   @1=2
###   @2=5
### SET
###   @1=2
###   @2=4

Ini berarti bahwa kami memperbarui baris dalam tabel 'tab' dalam skema 'pengujian' di mana kolom pertama memiliki nilai 2 dan kolom kedua memiliki nilai 5. Kami menetapkan kolom pertama ke 2 (nilai tidak berubah) dan kedua kolom ke 4. Seperti yang Anda lihat, tidak ada banyak ruang untuk interpretasi - baris mana yang digunakan dan bagaimana perubahannya ditentukan dengan tepat. Akibatnya, format ini sangat bagus untuk konsistensi slave, tetapi, seperti yang dapat Anda bayangkan, format ini sangat rentan dalam hal penyimpangan data. Tetap saja ini adalah cara yang disarankan untuk menjalankan replikasi MySQL.

Terakhir, yang ketiga, “campuran”, bekerja sedemikian rupa sehingga peristiwa-peristiwa yang aman untuk ditulis dalam bentuk pernyataan menggunakan format “pernyataan”. Yang dapat menyebabkan penyimpangan data akan menggunakan format “baris”.

Bagaimana Anda Mendeteksi Mereka?

Seperti biasa, SHOW SLAVE STATUS akan membantu kami mengidentifikasi masalah.

               Last_SQL_Errno: 1032
               Last_SQL_Error: Could not execute Update_rows event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000021, end_log_pos 970
               Last_SQL_Errno: 1062
               Last_SQL_Error: Could not execute Write_rows event on table test.tab; Duplicate entry '3' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log binlog.000021, end_log_pos 1229

Seperti yang Anda lihat, kesalahan jelas dan cukup jelas (dan pada dasarnya sama antara MySQL dan MariaDB.

Bagaimana Anda memperbaiki Masalah?

Sayangnya, ini adalah bagian yang kompleks. Pertama-tama, Anda perlu mengidentifikasi sumber kebenaran. Host mana yang berisi data yang benar? Tuan atau budak? Biasanya Anda akan menganggap itu master tetapi jangan menganggapnya secara default - selidiki! Bisa jadi setelah failover, beberapa bagian dari aplikasi masih menulis ke master lama, yang sekarang bertindak sebagai budak. Bisa jadi read_only belum disetel dengan benar pada host tersebut atau mungkin aplikasi menggunakan superuser untuk terhubung ke database (ya, kami telah melihat ini di lingkungan produksi). Dalam kasus seperti itu, budak bisa menjadi sumber kebenaran - setidaknya sampai batas tertentu.

Bergantung pada data mana yang harus tetap ada dan mana yang harus pergi, tindakan terbaik adalah mengidentifikasi apa yang diperlukan agar replikasi kembali sinkron. Pertama-tama, replikasi rusak sehingga Anda harus memperhatikan ini. Masuk ke master dan periksa log biner yang menyebabkan replikasi rusak.

           Retrieved_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1106672
            Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-1106671

Seperti yang Anda lihat, kami melewatkan satu acara:5d1e2227-07c6-11e7-8123-080027495a77:1106672. Mari kita periksa di log biner master:

mysqlbinlog -v --include-gtids='5d1e2227-07c6-11e7-8123-080027495a77:1106672' /var/lib/mysql/binlog.000021
#170320 20:53:37 server id 1  end_log_pos 1066 CRC32 0xc582a367     GTID    last_committed=3    sequence_number=4
SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106672'/*!*/;
# at 1066
#170320 20:53:37 server id 1  end_log_pos 1138 CRC32 0x6f33754d     Query    thread_id=5285    exec_time=0    error_code=0
SET TIMESTAMP=1490043217/*!*/;
SET @@session.pseudo_thread_id=5285/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 1138
#170320 20:53:37 server id 1  end_log_pos 1185 CRC32 0xa00b1f59     Table_map: `test`.`tab` mapped to number 571
# at 1185
#170320 20:53:37 server id 1  end_log_pos 1229 CRC32 0x5597e50a     Write_rows: table id 571 flags: STMT_END_F

BINLOG '
UUHQWBMBAAAALwAAAKEEAAAAADsCAAAAAAEABHRlc3QAA3RhYgACAwMAAlkfC6A=
UUHQWB4BAAAALAAAAM0EAAAAADsCAAAAAAEAAgAC//wDAAAABwAAAArll1U=
'/*!*/;
### INSERT INTO `test`.`tab`
### SET
###   @1=3
###   @2=7
# at 1229
#170320 20:53:37 server id 1  end_log_pos 1260 CRC32 0xbbc3367c     Xid = 5224257
COMMIT/*!*/;

Kita dapat melihatnya sebagai sisipan yang menyetel kolom pertama menjadi 3 dan kedua menjadi 7. Mari kita verifikasi bagaimana tampilan tabel kita sekarang:

mysql> SELECT * FROM test.tab;
+----+------+
| id | b    |
+----+------+
|  1 |    2 |
|  2 |    4 |
|  3 |   10 |
+----+------+
3 rows in set (0.01 sec)

Sekarang kami memiliki dua opsi, tergantung pada data mana yang harus digunakan. Jika data yang benar ada pada master, kita cukup menghapus baris dengan id=3 pada slave. Pastikan Anda menonaktifkan logging biner untuk menghindari terjadinya transaksi yang salah. Di sisi lain, jika kita memutuskan bahwa data yang benar ada di slave, kita perlu menjalankan perintah REPLACE pada master untuk mengatur baris dengan id=3 untuk mengoreksi konten (3, 10) dari saat ini (3, 7). Namun, pada slave, kita harus melewati GTID saat ini (atau, lebih tepatnya, kita harus membuat acara GTID kosong) untuk dapat memulai ulang replikasi.

Menghapus baris pada budak itu sederhana:

SET SESSION log_bin=0; DELETE FROM test.tab WHERE id=3; SET SESSION log_bin=1;

Memasukkan GTID kosong hampir sesederhana:

mysql> SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106672';
Query OK, 0 rows affected (0.00 sec)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SET @@SESSION.GTID_NEXT=automatic;
Query OK, 0 rows affected (0.00 sec)

Metode lain untuk memecahkan masalah khusus ini (selama kita menerima master sebagai sumber kebenaran) adalah dengan menggunakan alat seperti pt-table-checksum dan pt-table-sync untuk mengidentifikasi di mana slave tidak konsisten dengan masternya dan apa SQL harus dijalankan pada master untuk mengembalikan slave dalam sinkronisasi. Sayangnya, metode ini agak berat - banyak beban ditambahkan ke master dan banyak kueri ditulis ke dalam aliran replikasi yang dapat memengaruhi kelambatan pada budak dan kinerja umum pengaturan replikasi. Ini terutama benar jika ada sejumlah besar baris yang perlu disinkronkan.

Terakhir, seperti biasa, Anda dapat membangun kembali slave Anda menggunakan data dari master - dengan cara ini Anda dapat yakin bahwa slave akan disegarkan dengan data terbaru dan terbaru. Sebenarnya, ini bukan ide yang buruk - ketika kita berbicara tentang sejumlah besar baris untuk disinkronkan menggunakan pt-table-checksum/pt-table-sync, ini datang dengan overhead yang signifikan dalam kinerja replikasi, keseluruhan CPU dan I/O beban dan jam kerja yang dibutuhkan.

ClusterControl memungkinkan Anda membangun kembali slave, menggunakan salinan baru dari data master.

Pemeriksaan Konsistensi

Seperti yang kami sebutkan di bab sebelumnya, konsistensi dapat menjadi masalah serius dan dapat menyebabkan banyak masalah bagi pengguna yang menjalankan pengaturan replikasi MySQL. Mari kita lihat bagaimana Anda dapat memverifikasi bahwa budak MySQL Anda sinkron dengan master dan apa yang dapat Anda lakukan.

Cara Mendeteksi Budak yang Tidak Konsisten

Sayangnya, cara khas pengguna untuk mengetahui bahwa seorang budak tidak konsisten adalah dengan mengalami salah satu masalah yang kami sebutkan di bab sebelumnya. Untuk menghindari pemantauan proaktif konsistensi budak diperlukan. Mari kita periksa bagaimana hal itu bisa dilakukan.

Kita akan menggunakan alat dari Percona Toolkit:pt-table-checksum. Ini dirancang untuk memindai kluster replikasi dan mengidentifikasi perbedaan apa pun.

Kami membuat skenario khusus menggunakan sysbench dan kami memperkenalkan sedikit inkonsistensi pada salah satu slave. Yang penting (jika Anda ingin mengujinya seperti yang kami lakukan), Anda perlu menerapkan patch di bawah ini untuk memaksa pt-table-checksum mengenali skema 'sbtest' sebagai skema non-sistem:

--- pt-table-checksum    2016-12-15 14:31:07.000000000 +0000
+++ pt-table-checksum-fix    2017-03-21 20:32:53.282254794 +0000
@@ -7614,7 +7614,7 @@

    my $filter = $self->{filters};

-   if ( $db =~ m/information_schema|performance_schema|lost\+found|percona|percona_schema|test/ ) {
+   if ( $db =~ m/information_schema|performance_schema|lost\+found|percona|percona_schema|^test/ ) {
       PTDEBUG && _d('Database', $db, 'is a system database, ignoring');
       return 0;
    }

Pada awalnya, kita akan menjalankan pt-table-checksum dengan cara berikut:

master:~# ./pt-table-checksum  --max-lag=5 --user=sbtest --password=sbtest --no-check-binlog-format --databases='sbtest'
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
03-21T20:33:30      0      0  1000000      15       0  27.103 sbtest.sbtest1
03-21T20:33:57      0      1  1000000      17       0  26.785 sbtest.sbtest2
03-21T20:34:26      0      0  1000000      15       0  28.503 sbtest.sbtest3
03-21T20:34:52      0      0  1000000      18       0  26.021 sbtest.sbtest4
03-21T20:35:34      0      0  1000000      17       0  42.730 sbtest.sbtest5
03-21T20:36:04      0      0  1000000      16       0  29.309 sbtest.sbtest6
03-21T20:36:42      0      0  1000000      15       0  38.071 sbtest.sbtest7
03-21T20:37:16      0      0  1000000      12       0  33.737 sbtest.sbtest8

Beberapa catatan penting tentang bagaimana kami menggunakan alat ini. Pertama-tama, user yang kita set harus ada di semua slave. Jika mau, Anda juga dapat menggunakan '--slave-user' untuk mendefinisikan pengguna lain yang kurang memiliki hak istimewa untuk mengakses slave. Hal lain yang perlu dijelaskan - kami menggunakan replikasi berbasis baris yang tidak sepenuhnya kompatibel dengan pt-table-checksum. Jika Anda memiliki replikasi berbasis baris, yang terjadi adalah pt-table-checksum akan mengubah format log biner pada tingkat sesi menjadi 'pernyataan' karena ini adalah satu-satunya format yang didukung. Masalahnya adalah bahwa perubahan tersebut hanya akan bekerja pada budak tingkat pertama yang terhubung langsung ke master. Jika Anda memiliki master perantara (jadi, lebih dari satu level budak), menggunakan pt-table-checksum dapat merusak replikasi. Inilah sebabnya, secara default, jika alat mendeteksi replikasi berbasis baris, alat akan keluar dan mencetak kesalahan:

“Replica slave1 memiliki binlog_format ROW yang dapat menyebabkan pt-table-checksum merusak replikasi. Harap baca "Replika menggunakan replikasi berbasis baris" di bagian KETERBATASAN pada dokumentasi alat. Jika Anda memahami risikonya, tentukan --no-check-binlog-format untuk menonaktifkan pemeriksaan ini.”

Kami hanya menggunakan satu level slave sehingga aman untuk menentukan “--no-check-binlog-format” dan melanjutkan.

Terakhir, kami mengatur lag maksimum menjadi 5 detik. Jika ambang batas ini tercapai, pt-table-checksum akan berhenti sejenak untuk membawa lag di bawah ambang batas.

Seperti yang Anda lihat dari output,

03-21T20:33:57      0      1  1000000      17       0  26.785 sbtest.sbtest2

inkonsistensi telah terdeteksi pada tabel sbtest.sbtest2.

Secara default, pt-table-checksum menyimpan checksum di tabel percona.checksums. Data ini dapat digunakan untuk alat lain dari Percona Toolkit, pt-table-sync, untuk mengidentifikasi bagian mana dari tabel yang harus diperiksa secara detail untuk menemukan perbedaan data yang tepat.

Cara memperbaiki Budak yang Tidak Konsisten

Seperti disebutkan di atas, kami akan menggunakan pt-table-sync untuk melakukan itu. Dalam kasus kami, kami akan menggunakan data yang dikumpulkan oleh pt-table-checksum meskipun juga memungkinkan untuk mengarahkan pt-table-sync ke dua host (master dan slave) dan itu akan membandingkan semua data di kedua host. Ini jelas merupakan proses yang lebih memakan waktu dan sumber daya oleh karena itu, selama Anda sudah memiliki data dari pt-table-checksum, lebih baik menggunakannya. Beginilah cara kami menjalankannya untuk menguji output:

master:~# ./pt-table-sync --user=sbtest --password=sbtest --databases=sbtest --replicate percona.checksums h=master --print
REPLACE INTO `sbtest`.`sbtest2`(`id`, `k`, `c`, `pad`) VALUES ('1', '434041', '61753673565-14739672440-12887544709-74227036147-86382758284-62912436480-22536544941-50641666437-36404946534-73544093889', '23608763234-05826685838-82708573685-48410807053-00139962956') /*percona-toolkit src_db:sbtest src_tbl:sbtest2 src_dsn:h=10.0.0.101,p=...,u=sbtest dst_db:sbtest dst_tbl:sbtest2 dst_dsn:h=10.0.0.103,p=...,u=sbtest lock:1 transaction:1 changing_src:percona.checksums replicate:percona.checksums bidirectional:0 pid:25776 user:root host:vagrant-ubuntu-trusty-64*/;

Seperti yang Anda lihat, sebagai hasilnya, beberapa SQL telah dibuat. Penting untuk diperhatikan adalah --replicate variabel. Apa yang terjadi di sini adalah kita mengarahkan pt-table-sync ke tabel yang dihasilkan oleh pt-table-checksum. Kami juga mengarahkannya ke master.

Untuk memverifikasi apakah SQL masuk akal, kami menggunakan opsi --print. Harap perhatikan bahwa SQL yang dihasilkan hanya valid pada saat dibuat - Anda tidak dapat benar-benar menyimpannya di suatu tempat, meninjaunya, lalu menjalankannya. Yang dapat Anda lakukan adalah memverifikasi apakah SQL masuk akal dan, segera setelah itu, jalankan kembali alat dengan --execute flag:

master:~# ./pt-table-sync --user=sbtest --password=sbtest --databases=sbtest --replicate percona.checksums h=10.0.0.101 --execute

Ini akan membuat budak kembali sinkron dengan master. Kami dapat memverifikasinya dengan pt-table-checksum:

[email protected]:~# ./pt-table-checksum  --max-lag=5 --user=sbtest --password=sbtest --no-check-binlog-format --databases='sbtest'
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
03-21T21:36:04      0      0  1000000      13       0  23.749 sbtest.sbtest1
03-21T21:36:26      0      0  1000000       7       0  22.333 sbtest.sbtest2
03-21T21:36:51      0      0  1000000      10       0  24.780 sbtest.sbtest3
03-21T21:37:11      0      0  1000000      14       0  19.782 sbtest.sbtest4
03-21T21:37:42      0      0  1000000      15       0  30.954 sbtest.sbtest5
03-21T21:38:07      0      0  1000000      15       0  25.593 sbtest.sbtest6
03-21T21:38:27      0      0  1000000      16       0  19.339 sbtest.sbtest7
03-21T21:38:44      0      0  1000000      15       0  17.371 sbtest.sbtest8

Seperti yang Anda lihat, tidak ada perbedaan lagi di tabel sbtest.sbtest2.

Kami harap Anda menemukan posting blog ini informatif dan bermanfaat. Klik di sini untuk mempelajari lebih lanjut tentang Replikasi MySQL. Jika Anda memiliki pertanyaan atau saran, jangan ragu untuk menghubungi kami melalui komentar di bawah.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa menulis SQL untuk tabel yang memiliki nama yang sama dengan kata kunci yang dilindungi di MySql?

  2. Memigrasikan MySQL ke PostgreSQL di AWS RDS, Bagian 3

  3. Apa itu MySQL? – Pengantar Sistem Manajemen Basis Data

  4. Bagaimana cara memulai MySQL dengan --skip-grant-tables?

  5. Mengekspor tabel dari Amazon RDS ke file CSV