ความคืบหน้าไม่หยุดนิ่ง ดังนั้นเหตุผลในการอัพเกรดเป็น MySQL เวอร์ชันล่าสุดจึงมีความน่าสนใจมากขึ้นเรื่อยๆ ไม่นานมานี้ หนึ่งในโครงการของเรา ถึงเวลาอัปเดตคลัสเตอร์ Percona Server 5.7 ที่สะดวกสบายเป็นเวอร์ชัน 8 ทั้งหมดนี้เกิดขึ้นบนแพลตฟอร์ม Ubuntu Linux 16.04 วิธีดำเนินการดังกล่าวโดยมีเวลาหยุดทำงานน้อยที่สุดและปัญหาใดที่เราพบระหว่างการอัปเดต - อ่านในบทความนี้
การอบรม
การอัพเดตเซิร์ฟเวอร์ฐานข้อมูลมักจะเกี่ยวข้องกับการกำหนดค่าฐานข้อมูลใหม่: การเปลี่ยนแปลงข้อกำหนดสำหรับขีดจำกัดทรัพยากรระบบ และการแก้ไขการกำหนดค่าฐานข้อมูลที่ต้องล้างคำสั่งที่ล้าสมัย
ก่อนที่จะอัปเดต เราจะอ้างอิงถึงเอกสารอย่างเป็นทางการอย่างแน่นอน:
-
บันทึกประจำรุ่น MySQL 8 ; -
คู่มือการอัพเกรด MySQL ; -
คู่มือการอัพเดต Percona ; -
คู่มือ MySQL เพื่ออัปเดตเรพลิกาและมาสเตอร์ .
และมาจัดทำแผนปฏิบัติการกัน:
- แก้ไขไฟล์การกำหนดค่าโดยการลบคำสั่งที่ล้าสมัย
- ตรวจสอบความเข้ากันได้กับยูทิลิตี้
- อัพเดตฐานข้อมูลทาสโดยการติดตั้งแพ็คเกจ
percona-server-server
. - อัพเดตต้นแบบด้วยแพ็คเกจเดียวกัน
ลองดูที่แต่ละจุดของแผนและดูว่ามีอะไรผิดพลาดบ้าง
สำคัญ! ขั้นตอนการอัปเดตคลัสเตอร์ MySQL ที่ใช้ Galera มีรายละเอียดปลีกย่อยของตัวเองที่ไม่ได้อธิบายไว้ในบทความ คุณไม่ควรใช้คำแนะนำนี้ในกรณีนี้
ส่วนที่ 1: การตรวจสอบการกำหนดค่า
MySQL ถูกลบออกในเวอร์ชัน 8 query_cache
. จริงๆแล้วเขาเป็น
นอกจากนี้ในการกำหนดค่ายังมีคำสั่งที่ล้าสมัยอยู่ innodb_file_format
. หากใน MySQL 5.7 สามารถเลือกรูปแบบ InnoDB ได้แสดงว่าเวอร์ชัน 8 ใช้งานได้แล้ว
ผลลัพธ์ของเราคือการลบคำสั่งต่อไปนี้:
-
query_cache_type
,query_cache_limit
иquery_cache_size
; -
innodb_file_format
иinnodb_file_format_max
.
ในการตรวจสอบ เราจะใช้อิมเมจ Docker ของ Percona Server เราจะวางการกำหนดค่าเซิร์ฟเวอร์ไว้ในไดเร็กทอรี mysql_config_test
และถัดจากนั้นเราจะสร้างไดเร็กทอรีสำหรับข้อมูลและบันทึก ตัวอย่างการทดสอบการกำหนดค่าเซิร์ฟเวอร์ 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
บรรทัดล่าง: ทั้งในบันทึกของนักเทียบท่าหรือในไดเร็กทอรีที่มีบันทึก - ขึ้นอยู่กับการกำหนดค่าของคุณ - ไฟล์จะปรากฏขึ้นโดยจะมีการอธิบายคำสั่งที่มีปัญหา
นี่คือสิ่งที่เรามี:
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.
ดังนั้นเราจึงยังคงจำเป็นต้องค้นหาการเข้ารหัสและแทนที่คำสั่งที่ล้าสมัย expire-logs-days
.
ส่วนที่ 2: การตรวจสอบการติดตั้งที่ใช้งานได้
เอกสารการอัพเดตประกอบด้วย 2 ยูทิลิตี้สำหรับตรวจสอบความเข้ากันได้ของฐานข้อมูล การใช้งานช่วยให้ผู้ดูแลระบบตรวจสอบความเข้ากันได้ของโครงสร้างข้อมูลที่มีอยู่
เริ่มจากยูทิลิตี้ mysqlcheck แบบคลาสสิกกันก่อน เพียงเรียกใช้:
mysqlcheck -u root -p --all-databases --check-upgrade
หากไม่พบปัญหา ยูทิลิตี้นี้จะออกด้วยรหัส 0:
นอกจากนี้ ยังมียูทิลิตี้นี้ใน MySQL เวอร์ชันทันสมัยอีกด้วย percona-mysql-shell
). เป็นการทดแทนไคลเอนต์ mysql แบบคลาสสิกและรวมฟังก์ชันของไคลเอนต์ โปรแกรมแก้ไขโค้ด SQL และเครื่องมือการดูแลระบบ MySQL หากต้องการตรวจสอบเซิร์ฟเวอร์ก่อนอัปเดต คุณสามารถรันคำสั่งต่อไปนี้ผ่านเซิร์ฟเวอร์ได้:
mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnf
นี่คือความคิดเห็นที่เราได้รับ:
โดยทั่วไปไม่มีอะไรสำคัญ - มีเพียงคำเตือนเกี่ยวกับการเข้ารหัสเท่านั้น (ดูด้านล่าง). ผลการดำเนินการโดยรวม:
เราตัดสินใจว่าการอัปเดตควรจะดำเนินไปโดยไม่มีปัญหา
หมายเหตุเกี่ยวกับคำเตือนข้างต้นซึ่งระบุถึงปัญหาในการเข้ารหัส ความจริงก็คือ UTF-8 ใน MySQL จนกระทั่งเมื่อไม่นานมานี้ utf8
จะนำไปสู่การเข้ารหัสในไม่ช้า utf8mb4
และคอลัมน์เก่าในตารางจะกลายเป็น utf8mb3
. การเข้ารหัสเพิ่มเติม utf8mb3
จะถูกลบออก แต่ไม่ใช่ในรุ่นนี้ ดังนั้นเราจึงตัดสินใจแก้ไขการเข้ารหัสที่มีอยู่แล้วในการติดตั้ง DBMS ที่ทำงานอยู่หลังจากอัปเดตแล้ว
ส่วนที่ 3: การอัปเดตเซิร์ฟเวอร์
จะเกิดอะไรขึ้นเมื่อมีแผนอันชาญฉลาดเช่นนั้น.. ด้วยความเข้าใจอย่างถ่องแท้ว่าความแตกต่างเล็กๆ น้อยๆ เกิดขึ้นได้เสมอ เราจึงทำการทดลองครั้งแรกกับคลัสเตอร์ MySQL dev
ดังที่ได้กล่าวมาแล้ว
โทโพโลยีมีลักษณะดังนี้:
การอัปเดตต้องเริ่มต้นด้วยการจำลอง mysql จำลอง dc2, mysql มาสเตอร์ ดีซี 2 и mysql replica dc 1
และปิดท้ายด้วยเซิร์ฟเวอร์ mysql master dc 1 เพื่อให้เชื่อถือได้มากขึ้น เราได้หยุดเครื่องเสมือน ถ่ายภาพสแนปชอตของเครื่องเหล่านั้น และทันทีก่อนที่การอัปเดตจะหยุดการจำลองด้วยคำสั่ง STOP SLAVE
. การอัปเดตที่เหลือมีลักษณะดังนี้:
- เรารีสตาร์ทแต่ละเรพลิกาโดยเพิ่ม 3 ตัวเลือกให้กับการกำหนดค่า:
skip-networking
,skip-slave-start
,skip-log-bin
. ความจริงก็คือการอัพเดตฐานข้อมูลจะสร้างบันทึกไบนารีพร้อมการอัพเดตตารางระบบ คำสั่งเหล่านี้รับประกันว่าจะไม่มีการเปลี่ยนแปลงข้อมูลแอปพลิเคชันในฐานข้อมูล และข้อมูลเกี่ยวกับการอัปเดตตารางระบบจะไม่รวมอยู่ในบันทึกไบนารี วิธีนี้จะหลีกเลี่ยงปัญหาเมื่อดำเนินการจำลองแบบต่อ - กำลังติดตั้งแพ็คเกจ
percona-server-server
. สิ่งสำคัญคือต้องทราบว่าใน MySQL เวอร์ชัน 8 ไม่ คุณต้องรันคำสั่งmysqlupgrade
หลังจากอัพเดตเซิร์ฟเวอร์ - หลังจากเริ่มต้นได้สำเร็จ เราจะรีสตาร์ทเซิร์ฟเวอร์อีกครั้ง - โดยไม่มีพารามิเตอร์ที่เพิ่มไว้ในย่อหน้าแรก
- ตรวจสอบให้แน่ใจว่าการจำลองแบบทำงานได้สำเร็จ: ตรวจสอบ
SHOW SLAVE STATUS
และดูว่าตารางที่มีตัวนับในฐานข้อมูลแอปพลิเคชันได้รับการอัปเดตแล้ว
ทุกอย่างดูเรียบง่าย: การอัปเดต dev สำเร็จแล้ว ตกลง คุณสามารถกำหนดเวลาการอัปเดตการผลิตทุกคืนได้อย่างปลอดภัย
ไม่มีความโศกเศร้า - เราอัปเดตผลิตภัณฑ์แล้ว
อย่างไรก็ตาม การถ่ายโอนประสบการณ์การพัฒนาที่ประสบความสำเร็จไปสู่การผลิตไม่ใช่เรื่องน่าประหลาดใจเลย
โชคดีที่กระบวนการอัปเดตนั้นเริ่มต้นด้วยการจำลอง ดังนั้นเมื่อเราประสบปัญหา เราก็หยุดงานและกู้คืนแบบจำลองจากสแน็ปช็อต การสอบสวนปัญหาถูกเลื่อนออกไปเป็นเช้าวันรุ่งขึ้น บันทึกมีรายการต่อไปนี้:
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
การค้นคว้าข้อมูลที่เก็บถาวรของรายชื่อผู้รับจดหมายต่างๆ บน Google ทำให้เกิดความเข้าใจว่าปัญหานี้เกิดขึ้นเนื่องจาก mysqlcheck
и mysqlsh
.
ปรากฎว่า MySQL เปลี่ยนวิธีการแสดงข้อมูลสำหรับเขตข้อมูลทศนิยม (int, Tinyint ฯลฯ) ดังนั้นเซิร์ฟเวอร์ mysql จึงใช้วิธีอื่นในการจัดเก็บข้อมูล หากฐานข้อมูลของคุณ เริ่มแรก อยู่ในเวอร์ชัน 5.5 หรือ 5.1 จากนั้นคุณอัปเดตเป็น 5.7 แล้วคุณอาจต้องทำ OPTIMIZE
สำหรับบางโต๊ะ จากนั้น MySQL จะอัปเดตไฟล์ข้อมูลโดยถ่ายโอนเป็นรูปแบบที่จัดเก็บข้อมูลปัจจุบัน
คุณสามารถตรวจสอบสิ่งนี้ได้ด้วยยูทิลิตี้นี้ 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',
...
ถ้า field_type
หากคุณมีค่าเท่ากับ 0 แสดงว่าตารางจะใช้แบบเก่า - คุณต้องดำเนินการ OPTIMIZE
. อย่างไรก็ตาม หากค่าเป็น 246 แสดงว่าคุณมีประเภทใหม่แล้ว ข้อมูลเพิ่มเติมเกี่ยวกับประเภทสามารถพบได้ใน
นอกจากนี้ใน INNODB_SYS_TABLESPACES
หากตารางถูกสร้างขึ้นในเวอร์ชัน 5.1 คุณสามารถใช้เพื่อหลีกเลี่ยงปัญหาในการอัพเดต
ทำไมเราไม่พบปัญหาดังกล่าวใน dev? ฐานข้อมูลจะถูกคัดลอกเป็นระยะจากการผลิต - ดังนั้น ตารางจะถูกสร้างขึ้นใหม่.
น่าเสียดายที่บนฐานข้อมูลขนาดใหญ่ที่ใช้งานได้ดี คุณจะไม่สามารถดำเนินการและดำเนินการแบบสากลได้ OPTIMIZE
. percona-toolkit จะช่วยได้ที่นี่: ยูทิลิตี้ pt-online-schema-change นั้นยอดเยี่ยมสำหรับการดำเนินการ OPTIMIZE ออนไลน์
แผนที่อัปเดตมีลักษณะดังนี้:
- เพิ่มประสิทธิภาพตารางทั้งหมด
- อัพเดตฐานข้อมูล
เพื่อตรวจสอบและค้นหาเวลาอัปเดตในเวลาเดียวกัน เราได้ปิดการใช้งานหนึ่งในเรพลิกาและรันคำสั่งต่อไปนี้สำหรับตารางทั้งหมด:
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
ตารางได้รับการอัปเดตโดยไม่มีการล็อคที่ยาวเนื่องจากยูทิลิตี้สร้างตารางชั่วคราวใหม่เพื่อคัดลอกข้อมูลจากตารางหลัก ในขณะที่ทั้งสองตารางเหมือนกัน ตารางเดิมจะถูกล็อคและแทนที่ด้วยตารางใหม่ ในกรณีของเรา การทดสอบแสดงให้เห็นว่าจะใช้เวลาประมาณหนึ่งวันในการอัปเดตตารางทั้งหมด แต่การคัดลอกข้อมูลทำให้ดิสก์มีภาระมากเกินไป
เพื่อหลีกเลี่ยงปัญหานี้ ในการผลิตเราได้เพิ่มอาร์กิวเมนต์ให้กับคำสั่ง --sleep
ด้วยค่า 10 - พารามิเตอร์นี้จะปรับระยะเวลารอหลังจากถ่ายโอนชุดข้อมูลไปยังตารางใหม่ วิธีนี้ทำให้คุณสามารถลดภาระได้หากแอปพลิเคชันที่ทำงานอยู่จริงต้องการเวลาตอบสนอง
หลังจากดำเนินการปรับให้เหมาะสมแล้ว การอัปเดตก็สำเร็จ
...แต่ยังไม่หมด!
ภายในครึ่งชั่วโมงหลังจากการอัพเดต ลูกค้าก็ประสบปัญหา ฐานข้อมูลทำงานแปลกมาก: เริ่มทำงานเป็นระยะ รีเซ็ตการเชื่อมต่อ. นี่คือสิ่งที่ดูเหมือนในการตรวจสอบ:
ภาพหน้าจอแสดงกราฟฟันเลื่อยเนื่องจากเธรดเซิร์ฟเวอร์ MySQL บางเธรดขัดข้องเป็นระยะโดยมีข้อผิดพลาด ข้อผิดพลาดปรากฏในแอปพลิเคชัน:
[PDOException] SQLSTATE[HY000] [2002] Connection refused
การตรวจสอบบันทึกอย่างรวดเร็วพบว่า mysqld daemon ไม่สามารถรับทรัพยากรที่จำเป็นจากระบบปฏิบัติการได้ ขณะแยกแยะข้อผิดพลาด เราค้นพบในระบบ ไฟล์นโยบาย apparmor "orphan":
# 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
ไฟล์เหล่านี้ถูกสร้างขึ้นเมื่ออัปเกรดเป็น MySQL 5.7 เมื่อสองสามปีก่อนและเป็นของแพ็คเกจที่ถูกลบออก การลบไฟล์และการรีสตาร์ทบริการ apparmor ช่วยแก้ปัญหาได้:
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
ในข้อสรุป
แม้แต่การดำเนินการที่ง่ายที่สุดก็สามารถนำไปสู่ปัญหาที่ไม่คาดคิดได้ และแม้แต่การมีแผนงานที่คิดมาอย่างดีก็ไม่ได้รับประกันผลลัพธ์ที่คาดหวังเสมอไป ขณะนี้ แผนการอัปเดตใดๆ ที่ทีมของเราได้รวมการบังคับล้างไฟล์ที่ไม่จำเป็นซึ่งอาจปรากฏขึ้นอันเป็นผลมาจากการกระทำล่าสุด
และด้วยความคิดสร้างสรรค์กราฟิกที่ไม่เป็นมืออาชีพมากนัก ฉันอยากจะขอบคุณ Percona อย่างมากสำหรับผลิตภัณฑ์ที่ยอดเยี่ยมของพวกเขา!
PS
อ่านเพิ่มเติมในบล็อกของเรา:
- «
ฐานข้อมูลและ Kubernetes (รีวิวและรายงานวิดีโอ) "; - «
เคล็ดลับและเทคนิค Kubernetes: เร่งความเร็วบูตสแตรปสำหรับฐานข้อมูลขนาดใหญ่ "; - «
6 เรื่องราวเชิงปฏิบัติจากชีวิตประจำวัน SRE ของเรา "; - «
เรื่องราวหนึ่งเกี่ยวกับตัวดำเนินการ Redis ใน K8 และการตรวจสอบยูทิลิตี้ขนาดเล็กสำหรับการวิเคราะห์ข้อมูลจากฐานข้อมูลนี้ "; - «
การย้าย MongoDB ไปยัง Kubernetes ได้อย่างราบรื่น '
ที่มา: will.com