MySQL ความพร้อมใช้งานสูงในการผลิต: คลัสเตอร์ InnoDB, การจำลองแบบกลุ่ม และตัวดำเนินการ Kubernetes
คู่มือวิศวกรฝ่ายผลิตเกี่ยวกับ InnoDB Cluster, Group Replication, MySQL Operator สำหรับ Kubernetes, Percona XtraDB Cluster, กลยุทธ์มัลติคลาวด์ และการปรับใช้ Bare Metal k3s/Rancher พร้อมพื้นที่จัดเก็บ Longhorn
การใช้งาน MySQL ในการผลิตถือเป็นขอบเขตที่คุ้นเคยสำหรับทีมวิศวกรส่วนใหญ่ การรันด้วยความพร้อมใช้งานสูงของแท้ — ในกรณีที่โหนดล้มเหลว พาร์ติชันเครือข่าย หรือ Availability Zone ทั้งหมดดับลง ไม่ส่งผลให้ระบบหยุดทำงานหรือสูญเสียข้อมูล — ต้องใช้สถาปัตยกรรมโดยเจตนา คู่มือนี้จะอธิบายทุกชั้นของสถาปัตยกรรมนั้น ตั้งแต่การจำลองแบบดั้งเดิมภายใน MySQL เอง ผ่านตัวดำเนินการ Kubernetes ที่ทำให้การจัดการวงจรชีวิตเป็นแบบอัตโนมัติ ตลอดทั้งตัวเลือกที่มีการจัดการและจัดการด้วยตนเองบนผู้ให้บริการระบบคลาวด์รายใหญ่ทุกราย ไปจนถึงคลัสเตอร์ Bare Metal k3s ที่จัดการโดย Rancher
ในตอนท้ายของบทความนี้ คุณจะมีแบบจำลองทางจิตที่สมบูรณ์สำหรับการเลือกและใช้งาน MySQL HA ในการผลิต พร้อมด้วยตัวอย่างการกำหนดค่าที่เป็นรูปธรรมที่คุณสามารถปรับให้เข้ากับสภาพแวดล้อมของคุณเองได้
MySQL สถาปัตยกรรมคลัสเตอร์ InnoDB
InnoDB Cluster เป็นโซลูชันความพร้อมใช้งานสูงแบบผสานรวมของ Oracle สำหรับ MySQL ประกอบด้วยสามองค์ประกอบ: MySQL Group Replication สำหรับการซิงโครไนซ์ข้อมูล, MySQL Shell สำหรับการดูแลคลัสเตอร์ และ MySQL Router สำหรับการกำหนดเส้นทางการเชื่อมต่อที่โปร่งใสและการเฟลโอเวอร์อัตโนมัติ พวกเขาร่วมกันสร้างคลัสเตอร์การรักษาตัวเองที่สามารถทนต่อความล้มเหลวของโหนดโดยไม่ต้องมีการแทรกแซงด้วยตนเอง
สถาปัตยกรรมที่หรูหราในความเรียบง่าย แอปพลิเคชันเชื่อมต่อกับเราเตอร์ MySQL ซึ่งรักษาการรับรู้เกี่ยวกับโทโพโลยีคลัสเตอร์โดยการสืบค้นสคีมาข้อมูลเมตาของคลัสเตอร์ InnoDB เมื่อตัวหลักล้มเหลว การจำลองแบบกลุ่มจะเลือกตัวหลักใหม่จากตัวรองที่เหลือ และเราเตอร์ MySQL จะเปลี่ยนเส้นทางการเขียนข้อมูลไปยังตัวหลักใหม่โดยอัตโนมัติ โดยทั่วไปภายในไม่กี่วินาที ปริมาณการอ่านสามารถกระจายไปยังส่วนรองทั้งหมดเพื่อปรับขนาดการอ่านแนวนอน
พื้นฐานการจำลองแบบกลุ่มMySQL Group Replication เป็นรากฐานของ InnoDB Cluster ใช้โปรโตคอลฉันทามติตาม Paxos เพื่อให้แน่ใจว่าทุกธุรกรรมที่กระทำบนหลักจะถูกจำลองไปยังโหนดส่วนใหญ่ก่อนที่จะได้รับการยอมรับ ซึ่งจะมอบการจำลองแบบซิงโครนัสเสมือนซึ่งเป็นการรับประกันว่าข้อมูลที่คอมมิตมีอยู่บนสมาชิกคลัสเตอร์ส่วนใหญ่เป็นอย่างน้อย ณ เวลาที่คอมมิต
Group Replication ทำงานในสองโหมด:
- โหมดหลักเดียว- โหนดหนึ่งยอมรับการเขียน (โหนดหลัก); ส่วนอื่นๆ ทั้งหมดเป็นรายการรองแบบอ่านอย่างเดียว นี่คือโหมดที่แนะนำและโหมดเริ่มต้น หลีกเลี่ยงข้อขัดแย้งในการเขียนโดยสิ้นเชิงเนื่องจากมีเพียงโหนดเดียวเท่านั้นที่สามารถสร้างธุรกรรมได้
- โหมดหลายหลัก— โหนดทั้งหมดยอมรับการเขียนพร้อมกัน ซึ่งให้ปริมาณงานการเขียนที่สูงกว่าสำหรับปริมาณงานที่แบ่งพาร์ติชันระหว่างตารางหรือคีย์สเปซที่แตกต่างกันอย่างหมดจด แต่จะทำให้เกิดข้อขัดแย้งในการรับรองเมื่อธุรกรรมที่เกิดขึ้นพร้อมกันแก้ไขแถวเดียวกัน ธุรกรรมที่ขัดแย้งกันจะถูกย้อนกลับบนโหนดเดียว ใช้หลายหลักเฉพาะเมื่อแอปพลิเคชันของคุณได้รับการออกแบบมาเพื่อจัดการกับความล้มเหลวของการรับรองและตรรกะในการลองใหม่
การตั้งค่าคลัสเตอร์ InnoDB ด้วย MySQL Shell
MySQL Shell มอบ AdminAPI ซึ่งเป็นชุดฟังก์ชันที่ทำให้วงจรชีวิตของคลัสเตอร์ทั้งหมดเป็นแบบอัตโนมัติ ต่อไปนี้เป็นลำดับการตั้งค่าที่สมบูรณ์สำหรับคลัสเตอร์ 3 โหนด
# Step 1: Prepare each MySQL instance (run on all 3 nodes)
# Ensure my.cnf has required settings
[mysqld]
server-id=1 # unique per node: 1, 2, 3
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
binlog_transaction_dependency_tracking=WRITESET
transaction_write_set_extraction=XXHASH64
loose-group_replication_start_on_boot=OFF
plugin_load_add='group_replication.so'
plugin_load_add='mysql_clone.so'
report_host='mysql-node-1' # unique per node
# Step 2: Use MySQL Shell to configure and create the cluster
mysqlsh -- dba configure-instance root@mysql-node-1:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
mysqlsh -- dba configure-instance root@mysql-node-2:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
mysqlsh -- dba configure-instance root@mysql-node-3:3306 --clusterAdmin=gradmin --clusterAdminPassword='SecurePass123!'
# Step 3: Connect to the first node and create the cluster
mysqlsh gradmin@mysql-node-1:3306
# Inside MySQL Shell:
var cluster = dba.createCluster('productionCluster', {
memberWeight: 90,
exitStateAction: 'ABORT_SERVER',
consistency: 'BEFORE_ON_PRIMARY_FAILOVER',
expelTimeout: 10
})
# Step 4: Add remaining nodes
cluster.addInstance('gradmin@mysql-node-2:3306', {recoveryMethod: 'clone'})
cluster.addInstance('gradmin@mysql-node-3:3306', {recoveryMethod: 'clone'})
# Step 5: Verify cluster status
cluster.status()
ตัวเลือกrecoveryMethod: 'clone'ใช้ MySQL Clone Plugin เพื่อทำสำเนาข้อมูลทั้งหมดจากข้อมูลหลักไปยังสมาชิกที่เข้าร่วม ซึ่งเร็วกว่าการกู้คืนส่วนเพิ่มจากบันทึกไบนารีสำหรับชุดข้อมูลขนาดใหญ่มาก
MySQL การกำหนดค่าเราเตอร์
เราเตอร์MySQL ได้รับการบูตเข้ากับคลัสเตอร์และสร้างไฟล์การกำหนดค่าโดยอัตโนมัติ
# Bootstrap MySQL Router against the cluster
mysqlrouter --bootstrap gradmin@mysql-node-1:3306 \
--directory /opt/mysqlrouter \
--conf-use-sockets \
--user=mysqlrouter \
--name='production-router'
# Start MySQL Router
/opt/mysqlrouter/start.sh
# Default ports after bootstrap:
# 6446 — R/W (routes to primary)
# 6447 — R/O (round-robin across secondaries)
# 6448 — R/W (X Protocol)
# 6449 — R/O (X Protocol)
แอปพลิเคชันเชื่อมต่อกับพอร์ต R/W ของเราเตอร์สำหรับการเขียนและพอร์ต R/O สำหรับการจำลองการอ่าน เมื่อเครือข่ายหลักล้มเหลว เราเตอร์จะตรวจพบการเปลี่ยนแปลงโทโพโลยีและกำหนดเส้นทางใหม่ภายในไม่กี่วินาที
การปรับใช้ MySQL หลายภูมิภาค
สำหรับการกู้คืนความเสียหายและการอ่านข้อมูลที่มีความหน่วงต่ำในพื้นที่ต่างๆ MySQL สามารถใช้งานได้ในหลายภูมิภาค InnoDB ClusterSet ขยาย InnoDB Cluster เพื่อรองรับการจำลองแบบอะซิงโครนัสระหว่างคลัสเตอร์หลักและคลัสเตอร์แบบจำลองตั้งแต่หนึ่งคลัสเตอร์ขึ้นไปในภูมิภาคต่างๆ
InnoDB ClusterSet ทำงานร่วมกับคลัสเตอร์หลักหนึ่งคลัสเตอร์ที่จัดการการเขียนทั้งหมด และคลัสเตอร์แบบจำลองอย่างน้อยหนึ่งคลัสเตอร์ที่ได้รับการเปลี่ยนแปลงแบบอะซิงโครนัส ในสถานการณ์ภัยพิบัติ คลัสเตอร์แบบจำลองสามารถเลื่อนระดับเป็นคลัสเตอร์หลักผ่าน MySQL Shell
# Create a ClusterSet from an existing InnoDB Cluster
mysqlsh gradmin@mysql-node-1:3306
var cluster = dba.getCluster()
var cs = cluster.createClusterSet('globalSet')
# Create a replica cluster in eu-west region
cs.createReplicaCluster('gradmin@mysql-eu-node-1:3306', 'euWestCluster', {
recoveryMethod: 'clone'
})
var euCluster = cs.getCluster('euWestCluster')
euCluster.addInstance('gradmin@mysql-eu-node-2:3306', {recoveryMethod: 'clone'})
euCluster.addInstance('gradmin@mysql-eu-node-3:3306', {recoveryMethod: 'clone'})
# Emergency failover (when primary cluster is unreachable)
cs.forcePrimaryCluster('euWestCluster')
MySQL บน Kubernetes — รูปแบบตัวดำเนินการ
การรัน MySQL บน Kubernetes จำเป็นต้องมีการแก้ปัญหาท้าทายหลายประการซึ่งใช้ไม่ได้กับปริมาณงานไร้สถานะ ได้แก่ ข้อมูลระบุตัวตนเครือข่ายที่เสถียร พื้นที่จัดเก็บข้อมูลถาวร การสั่งการเริ่มต้นและการปิดระบบ และการตรวจสอบสภาพการทำงานของคลัสเตอร์ ตัวดำเนินการ Kubernetes เข้ารหัสความรู้การปฏิบัติงานเฉพาะโดเมนนี้ลงในตัวควบคุมที่เฝ้าดูทรัพยากรที่กำหนดเองและปรับสถานะที่แท้จริงของ MySQL ให้สอดคล้องกับสถานะที่ต้องการที่ประกาศใน YAML
MySQL โอเปอเรเตอร์สำหรับ Kubernetes (Oracle)
MySQL Operator ของ Oracle สำหรับ Kubernetes ปรับใช้และจัดการอินสแตนซ์ InnoDB Cluster บน Kubernetes โดยจะสร้าง StatefulSets สำหรับพ็อดเซิร์ฟเวอร์ MySQL, การปรับใช้สำหรับเราเตอร์ MySQL และจัดการการเปลี่ยนระบบอัตโนมัติ การปรับขนาด การสำรองข้อมูล และการเปลี่ยนแปลงการกำหนดค่า
# Install the MySQL Operator via Helm
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
helm install mysql-operator mysql-operator/mysql-operator \
--namespace mysql-operator \
--create-namespace \
--set image.pullPolicy=IfNotPresent
เมื่อโอเปอเรเตอร์ทำงาน ให้ปรับใช้คลัสเตอร์ InnoDB โดยการสร้างทรัพยากรที่กำหนดเอง
apiVersion: v1
kind: Secret
metadata:
name: mysql-root-credentials
namespace: production
stringData:
rootUser: root
rootHost: '%'
rootPassword: 'ProductionSecurePass123!'
---
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: production-mysql
namespace: production
spec:
secretName: mysql-root-credentials
instances: 3
tlsUseSelfSigned: true
router:
instances: 2
datadirVolumeClaimTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: gp3-encrypted
mycnf: |
[mysqld]
innodb_buffer_pool_size=4G
innodb_log_file_size=1G
innodb_flush_log_at_trx_commit=1
sync_binlog=1
max_connections=500
innodb_io_capacity=2000
innodb_io_capacity_max=4000
innodb_read_io_threads=8
innodb_write_io_threads=8
performance_schema=ON
slow_query_log=ON
long_query_time=1
podSpec:
containers:
- name: mysql
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16Gi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: component
operator: In
values: [mysqld]
topologyKey: topology.kubernetes.io/zone
กฎการต่อต้านความสัมพันธ์ของพ็อดทำให้มั่นใจได้ว่าพ็อด MySQL จะกระจายไปทั่วโซนความพร้อมใช้งาน โดยให้ความทนทานต่อข้อผิดพลาดระดับโซน บล็อกmycnfช่วยให้คุณสามารถฉีดการกำหนดค่า MySQL ที่ปรับแต่งตามการผลิตได้โดยตรงผ่าน CR
ตัวดำเนินการ Percona สำหรับ MySQL (PXC)
Percona Operator สำหรับ MySQL ปรับใช้ Percona XtraDB Cluster (PXC) ซึ่งเป็นโซลูชันการจำลองแบบซิงโครนัสหลายหลักที่ใช้ Galera PXC แตกต่างจาก InnoDB Cluster ตรงที่ทุกโหนดสามารถรับการเขียน (หลายหลักที่แท้จริง) และการจำลองแบบจะซิงโครนัสที่ระดับการรับรองโดยใช้ wsrep API
# Install Percona Operator
helm repo add percona https://percona.github.io/percona-helm-charts/
helm repo update
helm install pxc-operator percona/pxc-operator \
--namespace pxc \
--create-namespace
# Percona XtraDB Cluster Custom Resource
apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBCluster
metadata:
name: production-pxc
namespace: pxc
spec:
crVersion: '1.14.0'
secretsName: pxc-secrets
pxc:
size: 3
image: percona/percona-xtradb-cluster:8.0.35
resources:
requests:
memory: 8Gi
cpu: "2"
limits:
memory: 16Gi
cpu: "4"
volumeSpec:
persistentVolumeClaim:
storageClassName: gp3-encrypted
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 200Gi
affinity:
antiAffinityTopologyKey: topology.kubernetes.io/zone
configuration: |
[mysqld]
innodb_buffer_pool_size=4G
innodb_flush_log_at_trx_commit=1
wsrep_provider_options="gcache.size=2G; gcs.fc_limit=256"
wsrep_slave_threads=8
wsrep_certify_nonPK=1
wsrep_trx_fragment_size=10M
max_connections=500
haproxy:
enabled: true
size: 3
image: percona/haproxy:2.8.5
resources:
requests:
memory: 1Gi
cpu: 500m
proxysql:
enabled: false
backup:
image: percona/percona-xtradb-cluster-operator:1.14.0-pxc8.0-backup-pxb8.0.35
storages:
s3-backup:
type: s3
verifyTLS: true
s3:
bucket: production-mysql-backups
region: us-east-1
credentialsSecret: aws-s3-credentials
schedule:
- name: daily-full
schedule: "0 3 * * *"
keep: 7
storageName: s3-backup
- name: hourly-incremental
schedule: "0 * * * *"
keep: 24
storageName: s3-backup
ตัวดำเนินการ Percona จัดการการสำรองข้อมูลอัตโนมัติไปยัง S3, การกู้คืน ณ เวลานั้น, การอัปเกรดแบบต่อเนื่อง และ ProxySQL หรือ HAProxy สำหรับการกำหนดเส้นทางการเชื่อมต่อ การจำลองแบบที่ใช้ Galera ใน PXC ให้การเขียนแบบหลายหลักแบบซิงโครนัสอย่างแท้จริง — ทุกธุรกรรมที่คอมมิตรับประกันว่าจะมีอยู่บนทุกโหนด
เส้นทางการเชื่อมต่อ: เราเตอร์ MySQL กับ ProxySQL
ทั้งเราเตอร์ MySQL และ ProxySQL ทำหน้าที่เป็นพร็อกซีฐานข้อมูล แต่มีจุดแข็งที่แตกต่างกัน
MySQL เราเตอร์สร้างขึ้นโดยเฉพาะสำหรับคลัสเตอร์ InnoDB โดยจะอ่านข้อมูลเมตาของคลัสเตอร์ ติดตามการเปลี่ยนแปลงโทโพโลยี และกำหนดเส้นทางการเชื่อมต่อไปยังหลักหรือรองที่ถูกต้อง การกำหนดค่ามีเพียงเล็กน้อยและผสานรวมเข้ากับระบบนิเวศ MySQL ได้อย่างราบรื่น ข้อเสียคือการกำหนดเส้นทางระดับการสืบค้นที่จำกัด — มันทำงานที่ระดับการเชื่อมต่อ ไม่ใช่ระดับการสืบค้น
ProxySQLเป็นพร็อกซี MySQL อเนกประสงค์พร้อมฟีเจอร์ขั้นสูง: การแยกการอ่าน/เขียนระดับคิวรี การแคชคิวรี การเชื่อมต่อมัลติเพล็กซ์ การเขียนคิวรีใหม่ และกฎการกำหนดเส้นทางที่ซับซ้อน มีความโดดเด่นในสภาพแวดล้อมที่คุณต้องการการควบคุมวิธีการกระจายการสืบค้นโดยละเอียด
# ProxySQL configuration for read/write splitting
# proxysql.cnf
mysql_servers:
(
{ hostgroup_id=10, hostname="mysql-primary", port=3306, max_connections=200, weight=1000 },
{ hostgroup_id=20, hostname="mysql-secondary-1", port=3306, max_connections=200, weight=500 },
{ hostgroup_id=20, hostname="mysql-secondary-2", port=3306, max_connections=200, weight=500 }
)
mysql_query_rules:
(
{ rule_id=1, active=1, match_digest="^SELECT .* FOR UPDATE$", destination_hostgroup=10, apply=1 },
{ rule_id=2, active=1, match_digest="^SELECT", destination_hostgroup=20, apply=1 },
{ rule_id=3, active=1, match_digest=".*", destination_hostgroup=10, apply=1 }
)
mysql_replication_hostgroups:
(
{ writer_hostgroup=10, reader_hostgroup=20, comment="InnoDB Cluster" }
)
ในสภาพแวดล้อม Kubernetes นั้น ProxySQL สามารถทำงานเป็นคอนเทนเนอร์ไซด์คาร์ในพ็อดแอปพลิเคชันของคุณหรือเป็นการปรับใช้เฉพาะ การรันเป็นรถเทียมข้างรถจักรยานยนต์จะช่วยลดการกระโดดของเครือข่าย แต่เพิ่มการใช้ทรัพยากรพ็อด การปรับใช้เฉพาะนั้นง่ายต่อการจัดการในวงกว้าง
การเปรียบเทียบผู้ให้บริการคลาวด์:
ที่มีการจัดการและการจัดการด้วยตนเองAWS: RDS Multi-AZ กับ Aurora และจัดการด้วยตนเองบน EKS
Amazon RDS Multi-AZให้การเฟลโอเวอร์อัตโนมัติระหว่างอินสแตนซ์หลักและอินสแตนซ์สแตนด์บายในโซนความพร้อมใช้งานที่แตกต่างกัน โดยทั่วไปการเฟลโอเวอร์จะใช้เวลา 60–120 วินาที ใช้การจำลองแบบฟิสิคัลแบบซิงโครนัสเพื่อสแตนด์บาย คุณสามารถเพิ่มแบบจำลองการอ่านเพื่อปรับขนาดการอ่านได้ แต่จะใช้การจำลองแบบอะซิงโครนัส RDS จัดการการสำรองข้อมูล การแพตช์ และการตรวจสอบ แต่จะจำกัดการควบคุมการกำหนดค่า MySQL และตัวเลือกเวอร์ชันของคุณ
Amazon Aurora MySQLเป็นการเขียนซ้ำบนระบบคลาวด์ของกลไกจัดเก็บข้อมูล MySQL แยกการประมวลผลออกจากพื้นที่จัดเก็บข้อมูล โดยชั้นพื้นที่จัดเก็บข้อมูลเป็นระบบแบบกระจายและทนทานต่อข้อผิดพลาด ซึ่งจะจำลองข้อมูลหกวิธีใน AZ สามแห่ง Aurora มอบการเฟลโอเวอร์ภายใน 10 วินาที, แบบจำลองการอ่านสูงสุด 15 รายการพร้อมความล่าช้าในการจำลองน้อยที่สุด และขนาดพื้นที่จัดเก็บอัตโนมัติสูงสุด 128 TiB Aurora Serverless v2 เพิ่มการปรับขนาดการประมวลผลอัตโนมัติสำหรับปริมาณงานที่คาดเดาไม่ได้ การแลกเปลี่ยนคือต้นทุน (Aurora มีราคาแพงกว่า RDS 20–40%) และลดความเข้ากันได้กับคุณสมบัติ MySQL บางอย่าง
จัดการด้วยตนเองบน EKSช่วยให้คุณควบคุมเวอร์ชัน MySQL การกำหนดค่า และโทโพโลยีการจำลองได้อย่างสมบูรณ์ ใช้สิ่งนี้เมื่อคุณต้องการคุณสมบัติเฉพาะของ MySQL ที่ไม่มีในบริการที่ได้รับการจัดการ เมื่อคุณต้องการความสามารถในการพกพาแบบมัลติคลาวด์ หรือเมื่อการเพิ่มประสิทธิภาพต้นทุนในระดับที่เหมาะสมทำให้ค่าใช้จ่ายในการดำเนินงานเหมาะสม
# EKS StorageClass for MySQL with gp3 volumes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3-encrypted
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "6000"
throughput: "250"
encrypted: "true"
fsType: ext4
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
Azure: เซิร์ฟเวอร์ที่ยืดหยุ่นและการจัดการด้วยตนเองบน AKS
ฐานข้อมูล Azure สำหรับเซิร์ฟเวอร์ยืดหยุ่น MySQLนำเสนอ HA แบบสำรองโซนพร้อมระบบเฟลโอเวอร์อัตโนมัติ การจำลองการอ่านในภูมิภาคเดียวกัน และพื้นที่จัดเก็บ TiB สูงสุด 16 รายการ รองรับช่วงเวลาการบำรุงรักษาที่กำหนดค่าได้ ความสามารถในการหยุด/เริ่มอินสแตนซ์ (มีประโยชน์สำหรับการประหยัดต้นทุนการพัฒนา/ทดสอบ) และการผสานรวมกับ Azure Private Link สำหรับการแยกเครือข่าย ระดับ Business Critical มอบประสิทธิภาพที่ดีที่สุดด้วยที่เก็บข้อมูล SSD ในเครื่อง
จัดการด้วยตนเองบน AKSใช้ดิสก์ที่ได้รับการจัดการ Azure (แนะนำ Premium SSD v2 สำหรับเวิร์กโหลดฐานข้อมูล) กับ MySQL Operator หรือ Percona Operator AKS ให้การสนับสนุนโซนความพร้อมใช้งานและ Azure CNI สำหรับการผสานรวม VNET ระดับพ็อด
# AKS StorageClass for MySQL
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: premium-ssd-zrs
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_ZRS
cachingMode: None
DiskIOPSReadWrite: "5000"
DiskMBpsReadWrite: "200"
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
Google Cloud: Cloud SQL เทียบกับการจัดการด้วยตนเองบน GKE
Google Cloud SQL สำหรับ MySQLนำเสนออินสแตนซ์ระดับภูมิภาคที่มีการเฟลโอเวอร์อัตโนมัติข้ามโซน แบบจำลองการอ่าน (รวมถึงข้ามภูมิภาค) และการสำรองข้อมูลอัตโนมัติพร้อมการกู้คืน ณ เวลาใดเวลาหนึ่ง Cloud SQL มอบความสะดวกสบายในการจัดการระดับสูงสุดด้วยการผสานรวมเข้ากับ IAM, VPC ของ Google และระบบนิเวศการตรวจสอบ ระดับ Enterprise Plus เพิ่มการบำรุงรักษาการหยุดทำงานเกือบเป็นศูนย์และแคชข้อมูลเพื่อประสิทธิภาพการอ่านที่ดีขึ้น
จัดการด้วยตนเองบน GKEใช้ Persistent Disk SSD หรือ Hyperdisk สำหรับการจัดเก็บข้อมูล GKE Autopilot ช่วยให้การจัดการโหนดง่ายขึ้นและสามารถเรียกใช้ MySQL Operator โดยมีค่าใช้จ่ายในการดำเนินงานน้อยที่สุด
# GKE StorageClass for MySQL
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ssd-regional
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
replication-type: regional-pd
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
โลหะเปลือย: k3s + Rancher + Longhorn
ไม่ใช่ทุกเวิร์คโหลดที่อยู่ในคลาวด์สาธารณะ สำหรับอธิปไตยของข้อมูล การปฏิบัติตามข้อกำหนด การเพิ่มประสิทธิภาพต้นทุน หรือข้อกำหนดด้านเวลาแฝง คลัสเตอร์ Bare Metal Kubernetes ที่ใช้งาน k3s พร้อมการจัดการ Rancher และพื้นที่จัดเก็บข้อมูล Longhorn มอบแพลตฟอร์มระดับการผลิตสำหรับ MySQL HA
k3s การติดตั้งและการกำหนดค่า
k3s เป็นการกระจาย Kubernetes น้ำหนักเบาและได้รับการรับรอง เหมาะสำหรับขอบและโลหะเปลือย โดยจะรวมส่วนประกอบของระนาบควบคุมทั้งหมดไว้ในไบนารี่เดียว และใช้ SQLite หรือ etcd แบบฝังสำหรับการจัดเก็บสถานะ
# Install k3s server (first control-plane node)
curl -sfL https://get.k3s.io | sh -s - server \
--cluster-init \
--tls-san 10.10.0.10 \
--disable traefik \
--disable servicelb \
--write-kubeconfig-mode 644
# Join additional server nodes
curl -sfL https://get.k3s.io | K3S_TOKEN=$(cat /var/lib/rancher/k3s/server/node-token) sh -s - server \
--server https://10.10.0.10:6443 \
--tls-san 10.10.0.10
# Join worker nodes
curl -sfL https://get.k3s.io | K3S_URL=https://10.10.0.10:6443 \
K3S_TOKEN=$(cat /var/lib/rancher/k3s/server/node-token) sh -s -
ที่เก็บข้อมูล Longhorn สำหรับ MySQL
Longhorn เป็นระบบจัดเก็บข้อมูลบล็อกแบบกระจายบนคลาวด์ที่สร้างขึ้นสำหรับ Kubernetes โดยจำลองข้อมูลข้ามโหนด จัดเตรียมสแนปช็อตและการสำรองข้อมูล และผสานรวมเข้ากับไดรเวอร์ Kubernetes CSI สำหรับ MySQL นั้น Longhorn มอบเลเยอร์พื้นที่จัดเก็บข้อมูลจำลองแบบถาวรที่ผู้ให้บริการระบบคลาวด์จัดการกับข้อเสนอดิสก์ที่ได้รับการจัดการ
# Install Longhorn
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.defaultReplicaCount=3 \
--set defaultSettings.storageMinimalAvailablePercentage=15 \
--set defaultSettings.guaranteedInstanceManagerCPU=12
# StorageClass for MySQL on Longhorn
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-mysql
provisioner: driver.longhorn.io
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
dataLocality: best-effort
diskSelector: ssd
fsType: ext4
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true
MetalLB สำหรับโหลดบาลานซ์
บนโลหะเปลือย จะไม่มีโหลดบาลานเซอร์บนคลาวด์ MetalLB เติมเต็มช่องว่างนี้โดยการกำหนดที่อยู่ IP ภายนอกให้กับบริการ Kubernetes ประเภท LoadBalancer โดยใช้โหมด Layer 2 (ARP) หรือ BGP
# MetalLB IP Address Pool and L2 Advertisement
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: mysql-pool
namespace: metallb-system
spec:
addresses:
- 10.10.0.100-10.10.0.110
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: mysql-l2
namespace: metallb-system
spec:
ipAddressPools:
- mysql-pool
กลยุทธ์การสำรองและกู้คืนคลัสเตอร์ความพร้อมใช้งานสูงป้องกันความล้มเหลวของโหนด การสำรองข้อมูลช่วยป้องกันข้อมูลเสียหาย การลบโดยไม่ตั้งใจ จุดบกพร่องของแอปพลิเคชัน และสถานการณ์การกู้คืนระบบที่คลัสเตอร์ทั้งหมดสูญหาย คุณต้องการทั้งสองอย่าง
การสำรองข้อมูลแบบลอจิคัลด้วย mysqldump
mysqldumpสร้างการสำรองข้อมูลในรูปแบบ SQL ที่สามารถพกพาได้และมนุษย์สามารถอ่านได้ สำหรับฐานข้อมูลที่มีขนาดต่ำกว่า 50 GB เป็นตัวเลือกที่ง่ายที่สุด สำหรับชุดข้อมูลขนาดใหญ่ เวลาล็อกและส่งออกทำให้ไม่สามารถใช้งานได้จริงในช่วงเวลาทำการ
# Full logical backup with consistent snapshot
mysqldump --all-databases \
--single-transaction \
--routines \
--triggers \
--events \
--set-gtid-purged=ON \
--result-file=/backups/full-$(date +%Y%m%d-%H%M%S).sql
# Compressed backup piped to S3
mysqldump --all-databases --single-transaction | \
gzip | aws s3 cp - s3://mysql-backups/full-$(date +%Y%m%d).sql.gz
การสำรองข้อมูลทางกายภาพด้วย Percona XtraBackup
Percona XtraBackup ทำการสำรองข้อมูลทางกายภาพของข้อมูล InnoDB แบบไม่ปิดกั้น โดยจะคัดลอกไฟล์ข้อมูล InnoDB ในขณะที่ติดตามบันทึกการทำซ้ำ จากนั้นใช้บันทึกการทำซ้ำในระหว่างขั้นตอนการเตรียมการเพื่อสร้างการสำรองข้อมูลที่สอดคล้องกัน มันเร็วกว่า mysqldump อย่างมากสำหรับชุดข้อมูลขนาดใหญ่ และรองรับการสำรองข้อมูลส่วนเพิ่ม
# Full physical backup
xtrabackup --backup \
--target-dir=/backups/full \
--user=backup_user \
--password=SecureBackupPass \
--parallel=4 \
--compress \
--compress-threads=4
# Incremental backup based on previous full
xtrabackup --backup \
--target-dir=/backups/incr-$(date +%H) \
--incremental-basedir=/backups/full \
--user=backup_user \
--password=SecureBackupPass
# Prepare (apply redo log) and restore
xtrabackup --prepare --target-dir=/backups/full
xtrabackup --prepare --target-dir=/backups/full \
--incremental-dir=/backups/incr-01
# Copy back to data directory
xtrabackup --copy-back --target-dir=/backups/full --datadir=/var/lib/mysql
chown -R mysql:mysql /var/lib/mysql
Binary Log (binlog) การกู้คืนช่วงเวลา
บันทึกไบนารีจะบันทึกทุกธุรกรรมที่มีการแก้ไขข้อมูล เมื่อรวมกับการสำรองข้อมูลเต็มรูปแบบ จะช่วยให้สามารถกู้คืนข้อมูลแบบ point-in-time (PITR) ได้ — กู้คืนในช่วงเวลาใดเวลาหนึ่ง ไม่ใช่แค่เวลาของการสำรองข้อมูลครั้งล่าสุด
# Enable binlog retention (my.cnf)
[mysqld]
log_bin=mysql-bin
binlog_expire_logs_seconds=604800 # 7 days
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
# Restore from backup then replay binlogs to a specific point
mysqlbinlog --start-datetime="2026-04-12 08:00:00" \
--stop-datetime="2026-04-12 09:30:00" \
mysql-bin.000042 mysql-bin.000043 | mysql -u root -p
# Or replay to a specific GTID position
mysqlbinlog --include-gtids="3c2d4f9e-d17e-ec59-9029-6aafa8accef8:1-5000" \
mysql-bin.000042 | mysql -u root -p
Kubernetes สำรอง CronJob
ใน Kubernetes การสำรองข้อมูลควรทำงานเป็น CronJobs แทนที่จะเป็นคำสั่งเฉพาะกิจ สิ่งนี้ทำให้มั่นใจได้ว่าการสำรองข้อมูลจะเป็นอัตโนมัติ มีการตรวจสอบ และสามารถแจ้งเตือนได้หากล้มเหลว
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-backup
namespace: production
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 7
failedJobsHistoryLimit: 3
jobTemplate:
spec:
activeDeadlineSeconds: 7200
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: percona/percona-xtrabackup:8.0.35
command:
- /bin/sh
- -c
- |
BACKUP_DIR=/backups/$(date +%Y%m%d-%H%M%S)
mkdir -p $BACKUP_DIR
xtrabackup --backup \
--host=production-mysql.production.svc \
--user=backup_user \
--password=$BACKUP_PASSWORD \
--target-dir=$BACKUP_DIR \
--parallel=4 \
--compress
xtrabackup --prepare --target-dir=$BACKUP_DIR
# Upload to S3
aws s3 sync $BACKUP_DIR s3://mysql-backups/$(date +%Y%m%d)/
# Cleanup local
rm -rf $BACKUP_DIR
env:
- name: BACKUP_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-backup-credentials
key: password
volumeMounts:
- name: backup-scratch
mountPath: /backups
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "2"
memory: 4Gi
volumes:
- name: backup-scratch
emptyDir:
sizeLimit: 100Gi
การตรวจสอบด้วย Percona Monitoring and Management (PMM)
Percona Monitoring and Management (PMM) เป็นแพลตฟอร์มการตรวจสอบแบบโอเพ่นซอร์สที่สร้างขึ้นโดยเฉพาะเพื่อให้สามารถสังเกตฐานข้อมูลได้ แม้ว่า Prometheus และ Grafana จะมีการตรวจสอบ Kubernetes ทั่วไป แต่ PMM จะเพิ่มข้อมูลเชิงลึกเฉพาะของ MySQL ได้แก่ การวิเคราะห์คิวรี (QAN) ที่ระบุการสืบค้นที่ช้า แดชบอร์ดความล่าช้าในการจำลองข้อมูล อัตราการเข้าถึงพูลบัฟเฟอร์ InnoDB การโต้แย้งการล็อกตาราง และอื่นๆ อีกมากมาย
# Deploy PMM Server on Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: pmm-server
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: pmm-server
template:
metadata:
labels:
app: pmm-server
spec:
containers:
- name: pmm-server
image: percona/pmm-server:2
ports:
- containerPort: 443
env:
- name: DISABLE_TELEMETRY
value: "1"
volumeMounts:
- name: pmm-data
mountPath: /srv
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
cpu: "2"
memory: 8Gi
volumes:
- name: pmm-data
persistentVolumeClaim:
claimName: pmm-data-pvc
---
apiVersion: v1
kind: Service
metadata:
name: pmm-server
namespace: monitoring
spec:
type: ClusterIP
selector:
app: pmm-server
ports:
- port: 443
targetPort: 443
# Register MySQL instances with PMM Client (run on each MySQL pod or sidecar)
pmm-admin config --server-url=https://admin:password@pmm-server.monitoring:443 --server-insecure-tls
pmm-admin add mysql \
--username=pmm_monitor \
--password=MonitorPass123 \
--host=127.0.0.1 \
--port=3306 \
--query-source=perfschema \
--service-name=mysql-node-1
Query Analytics ของPMM มีคุณค่าอย่างยิ่งในการใช้งานจริง โดยจะบันทึกทุกการสืบค้นที่ดำเนินการบนเซิร์ฟเวอร์ (ผ่าน Performance Schema หรือบันทึกการสืบค้นที่ช้า) รวมเข้าด้วยกันด้วยลายนิ้วมือ และแสดงตัวชี้วัด เช่น เวลาแฝงเฉลี่ย แถวที่ตรวจสอบเทียบกับแถวที่ส่ง และเวลาล็อค นี่คือวิธีระบุข้อความค้นหาที่ทำให้ประสิทธิภาพของแอปพลิเคชันของคุณลดลง
การปรับแต่งการกำหนดค่าการผลิต
การกำหนดค่า MySQL เริ่มต้นได้รับการปรับแต่งสำหรับเวิร์กโหลดขนาดเล็กและมีวัตถุประสงค์ทั่วไป สภาพแวดล้อมการผลิตที่มีเซิร์ฟเวอร์ฐานข้อมูลเฉพาะจำเป็นต้องมีการตั้งค่าที่แตกต่างกันอย่างมาก ต่อไปนี้เป็นพารามิเตอร์ที่สำคัญและวิธีกำหนดขนาด
บัฟเฟอร์พูล InnoDB
พูลบัฟเฟอร์ InnoDB เป็นที่ที่ MySQL แคชตารางและข้อมูลดัชนีในหน่วยความจำ เป็นพารามิเตอร์การกำหนดค่าเดียวที่มีประสิทธิภาพมากที่สุด สำหรับเซิร์ฟเวอร์ MySQL เฉพาะ ให้ตั้งค่าเป็น 70–80% ของ RAM ที่มีอยู่
[mysqld]
# Memory: 16Gi container limit -> allocate ~12Gi to buffer pool
innodb_buffer_pool_size = 12G
innodb_buffer_pool_instances = 8 # 1 per GB (up to 64)
innodb_buffer_pool_chunk_size = 1536M # pool_size / instances
ทำซ้ำการกำหนดค่าบันทึก
บันทึกการทำซ้ำจะดูดซับการเขียนก่อนที่จะถูกฟลัชไปยังไฟล์ข้อมูล บันทึกการทำซ้ำที่ใหญ่ขึ้นจะช่วยลดความถี่ของการฟลัชจุดตรวจสอบและปรับปรุงปริมาณงานการเขียน MySQL 8.0.30+ ใช้innodb_redo_log_capacityแทนinnodb_log_file_sizeรุ่นเก่า
[mysqld]
# MySQL 8.0.30+
innodb_redo_log_capacity = 4G
# MySQL 8.0.29 and earlier
# innodb_log_file_size = 2G
# innodb_log_files_in_group = 2
ความทนทานของเทียบกับการแลกเปลี่ยนประสิทธิภาพ
การผสมผสานระหว่างinnodb_flush_log_at_trx_commitและsync_binlogจะเป็นตัวกำหนดการรับประกันความทนทานของคุณ
- ความทนทานสูงสุด(แนะนำสำหรับการผลิต):
innodb_flush_log_at_trx_commit=1+sync_binlog=1. ทุกธุรกรรมจะถูกล้างไปยังบันทึกการทำซ้ำและบันทึกไบนารีบนดิสก์ก่อนที่จะได้รับการยอมรับ ข้อมูลสูญหายเป็นศูนย์เมื่อเกิดความผิดพลาด - สมดุล:
innodb_flush_log_at_trx_commit=2+sync_binlog=1. บันทึกการทำซ้ำจะถูกเขียนลงในแคชของระบบปฏิบัติการต่อการคอมมิต แต่จะฟลัชลงดิสก์เพียงครั้งเดียวต่อวินาที ธุรกรรมอาจสูญหายได้สูงสุด 1 วินาทีหากระบบปฏิบัติการขัดข้อง (ข้อขัดข้อง MySQL ยังคงปลอดภัย) - ประสิทธิภาพสูงสุด(ไม่แนะนำสำหรับการผลิต):
innodb_flush_log_at_trx_commit=0+sync_binlog=0การเขียนจะถูกจัดเป็นชุดและล้างเป็นระยะ เสี่ยงต่อการสูญเสียธุรกรรมสูงสุด 1 วินาทีหากเกิดข้อขัดข้อง
[mysqld]
# Production durability settings
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_doublewrite = ON
innodb_checksum_algorithm = crc32
การกำหนดค่าI/O
[mysqld]
# SSD-optimised I/O settings
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_flush_method = O_DIRECT
innodb_file_per_table = ON
innodb_open_files = 10000
การเชื่อมต่อและการจัดการเธรด
[mysqld]
max_connections = 500
max_connect_errors = 1000000
thread_cache_size = 64
table_open_cache = 4096
table_open_cache_instances = 16
back_log = 1500
# Thread pool (MySQL Enterprise or Percona)
thread_pool_size = 16
thread_pool_max_threads = 1000
ตารางชั่วคราวและบัฟเฟอร์การเรียงลำดับ
[mysqld]
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
read_rnd_buffer_size = 2M
เทมเพลตการกำหนดค่าการผลิตที่สมบูรณ์
[mysqld]
# Identity
server-id = 1
report_host = mysql-node-1
# GTID Replication
gtid_mode = ON
enforce_gtid_consistency = ON
binlog_format = ROW
log_bin = mysql-bin
binlog_expire_logs_seconds = 604800
log_slave_updates = ON
relay_log_recovery = ON
# InnoDB Engine
innodb_buffer_pool_size = 12G
innodb_buffer_pool_instances = 8
innodb_redo_log_capacity = 4G
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
innodb_doublewrite = ON
innodb_flush_method = O_DIRECT
innodb_io_capacity = 4000
innodb_io_capacity_max = 8000
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_file_per_table = ON
innodb_open_files = 10000
innodb_adaptive_hash_index = ON
innodb_change_buffering = all
# Connections
max_connections = 500
max_connect_errors = 1000000
thread_cache_size = 64
table_open_cache = 4096
table_open_cache_instances = 16
back_log = 1500
# Temp / Sort
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 4M
join_buffer_size = 4M
# Monitoring
performance_schema = ON
slow_query_log = ON
long_query_time = 1
log_queries_not_using_indexes = ON
log_throttle_queries_not_using_indexes = 60
# Security
local_infile = OFF
skip_name_resolve = ON
default_authentication_plugin = caching_sha2_password
# Group Replication (InnoDB Cluster)
plugin_load_add = 'group_replication.so'
plugin_load_add = 'mysql_clone.so'
loose-group_replication_start_on_boot = OFF
loose-group_replication_bootstrap_group = OFF
loose-group_replication_recovery_use_ssl = ON
loose-group_replication_ssl_mode = REQUIRED
การทดสอบข้อผิดพลาดและวิศวกรรมความโกลาหล
ระบบความพร้อมใช้งานสูงที่ไม่เคยได้รับการทดสอบภายใต้สภาวะความล้มเหลวนั้นไม่มีความพร้อมใช้งานสูงนัก — เป็นเพียงสมมติฐานเท่านั้น การทดสอบเฟลโอเวอร์ต้องเป็นส่วนหนึ่งของจังหวะการปฏิบัติงานปกติของคุณ ไม่ใช่สิ่งที่คุณค้นพบว่าได้ผล (หรือไม่ได้ผล) ในระหว่างเหตุการณ์จริง
การทดสอบความล้มเหลวที่ควบคุม
# Test 1: Graceful primary failover (InnoDB Cluster)
mysqlsh gradmin@mysql-node-1:3306
var cluster = dba.getCluster()
cluster.setPrimaryInstance('gradmin@mysql-node-2:3306')
# Verify: cluster.status() should show node-2 as PRIMARY
# Test 2: Simulate primary crash
# On the primary node:
kill -9 $(pidof mysqld)
# Monitor: watch the cluster elect a new primary
# Verify: applications reconnect via MySQL Router within seconds
# Test 3: Network partition simulation
# On the primary node, block Group Replication port:
iptables -A INPUT -p tcp --dport 33061 -j DROP
iptables -A OUTPUT -p tcp --dport 33061 -j DROP
# The isolated node should be expelled; cluster continues with remaining members
# Cleanup:
iptables -D INPUT -p tcp --dport 33061 -j DROP
iptables -D OUTPUT -p tcp --dport 33061 -j DROP
# Test 4: Kubernetes pod deletion
kubectl delete pod mysql-0 -n production --grace-period=0 --force
# The StatefulSet controller recreates the pod
# The operator rejoins it to the cluster
Chaos Engineering พร้อม Litmus หรือ Chaos Mesh
เครื่องมือวิศวกรรมความโกลาหลที่มีโครงสร้างจะส่งความล้มเหลวอย่างเป็นระบบและวัดรัศมีการระเบิด Chaos Mesh ซึ่งเป็นโปรเจ็กต์ CNCF ผสานรวมกับ Kubernetes โดยกำเนิด
# Chaos Mesh: Kill a MySQL pod randomly
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: mysql-pod-kill
namespace: production
spec:
action: pod-kill
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
scheduler:
cron: "0 */4 * * *"
---
# Chaos Mesh: Network delay between MySQL pods
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: mysql-network-delay
namespace: production
spec:
action: delay
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
delay:
latency: "200ms"
jitter: "50ms"
duration: "5m"
scheduler:
cron: "30 */6 * * *"
---
# Chaos Mesh: Disk I/O stress
apiVersion: chaos-mesh.org/v1alpha1
kind: IOChaos
metadata:
name: mysql-io-latency
namespace: production
spec:
action: latency
mode: one
selector:
namespaces:
- production
labelSelectors:
app.kubernetes.io/component: mysqld
volumePath: /var/lib/mysql
path: '*'
delay: '100ms'
percent: 50
duration: '5m'
สิ่งที่ต้องวัดในระหว่างการทดสอบ Failover
- Recovery Time Objective (RTO)— นานแค่ไหนตั้งแต่การตรวจจับความล้มเหลวไปจนถึงการกู้คืนบริการ โดยทั่วไปคลัสเตอร์ InnoDB จะใช้เวลา 5–30 วินาที คลัสเตอร์ Percona XtraDB สามารถทำงานได้เร็วขึ้นเนื่องจากไม่มีการเลือกตั้ง (โหนดทั้งหมดสามารถเขียนได้)
- Recovery Point Objective (RPO)— ข้อมูลจำนวนเท่าใดที่สูญหายระหว่างการเปลี่ยนระบบเมื่อเกิดข้อผิดพลาด ด้วยการจำลองแบบซิงโครนัส (การจำลองแบบกลุ่มในโหมดหลักเดียว PXC) RPO จะเป็นศูนย์สำหรับธุรกรรมที่คอมมิต ด้วยการจำลองแบบอะซิงโครนัส (ClusterSet ข้ามภูมิภาค) RPO จะเท่ากับความล่าช้าในการจำลอง
- อัตราข้อผิดพลาดของแอปพลิเคชัน— มีคำขอแอปพลิเคชันจำนวนเท่าใดที่ล้มเหลวในระหว่างหน้าต่างเฟลโอเวอร์ สิ่งนี้จะทดสอบไม่เพียงแค่การเฟลโอเวอร์ฐานข้อมูลเท่านั้น แต่ยังทดสอบลอจิกการลองเชื่อมต่อของแอปพลิเคชันของคุณและความเร็วการกำหนดเส้นทางใหม่ของเราเตอร์ MySQL
- เวลาระบายการเชื่อมต่อ— การเชื่อมต่อที่มีอยู่กับหลักเก่าใช้เวลานานเท่าใดในการระบายและเชื่อมต่อกับหลักใหม่อีกครั้ง?
Runbook: รายการตรวจสอบความล้มเหลวของโหนดหลัก
- ตรวจสอบว่าคลัสเตอร์ได้เลือกหลักใหม่:
cluster.status() - ยืนยันว่าเราเตอร์ MySQL กำลังกำหนดเส้นทางไปยังหลักใหม่: ตรวจสอบบันทึกของเราเตอร์และจำนวนการเชื่อมต่อ
- ตรวจสอบความล่าช้าในการจำลองข้อมูลในส่วนรองที่เหลือ:
SELECT * FROM performance_schema.replication_group_member_stats - หากสามารถกู้คืนโหนดที่ล้มเหลวได้ ให้เข้าร่วมใหม่:
cluster.rejoinInstance('gradmin@failed-node:3306') - หากไม่สามารถกู้คืนโหนดที่ล้มเหลวได้ ให้ลบออกและเพิ่มโหนดใหม่:
cluster.removeInstance('gradmin@failed-node:3306', {force: true}) - ตรวจสอบความสมบูรณ์ของคลัสเตอร์: สมาชิกทั้งหมดออนไลน์ ไม่มีข้อผิดพลาดในการจำลอง กำหนดการสำรองข้อมูลครบถ้วน
- อัปเดตแผนความจุของคุณ: การรันด้วย 2 โหนดหมายความว่าคุณมีความทนทานต่อข้อผิดพลาดเป็นศูนย์จนกว่าโหนดที่สามจะได้รับการกู้คืน
เสริมความปลอดภัย
การใช้งานProduction MySQL ต้องจัดการกับข้อกังวลด้านความปลอดภัยหลายประการ นอกเหนือจากการตรวจสอบสิทธิ์ขั้นพื้นฐาน
การเข้ารหัสในระหว่างทางและที่เหลือ
[mysqld]
# TLS for client connections
ssl_ca = /etc/mysql/certs/ca.pem
ssl_cert = /etc/mysql/certs/server-cert.pem
ssl_key = /etc/mysql/certs/server-key.pem
require_secure_transport = ON
tls_version = TLSv1.3
# Encryption at rest (InnoDB tablespace encryption)
early-plugin-load = keyring_file.so
keyring_file_data = /var/lib/mysql-keyring/keyring
innodb_undo_log_encrypt = ON
innodb_redo_log_encrypt = ON
default_table_encryption = ON
ความลับKubernetes และความลับที่ปิดผนึก
# Never store database credentials in plain YAML
# Use Sealed Secrets or an external secret manager
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysql-root-credentials
namespace: production
spec:
encryptedData:
rootUser: AgBy3i4OJSWK+PiTy...
rootPassword: AgCtr7pJ2XQWK+Pi...
template:
metadata:
name: mysql-root-credentials
namespace: production
type: Opaque
การบันทึกการตรวจสอบ
[mysqld]
# MySQL Enterprise Audit (or Percona Audit Log plugin)
plugin-load-add = audit_log.so
audit_log_format = JSON
audit_log_policy = LOGINS
audit_log_rotate_on_size = 100M
audit_log_rotations = 10
เมทริกซ์การตัดสินใจ: การเลือกสถาปัตยกรรม MySQL HA ของคุณ
สถาปัตยกรรมที่เหมาะสมขึ้นอยู่กับความต้องการเฉพาะของคุณ นี่คือกรอบการตัดสินใจ
- คลาวด์เดี่ยว, การตั้งค่าที่ได้รับการจัดการ,ที่เข้ากันได้กับ MySQL — ใช้ Aurora (AWS), เซิร์ฟเวอร์ธุรกิจเซิร์ฟเวอร์ที่ยืดหยุ่นที่สำคัญ (Azure) หรือ Cloud SQL Enterprise Plus (GCP) สิ่งเหล่านี้ให้ค่าใช้จ่ายในการดำเนินงานต่ำที่สุด
- คลาวด์เดี่ยว จัดการด้วยตนเอง ต้องมีการควบคุม MySQL เต็มรูปแบบ— ใช้ MySQL Operator หรือ Percona Operator บน EKS/AKS/GKE พร้อมคลาสพื้นที่จัดเก็บข้อมูลบนคลาวด์
- มัลติคลาวด์หรือไฮบริดคลาวด์— ใช้ Percona Operator กับ PXC หรือ MySQL Operator กับ InnoDB Cluster เลเยอร์นามธรรม Kubernetes ทำให้การปรับใช้ MySQL ของคุณพกพาได้บนคลาวด์
- โลหะเปลือยหรือขอบ— ใช้ k3s กับ Rancher, ที่เก็บข้อมูล Longhorn, MetalLB และตัวดำเนินการ MySQL หรือตัวดำเนินการ Percona
- ปริมาณงานการเขียนสูงสุด ต้องใช้หลายหลัก— ใช้ Percona XtraDB Cluster (Galera) กับ Percona Operator โหนดทั้งหมดยอมรับการเขียนด้วยการรับรองแบบซิงโครนัส
- การกระจายทั่วโลกพร้อมการกู้คืนความเสียหาย— ใช้ InnoDB ClusterSet พร้อมการจำลองแบบอะซิงโครนัสระหว่างภูมิภาค ยอมรับการแลกเปลี่ยน RPO ของการจำลองแบบอะซิงโครนัสเพื่อประโยชน์ด้านเวลาแฝงของการเขียนในเครื่อง
สำหรับการผลิต MySQL HA
ก่อนที่จะประกาศว่าการปรับใช้งาน MySQL HA ของคุณพร้อมแล้ว ให้ตรวจสอบทุกรายการในรายการตรวจสอบนี้
- ความสมบูรณ์ของคลัสเตอร์— สมาชิกทั้งหมดรายงานสถานะออนไลน์ การจำลองแบบกลุ่มไม่แสดงข้อผิดพลาด
- การสำรองข้อมูลอัตโนมัติ— CronJob หรือการสำรองข้อมูลที่จัดการโดยผู้ให้บริการที่ทำงานตามกำหนดเวลา การสำรองข้อมูลได้รับการตรวจสอบโดยการทดสอบการคืนค่าเป็นระยะ
- การตรวจสอบ— PMM หรือ Prometheus/Grafana รวบรวมตัวชี้วัด MySQL การแจ้งเตือนที่กำหนดค่าสำหรับความล่าช้าในการจำลอง ความอิ่มตัวของการเชื่อมต่อ อัตราส่วนการเข้าถึงบัฟเฟอร์พูลต่ำกว่า 99% และพื้นที่ดิสก์
- ทดสอบเมื่อเกิดข้อผิดพลาด— ทดสอบเมื่อเกิดข้อผิดพลาดหลักภายใน 30 วันที่ผ่านมา RTO และ RPO วัดผลและภายในเป้าหมาย SLA
- เส้นทางการเชื่อมต่อ— เราเตอร์ MySQL หรือ ProxySQL ได้รับการตรวจสอบและปรับสมดุลโหลดแล้ว สตริงการเชื่อมต่อแอปพลิเคชันชี้ไปที่เราเตอร์ ไม่ใช่อินสแตนซ์ MySQL แต่ละรายการ
- ความปลอดภัย— TLS จำเป็นสำหรับการเชื่อมต่อทั้งหมด เปิดใช้งานการเข้ารหัสเมื่อไม่ได้ใช้งาน ข้อมูลรับรองที่จัดเก็บไว้ในผู้จัดการลับ การบันทึกการตรวจสอบใช้งานอยู่ ผู้ใช้ฐานข้อมูลที่มีสิทธิ์น้อยที่สุดสำหรับแต่ละแอปพลิเคชัน
- ขีดจำกัดทรัพยากร— คำขอทรัพยากร Kubernetes และขีดจำกัดที่ตั้งไว้อย่างเหมาะสม มี PodDisruptionBudgets อยู่แล้ว การต่อต้านความสัมพันธ์ของพ็อดจะกระจายพ็อด MySQL ข้ามโซน
- แผนความจุ— การใช้งานพื้นที่จัดเก็บข้อมูลได้รับการตรวจสอบพร้อมการแจ้งเตือนที่ 70% และ 85% ทดสอบการขยายปริมาตรแล้ว มีเอกสารขั้นตอนการปรับขนาดแนวตั้งและแนวนอน
- Runbooks— ขั้นตอนที่จัดทำเป็นเอกสารสำหรับการเฟลโอเวอร์หลัก การเปลี่ยนโหนด การกู้คืนข้อมูลสำรอง การอัปเกรดเวอร์ชัน และโหมดอ่านอย่างเดียวฉุกเฉิน
- การทดสอบความโกลาหล— การทดสอบความโกลาหลปกติที่กำหนดเพื่อตรวจสอบความถูกต้องของสมมติฐานด้านความยืดหยุ่น
สรุป
ความพร้อมใช้งานสูงMySQL ในการผลิตไม่ใช่ทางเลือกเทคโนโลยีเดียว แต่เป็นระบบการตัดสินใจที่ประสานกันซึ่งครอบคลุมเลเยอร์การจำลอง แพลตฟอร์มการจัดการ ระบบย่อยการจัดเก็บข้อมูล สแต็กการตรวจสอบ และกระบวนการปฏิบัติงานรอบตัว คลัสเตอร์ InnoDB พร้อมการจำลองแบบกลุ่มมอบ HA พื้นฐานขั้นพื้นฐาน ตัวดำเนินการ Kubernetes จาก Oracle และ Percona จัดการวงจรการใช้งานโดยอัตโนมัติ ซึ่งอาจต้องใช้เวลาทางวิศวกรรมจำนวนมาก การควบคุมการแลกเปลี่ยนบริการที่มีการจัดการบนคลาวด์เพื่อความสะดวก การใช้งาน Bare Metal กับ k3s, Rancher และ Longhorn พิสูจน์ได้ว่าคุณไม่จำเป็นต้องมีผู้ให้บริการระบบคลาวด์เพื่อรัน MySQL HA ระดับการผลิต
ข้อมูลเชิงลึกที่สำคัญที่สุดคือความพร้อมใช้งานสูงเป็นคุณสมบัติของทั้งระบบ ไม่ใช่แค่ฐานข้อมูลเท่านั้น รวมถึงวิธีที่แอปพลิเคชันของคุณจัดการกับความล้มเหลวในการเชื่อมต่อและการลองใหม่ วิธีที่ชั้นพร็อกซีของคุณตรวจจับและกำหนดเส้นทางรอบโหนดที่ล้มเหลว วิธีที่การแจ้งเตือนการตรวจสอบของคุณก่อนที่ผู้ใช้จะสังเกตเห็น วิธีที่กลยุทธ์การสำรองข้อมูลของคุณช่วยให้สามารถกู้คืนจากสถานการณ์ที่ HA เพียงอย่างเดียวไม่สามารถจัดการได้ และวิธีที่ทีมของคุณปฏิบัติขั้นตอนการเฟลโอเวอร์เพื่อให้พวกเขาดำเนินการอย่างหมดจดภายใต้ความเครียดของเหตุการณ์จริง
สร้างมันขึ้นมาอย่างตั้งใจ ทดสอบเป็นประจำ และปฏิบัติต่อ runbooks ของคุณเสมือนเป็นเอกสารที่มีชีวิตซึ่งพัฒนาไปพร้อมกับทุกเหตุการณ์และทุกการทดลองที่วุ่นวาย นั่นคือวิธีที่ MySQL กลายเป็นแพลตฟอร์มข้อมูลที่เชื่อถือได้และมีความพร้อมใช้งานสูงในการผลิต