Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Kemajuan tidak berhenti, sehingga alasan untuk mengupgrade ke versi terbaru MySQL menjadi semakin menarik. Belum lama ini, di salah satu proyek kami, tiba waktunya untuk memperbarui cluster Percona Server 5.7 yang nyaman ke versi 8. Semua ini terjadi pada platform Ubuntu Linux 16.04. Cara melakukan operasi seperti itu dengan waktu henti minimal dan masalah apa yang kami temui selama pembaruan - baca artikel ini.

Latihan

Setiap pembaruan server basis data kemungkinan besar terkait dengan konfigurasi ulang basis data: perubahan persyaratan untuk batasan sumber daya sistem dan koreksi konfigurasi basis data yang perlu dibersihkan dari arahan yang sudah ketinggalan zaman.

Sebelum memperbarui, kami pasti akan merujuk ke dokumentasi resmi:

Dan mari kita buat rencana aksi:

  1. Perbaiki file konfigurasi dengan menghapus arahan yang sudah ketinggalan zaman.
  2. Periksa kompatibilitas dengan utilitas.
  3. Perbarui database budak dengan menginstal paket percona-server-server.
  4. Perbarui master dengan paket yang sama.

Mari kita lihat setiap poin rencana dan lihat apa yang salah.

PENTING! Prosedur untuk memperbarui cluster MySQL berdasarkan Galera memiliki kehalusan tersendiri yang tidak dijelaskan dalam artikel. Anda sebaiknya tidak menggunakan instruksi ini dalam kasus ini.

Bagian 1: Memeriksa konfigurasi

MySQL telah dihapus di versi 8 query_cache. Sebenarnya dia dinyatakan usang kembali ke versi 5.7, tapi sekarang sepenuhnya dihapus. Oleh karena itu, arahan terkait perlu dihapus. Dan untuk menyimpan permintaan dalam cache, Anda sekarang dapat menggunakan alat eksternal - misalnya, ProksiSQL.

Juga di konfigurasi ada arahan usang tentang innodb_file_format. Jika di MySQL 5.7 dimungkinkan untuk memilih format InnoDB, maka versi ke-8 sudah berfungsi hanya dengan format Barracuda.

Hasil kami adalah penghapusan arahan berikut:

  • query_cache_type, query_cache_limit ΠΈ query_cache_size;
  • innodb_file_format ΠΈ innodb_file_format_max.

Untuk memeriksanya, kami akan menggunakan image Docker dari Percona Server. Kami akan menempatkan konfigurasi server di direktori mysql_config_test, dan di sebelahnya kita akan membuat direktori untuk data dan log. Contoh pengujian konfigurasi server Percona:

mkdir -p {mysql_config_test,mysql_data,mysql_logs}
cp -r /etc/mysql/conf.d/* mysql_config_test/
docker run  --name some-percona -v $(pwd)/mysql_config_test:/etc/my.cnf.d/  -v $(pwd)/mysql_data/:/var/lib/mysql/ -v $(pwd)/mysql_logs/:/var/log/mysql/ -e MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} -d percona:8-centos

Intinya: baik di log Docker atau di direktori dengan log - tergantung pada konfigurasi Anda - sebuah file akan muncul di mana arahan yang bermasalah akan dijelaskan.

Inilah yang kami punya:

2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.

Oleh karena itu, kami masih perlu mencari tahu pengkodeannya dan mengganti arahan yang sudah ketinggalan zaman expire-logs-days.

Bagian 2: Memeriksa instalasi yang berfungsi

Dokumentasi pembaruan berisi 2 utilitas untuk memeriksa kompatibilitas database. Penggunaannya membantu administrator memeriksa kompatibilitas struktur data yang ada.

Mari kita mulai dengan utilitas mysqlcheck klasik. Cukup jalankan:

mysqlcheck -u root -p --all-databases --check-upgrade

Jika tidak ditemukan masalah, utilitas akan keluar dengan kode 0:

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Selain itu, utilitas tersedia di MySQL versi modern shell mysql (dalam kasus Percona ini adalah paketnya percona-mysql-shell). Ini adalah pengganti klien mysql klasik dan menggabungkan fungsi klien, editor kode SQL dan alat administrasi MySQL. Untuk memeriksa server sebelum memperbarui, Anda dapat menjalankan perintah berikut melaluinya:

mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnf

Berikut komentar yang kami terima:

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Secara umum, tidak ada yang penting - hanya peringatan tentang penyandian (Lihat di bawah). Hasil eksekusi keseluruhan:

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Kami memutuskan bahwa pembaruan akan berjalan tanpa masalah.

Catatan tentang peringatan di atas yang menunjukkan masalah dengan pengkodean. Faktanya adalah UTF-8 di MySQL sampai saat ini tidak "benar" UTF-8, karena hanya menyimpan 3 byte, bukan 4. Di MySQL 8, ini akhirnya terjadi memutuskan untuk memperbaikinya: alias utf8 akan segera mengarah pada pengkodean utf8mb4, dan kolom lama di tabel akan menjadi utf8mb3. Pengkodean lebih lanjut utf8mb3 akan dihapus, tetapi tidak dalam rilis ini. Oleh karena itu, kami memutuskan untuk memperbaiki pengkodean yang sudah ada pada instalasi DBMS yang sedang berjalan, setelah memperbaruinya.

Bagian 3: Pembaruan Server

Apa yang salah jika ada rencana cerdas seperti itu?.. Memahami sepenuhnya bahwa perbedaan selalu terjadi, kami melakukan percobaan pertama pada cluster pengembang MySQL.

Seperti yang sudah disebutkan, dokumentasi resmi mencakup masalah memperbarui server MySQL dengan replika. Intinya adalah Anda harus memperbarui semua replika (slave) terlebih dahulu, karena MySQL 8 dapat mereplikasi dari master versi 5.7. Beberapa kesulitan terletak pada kenyataan bahwa kita menggunakan mode tersebut tuan <-> tuan, saat master jarak jauh berada dalam mode read-only. Faktanya, lalu lintas pertempuran menuju ke satu pusat data, dan yang kedua adalah pusat data cadangan.

Topologinya terlihat seperti ini:

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Pembaruan harus dimulai dengan replika replika mysql dc 2, mysql master dc 2 ΠΈ mysql replica dc 1, dan diakhiri dengan server mysql master dc 1. Agar lebih andal, kami menghentikan mesin virtual, mengambil snapshotnya, dan segera sebelum pembaruan menghentikan replikasi dengan perintah STOP SLAVE. Pembaruan lainnya terlihat seperti ini:

  1. Kami memulai ulang setiap replika dengan menambahkan 3 opsi ke konfigurasi: skip-networking, skip-slave-start, skip-log-bin. Faktanya adalah memperbarui database menghasilkan log biner dengan pembaruan tabel sistem. Arahan ini menjamin bahwa tidak akan ada perubahan pada data aplikasi dalam database, dan informasi tentang pembaruan tabel sistem tidak akan disertakan dalam log biner. Ini akan menghindari masalah saat melanjutkan replikasi.
  2. Menginstal paket percona-server-server. Penting untuk dicatat bahwa di MySQL versi 8 tidak Anda perlu menjalankan perintah mysqlupgrade setelah pembaruan server.
  3. Setelah permulaan berhasil, kami me-restart server lagi - tanpa parameter yang ditambahkan di paragraf pertama.
  4. Kami memastikan bahwa replikasi berhasil: periksa SHOW SLAVE STATUS dan melihat bahwa tabel dengan penghitung di database aplikasi diperbarui.

Semuanya terlihat cukup sederhana: pembaruan dev berhasil. Oke, Anda dapat dengan aman menjadwalkan pembaruan setiap malam untuk produksi.

Tidak ada kesedihan - kami memperbarui produknya

Namun, perpindahan pengalaman pengembang yang sukses ke produksi bukannya tanpa kejutan.

Untungnya, proses pembaruan itu sendiri dimulai dengan replika, jadi ketika kami mengalami kesulitan, kami menghentikan pekerjaan dan memulihkan replika dari snapshot. Penyelidikan masalah tersebut ditunda hingga keesokan paginya. Log berisi entri berikut:

2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] table: t1 has 19 columns but InnoDB dictionary has 20 columns
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Error in fixing SE data for db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Failed to Populate DD tables.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Aborting

Meneliti arsip berbagai milis di Google menghasilkan pemahaman bahwa masalah ini terjadi karena kesalahan MySQL. Meskipun ini lebih mungkin merupakan bug utilitas mysqlcheck ΠΈ mysqlsh.

Ternyata MySQL mengubah cara mereka merepresentasikan data untuk bidang desimal (int, tinyint, dll.), sehingga server mysql menggunakan cara berbeda untuk menyimpannya. Jika basis data Anda mulanya berada di versi 5.5 atau 5.1, lalu Anda memperbarui ke 5.7, maka Anda mungkin perlu melakukannya OPTIMIZE untuk beberapa tabel. Kemudian MySQL akan memperbarui file data, mentransfernya ke format penyimpanan saat ini.

Anda juga dapat memeriksanya dengan utilitas mysqlfrm:

mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
 'field_length': 8,
  'field_type': 246, # Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ поля
  'field_type_name': 'decimal',
  'flags': 3,
  'flags_extra': 67,
  'interval_nr': 0,
 'name': 'you_deciaml_column',
...

Jika field_type Jika Anda memilikinya sama dengan 0, maka tabel menggunakan tipe lama - Anda perlu melakukan OPTIMIZE. Namun jika nilainya 246, Anda sudah memiliki tipe baru. Informasi lebih lanjut tentang jenisnya dapat ditemukan di kode.

Selain itu, di bug ini Kami sedang mempertimbangkan kemungkinan alasan kedua yang luput dari perhatian kami: tidak adanya tabel InnoDB di tabel sistem INNODB_SYS_TABLESPACES, jika tabel tersebut dibuat di versi 5.1. Untuk menghindari masalah saat update, Anda bisa menggunakan skrip SQL terlampir.

Mengapa kami tidak mengalami masalah seperti itu di dev? Basis data disalin secara berkala di sana dari produksi - dengan demikian, tabel dibuat ulang.

Sayangnya, pada database besar yang benar-benar berfungsi, Anda tidak bisa begitu saja mengambil dan menjalankan database universal OPTIMIZE. percona-toolkit akan membantu di sini: utilitas pt-online-schema-change sangat baik untuk operasi OPTIMIZE online.

Paket yang diperbarui terlihat seperti ini:

  1. Optimalkan semua tabel.
  2. Perbarui database.

Untuk memeriksanya dan sekaligus mengetahui waktu pembaruan, kami menonaktifkan salah satu replika dan menjalankan perintah berikut untuk semua tabel:

pt-online-schema-change --critical-load Threads_running=150 --alter "ENGINE=InnoDB" --execute --chunk-size 100 --quiet --alter-foreign-keys-method auto h=127.0.0.1,u=root,p=${MYSQL_PASSWORD},D=db1,t=t1

Tabel diperbarui tanpa kunci yang panjang karena utilitas membuat tabel sementara baru untuk menyalin data dari tabel utama. Pada saat kedua tabel identik, tabel asli dikunci dan diganti dengan tabel baru. Dalam kasus kami, uji coba menunjukkan bahwa diperlukan waktu sekitar satu hari untuk memperbarui semua tabel, namun menyalin data menyebabkan terlalu banyak beban pada disk.

Untuk menghindari hal ini, dalam produksi kami menambahkan argumen ke perintah --sleep dengan nilai 10 - parameter ini menyesuaikan lama tunggu setelah mentransfer sekumpulan data ke tabel baru. Dengan cara ini Anda dapat mengurangi beban jika aplikasi yang sedang berjalan menuntut waktu respons.

Setelah melakukan optimasi, update berhasil.

...tapi tidak sepenuhnya!

Dalam waktu setengah jam setelah pembaruan, klien datang dengan masalah. Basis data bekerja dengan sangat aneh: dimulai secara berkala koneksi disetel ulang. Berikut penampakannya dalam pemantauan:

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

Tangkapan layar menunjukkan grafik gigi gergaji karena fakta bahwa beberapa thread server MySQL mengalami error secara berkala. Kesalahan muncul di aplikasi:

[PDOException] SQLSTATE[HY000] [2002] Connection refused

Pemeriksaan cepat terhadap log mengungkapkan bahwa daemon mysqld tidak dapat memperoleh sumber daya yang diperlukan dari sistem operasi. Saat memilah kesalahan, kami menemukan di sistem file kebijakan apparmor "yatim piatu".:

# dpkg -S /etc/apparmor.d/cache/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/cache/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/local/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/local/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/usr.sbin.mysqld
mysql-server-5.7: /etc/apparmor.d/usr.sbin.mysqld
# dpkg -l mysql-server-5.7
rc  mysql-server-5.7 5.7.23-0ubuntu0.16.04.1      amd64

File-file ini dibuat saat memutakhirkan ke MySQL 5.7 beberapa tahun yang lalu dan termasuk dalam paket yang dihapus. Menghapus file dan memulai ulang layanan apparmor memecahkan masalah:

systemctl stop apparmor
rm /etc/apparmor.d/cache/usr.sbin.mysqld
rm /etc/apparmor.d/local/usr.sbin.mysqld
rm /etc/apparmor.d/usr.sbin.mysqld
systemctl start apparmor

Sebagai kesimpulan

Apa pun, bahkan operasi yang paling sederhana sekalipun, dapat menyebabkan masalah yang tidak terduga. Dan bahkan memiliki rencana yang matang tidak selalu menjamin hasil yang diharapkan. Sekarang, setiap rencana pembaruan yang dimiliki tim kami juga mencakup pembersihan wajib atas file yang tidak diperlukan yang mungkin muncul akibat tindakan baru-baru ini.

Dan dengan kreativitas grafis yang tidak terlalu profesional ini, saya ingin mengucapkan terima kasih yang sebesar-besarnya kepada Percona atas produk unggulan mereka!

Memperbarui MySQL (Percona Server) dari 5.7 ke 8.0

PS

Baca juga di blog kami:

Sumber: www.habr.com

Tambah komentar