Memutakhirkan MySQL (Percona Server) dari 5.7 ke 8.0



Kemajuan tidak berhenti, jadi alasan untuk meningkatkan ke versi terbaru MySQL menjadi semakin signifikan. Belum lama berselang, di salah satu proyek kami, tiba saatnya untuk meningkatkan cluster Percona Server 5.7 yang nyaman ke versi 8. Semua ini terjadi pada platform Ubuntu Linux 16.04. Cara melakukan operasi serupa dengan downtime minimal dan masalah apa yang kami temui selama peningkatan - baca artikel ini.

Latihan


Setiap pembaruan dari server database kemungkinan besar terhubung dengan migrasi database: perubahan dalam persyaratan untuk batas sumber daya sistem dan koreksi konfigurasi database, yang harus dibersihkan dari arahan yang ketinggalan zaman.

Sebelum memperbarui, kami pasti akan beralih ke dokumentasi resmi:


Dan buatlah rencana aksi:

  1. Perbaiki file konfigurasi dengan menghapus arahan usang.
  2. Periksa kompatibilitas dengan utilitas.
  3. Perbarui database budak dengan menginstal paket percona-server-server.
  4. Perbarui wizard dengan meletakkan paket yang sama.

Kami akan menganalisis setiap item dalam rencana dan melihat apa yang salah.

PENTING! Prosedur pemutakhiran kluster MySQL berbasis Galera memiliki kehalusannya sendiri yang tidak dijelaskan dalam artikel. Anda tidak boleh menggunakan instruksi ini dalam kasus ini.

Bagian 1: Memeriksa Konfigurasi


Di versi 8, MySQL telah dihapus query_cache. Bahkan, itu dinyatakan usang kembali dalam versi 5.7, tetapi sekarang sudah benar - benar dihapus . Oleh karena itu, perlu untuk menghapus arahan terkait. Dan untuk permintaan caching, Anda sekarang dapat menggunakan alat eksternal - misalnya, ProxySQL .

Arahan pro usang juga ditemukan di konfigurasi innodb_file_format. Jika di MySQL 5.7 dimungkinkan untuk memilih format InnoDB, maka versi ke-8 hanya berfungsi dengan format Barracuda .

Hasil kami adalah penghapusan arahan berikut:

  • query_cache_type, query_cache_limitdan query_cache_size;
  • innodb_file_formatdan innodb_file_format_max.

Untuk verifikasi, kami akan menggunakan gambar Percona Server Docker. Kami akan meletakkan konfigurasi server di direktori mysql_config_test, dan selanjutnya membuat direktori untuk data dan log. Contoh uji konfigurasi percona-server:

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

Hasil: baik dalam log Docker, atau dalam direktori dengan log - tergantung pada konfigurasi Anda - file akan muncul di mana arahan masalah akan dijelaskan.

Inilah yang kami miliki:

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.

Dengan demikian, kami masih perlu berurusan dengan penyandian dan mengganti arahan usang expire-logs-days.

Bagian 2: Memverifikasi instalasi yang sedang berjalan


Ada 2 utilitas dalam dokumentasi pembaruan untuk memeriksa kompatibilitas database. Penggunaannya membantu administrator memverifikasi kompatibilitas struktur data yang ada.

Mari kita mulai dengan utilitas mysqlcheck klasik. Cukup jalankan:

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

Jika tidak ada masalah yang terdeteksi, utilitas akan keluar dengan kode 0:



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

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

Dan berikut adalah komentar yang kami terima:



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



Kami memutuskan bahwa pembaruan harus berjalan tanpa masalah.

Catatan tentang peringatan di atas yang mengindikasikan masalah penyandian. Faktanya adalah bahwa UTF-8 di MySQL sampai saat ini bukanlah UTF-8 yang "nyata" , karena UTF-8 hanya menyimpan 3 byte, bukannya 4. Dalam MySQL 8, mereka akhirnya memutuskan untuk memperbaikinya : alias utf8akan segera mengarah ke penyandian utf8mb4, dan yang lama kolom dalam tabel akan menjadi utf8mb3. Di masa depan, penyandian utf8mb3akan dihapus, tetapi tidak dalam rilis ini. Oleh karena itu, kami memutuskan untuk memperbaiki penyandian pada instalasi DBMS yang berfungsi, setelah memperbaruinya.

Bagian 3: Pembaruan Server


Apa yang bisa salah ketika ada rencana yang sangat bagus? .. Sadar bahwa nuansa selalu terjadi, kami melakukan percobaan pertama pada klaster dev MySQL.

Seperti yang telah disebutkan, dokumentasi resmi menyoroti masalah memperbarui server MySQL dengan replika. Intinya adalah bahwa pada awalnya ada baiknya memperbarui semua replika (budak), karena MySQL 8 dapat mereplikasi dari wizard versi 5.7. Beberapa kesulitan terletak pada kenyataan bahwa kita menggunakan mode master <-> master ketika master jarak jauh dalam mode read-only . Faktanya, lalu lintas tempur memasuki satu pusat data, dan yang kedua adalah cadangan.

Topologi adalah sebagai berikut:



Upgrade harus dimulai dengan replika mysql dc 2 replika, mysql master dc 2 dan mysql replica dc 1, dan berakhir dengan server mysql master dc 1. Untuk keandalan yang lebih baik, kami menghentikan mesin virtual, membuatnya snapshots, dan menghentikan replikasi dengan perintah sesaat sebelum pembaruan STOP SLAVE. Sisa pembaruan terlihat seperti ini:

  1. Setiap replika restart, menambahkan konfigurasi opsi 3: skip-networking, skip-slave-start, skip-log-bin. Faktanya adalah bahwa memperbarui database menghasilkan log biner dengan memperbarui tabel sistem. Arahan ini menjamin bahwa tidak akan ada perubahan pada data aplikasi dalam database, dan informasi tentang memperbarui tabel sistem tidak akan masuk ke log biner. Ini akan menghindari masalah saat melanjutkan replikasi.
  2. Instal paket percona-server-server. Penting untuk dicatat bahwa di MySQL 8, Anda tidak perlu menjalankan perintah mysqlupgradesetelah memperbarui server.
  3. Setelah awal yang berhasil, restart server lagi - sudah tanpa parameter yang ditambahkan pada paragraf pertama.
  4. Kami memastikan bahwa replikasi bekerja dengan sukses: kami memeriksa SHOW SLAVE STATUSdan melihat bahwa tabel dengan penghitung dalam database aplikasi diperbarui.

Semua ini terlihat cukup sederhana: pembaruan dev berhasil. Ok, Anda dapat dengan aman merencanakan upgrade semalam untuk produksi.

Tidak ada kesedihan - kami memperbarui prod


Namun, port pengalaman pengembang yang sukses untuk produksi bukan tanpa kejutan.

Untungnya, proses pembaruan itu sendiri dimulai dengan replika, oleh karena itu, setelah mengalami kesulitan, kami berhenti bekerja dan mengembalikan replika dari snapshot. Studi masalah dijadwalkan kembali keesokan paginya. Entri berikut muncul di log:

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

Sebuah studi tentang arsip berbagai milis di Google mengarah pada pemahaman bahwa masalah seperti itu muncul karena bug MySQL . Meskipun lebih tepatnya itu adalah bug utilitas mysqlcheckdan mysqlsh.

Ternyata MySQL telah mengubah cara data disajikan untuk bidang desimal (int, tinyint, dll.), Jadi cara lain untuk menyimpannya adalah digunakan di dalam mysql-server. Jika database Anda awalnya dalam versi 5.5 atau 5.1, dan kemudian Anda ditingkatkan ke 5.7, maka Anda mungkin perlu membuat OPTIMIZEbeberapa tabel. Kemudian MySQL akan memperbarui file data, mentransfernya ke format penyimpanan saat ini.

Anda juga dapat memeriksa ini 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_typeAnda memiliki 0, maka tipe lama digunakan dalam tabel - itu harus dilakukan OPTIMIZE. Namun, jika nilainya 246, Anda sudah memiliki tipe baru. Informasi lebih lanjut tentang jenis dapat ditemukan dalam kode .

Selain itu, bug ini mempertimbangkan kemungkinan alasan kedua yang telah melewati kami - kurangnya tabel InnoDB dalam tabel sistem INNODB_SYS_TABLESPACES, jika mereka, tabel, dibuat dalam versi 5.1. Untuk menghindari masalah selama pemutakhiran, Anda dapat menggunakan skrip SQL terlampir .

Mengapa kita tidak memiliki masalah seperti itu pada dev? Basis disalin secara berkala di sana dari produksi - dengan demikian, tabel diciptakan kembali .

Sayangnya, pada basis data besar yang benar-benar berfungsi tidak akan berfungsi hanya untuk mengambil dan melakukan yang ada di mana-mana OPTIMIZE. Percona-toolkit akan membantu di sini: utilitas perubahan skema pt-online sangat bagus untuk operasi OPTIMASI online.

Paket yang diperbarui adalah sebagai berikut:

  1. Optimalkan semua tabel.
  2. Lakukan pemutakhiran basis data.

Untuk memeriksanya dan pada saat yang sama mengetahui waktu pembaruan, kami menonaktifkan salah satu replika, dan untuk semua tabel kami menjalankan perintah berikut:

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 panjang karena fakta bahwa utilitas membuat tabel sementara baru di mana ia menyalin data dari tabel utama. Pada saat kedua tabel identik, tabel asli dikunci dan diganti dengan yang baru. Dalam kasus kami, uji coba menunjukkan bahwa memperbarui semua tabel akan memakan waktu sekitar satu hari, tetapi menyalin data menyebabkan terlalu banyak memuat pada disk.

Untuk menghindari ini, pada produksi kami menambahkan argumen --sleepdengan nilai 10 ke perintah - parameter ini mengontrol panjang menunggu setelah mentransfer paket data ke tabel baru. Dengan cara ini Anda dapat mengurangi beban jika aplikasi yang benar-benar berjalan membutuhkan waktu respons.

Setelah melakukan optimasi, pembaruan berhasil.

... tapi tidak sepenuhnya!


Setengah jam setelah pembaruan, klien menemukan masalah. Pangkalan itu bekerja sangat aneh: secara berkala, koneksi terputus . Inilah yang tampak dalam pemantauan:



Grafik gigi gergaji terlihat di tangkapan layar, karena fakta bahwa bagian dari utas server MySQL secara berkala jatuh dengan kesalahan. Kesalahan muncul di aplikasi:

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

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

# 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 dibentuk selama peningkatan ke MySQL 5.7 beberapa tahun yang lalu dan termasuk dalam paket jarak jauh. Menghapus file dan memulai kembali 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

Akhirnya


Apa pun, bahkan operasi paling sederhana, dapat menyebabkan masalah yang tidak terduga. Dan bahkan memiliki rencana yang dipikirkan dengan matang tidak selalu menjamin hasil yang diharapkan. Sekarang, dalam rencana pembaruan apa pun, tim kami juga menyertakan pembersihan wajib file tambahan yang dapat muncul sebagai akibat dari tindakan terbaru.

Dan dengan karya grafis yang tidak terlalu profesional ini, saya ingin mengucapkan terima kasih kepada Percona atas produk hebat mereka!



PS


Baca juga di blog kami:


All Articles