商店现已上线

我们打造用于网站、AI 智能体和 LLM 训练的 Workstation AI 机器——在线配置并购买。

获取同行价格
AI 产品
AI 实验室OpenAI 智能体Claude 代理Grok BotWorkstation AI 原生 CRM营销所有产品
AI 解决方案
应用型 AIAI 智能体生成式 AIAI 自动化AI 技能提升中小企业 AI 套餐企业 AI 实验室AI 工作站NVIDIA 硬件与软件NVIDIA 加速计算私有 AIGPU 集群边缘 AI行业 AI
AI 服务
平台现代化数字工程数据基础与 AI自主运营AI 咨询DevOps 自动化网络安全软件开发智能体构建MLOps 搭建GPU 租赁
关于我们
公司我们的故事合作伙伴客户案例
AI 数据中心
AI 洞察Jev 系列基准测试实验室模型选择
技术说明
文档
Linux 操作系统UbuntuRed Hat Enterprise LinuxSUSE LinuxAlpine LinuxDebian, Rocky & AlmaLinux
AI 云平台AWS & Amazon BedrockGoogle Cloud & Vertex AIMicrosoft Azure & AI FoundryGPU 云与算力市场
私有 AI 数据中心面向律师事务所面向会计师事务所本地部署平台全面安全的云
工具Ring PromoterJobshout
新闻
博客
联系我们登录

面向现代企业的 AI 工作站、AI 多智能体软件、GPU 基础设施和智能代理解决方案。

联系我们

AI 解决方案

应用型 AIAI 智能体生成式 AIAI 自动化AI 技能提升中小企业 AI 套餐企业 AI 实验室行业 AI

产品

所有产品Workstation AI native CRM 与 ERP营销OpenAI 智能体Ring PromoterJobshout

公司

关于我们公司AI 数据中心为什么选择Workstation合作伙伴客户案例定价联系TenthMatrix

资源

AI 洞察技术说明文档Linux 操作系统AI 云平台私有 AI 数据中心博客搜索网站地图
英国办公室
77-79 Marlowes, Hemel Hempstead HP1 1LF路线指引 — 从 M25 外环伦敦 20 号出口驶出公司编号: 11641870周一至周五:上午 9:00 - 下午 6:00 GMT
+44 7515 356 146
比利时办公室
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683周一至周五:上午 9:00 - 下午 6:00 CET
+32 492 45 67 46
印度办公室
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI。保留所有权利。

隐私数据删除Cookie服务条款网站地图

NVIDIA, the NVIDIA logo, RTX, RTX PRO, Blackwell, CUDA, NVLink, MGX, Omniverse, Spectrum-X, Quantum, BlueField, DGX and HGX are trademarks and/or registered trademarks of NVIDIA Corporation in the US and other countries. AMD, the AMD Arrow logo, EPYC, Instinct, Ryzen and Threadripper are trademarks of Advanced Micro Devices, Inc. Dell and PowerEdge are trademarks of Dell Inc. or its subsidiaries. Intel and Xeon are trademarks of Intel Corporation or its subsidiaries. AMAX, AceleMax and LiquidMax are trademarks of AMAX Engineering Corporation. All other product names, logos and brands are the property of their respective owners. We use them only to identify the products we describe, supply or support; their use does not mean their owners endorse us.

Loading blog...

首页 / 博客
DatabaseKubernetesDevOpsBackend

生产中的 MySQL 高可用性:InnoDB 集群、组复制和 Kubernetes Operator

有关 InnoDB 集群、组复制、Kubernetes 的 MySQL Operator、Percona XtraDB 集群、多云策略以及使用 Longhorn 存储的裸机 k3s/Rancher 部署的生产工程师指南

Balinder Walia2026年4月12日15 min read
Mysql ha architecture

在生产中运行 MySQL 对于大多数工程团队来说都是熟悉的领域。以真正的高可用性运行它——节点故障、网络分区或整个可用区变暗不会导致停机或数据丢失——需要精心设计的架构。本指南详细介绍了该架构的每一层:从 MySQL 本身内部的复制原语,到自动化生命周期管理的 Kubernetes 运算符,到每个主要云提供商的托管和自我管理选项,再到 Rancher 管理的裸机 k3s 集群。

在本文结束时,您将拥有在生产中选择和操作 MySQL HA 的完整心智模型,以及可适应您自己的环境的具体配置示例。

MySQL InnoDB 集群架构

InnoDB Cluster 是 Oracle 针对 MySQL 的集成高可用性解决方案。它结合了三个组件:用于数据同步的 MySQL 组复制、用于集群管理的 MySQL Shell 以及用于透明连接路由和自动故障转移的 MySQL 路由器。它们一起形成一个自我修复集群,无需人工干预即可容忍节点故障。

MySQL InnoDB 集群 — 高可用性架构应用服务器MySQL 路由器自动故障转移和读/写分离R/WR/OR/O主(读/写)mysql-node-1端口 3306 / 33061辅助 (R/O)mysql-node-2端口 3306 / 33061辅助 (R/O)mysql-node-3端口 3306 / 33061组复制(基于 Paxos 的共识)InnoDB 集群主(读/写)辅助 (R/O)MySQL 路由器组复制

架构简洁而优雅。应用程序连接到 MySQL 路由器,该路由器通过查询 InnoDB 集群元数据架构来保持对集群拓扑的了解。当主服务器发生故障时,组复制会从剩余的辅助服务器中选择一个新的主服务器,MySQL 路由器会自动将写入流量重定向到新的主服务器(通常在几秒钟内)。读取流量可以分布在所有辅助节点上,以实现水平读取扩展。

组复制基础知识

MySQL 组复制是 InnoDB Cluster 的基础。它使用基于 Paxos 的共识协议来确保在主节点上提交的每个事务在被确认之前都被复制到大多数节点。 这提供了虚拟同步复制— 保证提交的数据在提交时至少存在于大多数集群成员上。

组复制以两种模式运行:

  • 单主模式— 一个节点接受写入(主节点);所有其他都是只读辅助对象。这是推荐的默认模式。它完全避免了写冲突,因为只有一个节点可以生成事务。
  • 多主模式— 所有节点同时接受写入。这为跨不同表或键空间进行干净分区的工作负载提供了更高的写入吞吐量,但是当并发事务修改相同的行时,它会引入认证冲突的可能性。冲突的事务会在一个节点上回滚。仅当您的应用程序设计为处理认证失败和重试逻辑时,才使用多主。

使用 MySQL Shell 设置 InnoDB 集群

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 克隆插件执行从主成员到加入成员的完整数据复制,这比从大型数据集的二进制日志进行增量恢复要快得多。

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 部署us-east-1 (AWS)主集群主(读/写)辅助辅助MySQL 路由器组复制EBS gp3 / io2 存储eu-west-1 (Azure)副本集群主(备用)辅助辅助MySQL 路由器组复制Azure 托管磁盘ap-southeast-1 (GCP)副本集群主(备用)辅助辅助MySQL 路由器组复制持久磁盘 SSD异步异步全局流量管理器/基于 DNS 的路由Route53 / Azure 流量管理器 / 云 DNS主集群副本集群异步复制

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')
Kubernetes 上的

MySQL — 操作模式

在 Kubernetes 上运行 MySQL 需要解决一些不适用于无状态工作负载的挑战:稳定的网络身份、持久存储、有序启动和关闭以及集群感知的运行状况检查。 Kubernetes 操作员将特定于域的操作知识编码到控制器中,该控制器监视自定义资源并将 MySQL 的实际状态与 YAML 中声明的所需状态进行协调。

Kubernetes 上的MySQL — 操作架构Kubernetes 集群自定义资源InnoDBCluster CR副本:3 个,路由器:2 个手表MySQL 操作员控制器/协调器管理生命周期和维护故障转移创建配置映射服务ClusterIP / 无头StatefulSet:mysql有序 Pod 管理,稳定身份mysql-0(主要)mysqld + sidecarR/W — 端口 3306mysql-1(辅助)mysqld + sidecarR/O — 端口 3306mysql-2(辅助)mysqld + sidecarR/O — 端口 3306PVC:数据-mysql-0PVC:数据-mysql-1PVC:数据-mysql-2存储类别:gp3 / premium-ssd / longhorn配置器:ebs.csi / disk.csi / longhorn操作员StatefulSet

MySQL 用于 Kubernetes 的操作器 (Oracle)

适用于 Kubernetes 的 Oracle MySQL Operator 在 Kubernetes 上本地部署和管理 InnoDB Cluster 实例。它为 MySQL 服务器 Pod 创建 StatefulSet、为 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

Pod 反关联性规则可确保 MySQL Pod 分布在可用区域中,从而提供区域级容错。mycnf模块允许您直接通过 CR 注入经过生产调整的 MySQL 配置。

适用于 MySQL (PXC) 的 Percona 操作器

Percona Operator for 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 Operator 处理到 S3 的自动备份、时间点恢复、滚动升级以及用于连接路由的 ProxySQL 或 HAProxy。 PXC 中基于 Galera 的复制提供真正的同步多主写入 - 每个提交的事务都保证存在于所有节点上。

连接路由: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 可以作为应用程序 Pod 中的边车容器运行,也可以作为专用部署运行。将其作为 sidecar 运行可以消除网络跃点,但会增加 pod 资源使用率;专用部署更易于大规模管理。

云提供商比较:托管与自管理

AWS:RDS 多可用区与 Aurora 与 EKS

上的自我管理

Amazon RDS 多可用区可在不同可用区的主实例和备用实例之间提供自动故障转移。故障转移通常需要 60-120 秒。它使用同步物理复制到备用数据库。可以添加只读副本以进行读取扩展,但它们使用异步复制。 RDS 处理备份、修补和监控,但限制您对 MySQL 配置和版本选择的控制。

Amazon Aurora MySQL是 MySQL 存储引擎的云原生重写。它将计算与存储分开——存储层是一个分布式容错系统,可以跨三个可用区以六种方式复制数据。 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、同区域只读副本以及高达 16 TiB 的存储。它支持可配置的维护窗口、停止/启动实例的能力(有助于节省开发/测试成本)以及与 Azure Private Link 集成以实现网络隔离。关键业务层通过本地 SSD 存储提供最佳性能。

在 AKS 上进行自我管理将 Azure 托管磁盘(建议用于数据库工作负载的高级 SSD v2)与 MySQL Operator 或 Percona Operator 结合使用。 AKS 提供可用性区域支持和用于容器级 VNET 集成的 Azure CNI。

# 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

上的自我管理

适用于 MySQL的 Google Cloud SQL 提供区域实例,具有跨区域自动故障转移、只读副本(包括跨区域)以及具有时间点恢复功能的自动备份。 Cloud SQL 通过集成到 Google 的 IAM、VPC 和监控生态系统,提供最高级别的管理便利性。 Enterprise Plus 层增加了近乎零停机的维护和数据缓存,以提高读取性能。

在 GKE 上进行自我管理使用持久磁盘 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

并非所有工作负载都属于公共云。为了满足数据主权、合规性、成本优化或延迟要求,运行带有 Rancher 管理和 Longhorn 存储的 k3s 的裸机 Kubernetes 集群为 MySQL HA 提供了生产级平台。

裸机 k3s/Rancher MySQL HA 架构Rancher 管理服务器集群配置、监控、RBACk3s 集群控制平面 (x3)etcd + API 服务器 + 调度器金属LBL2/BGP 负载均衡器MySQL 操作员Oracle 或 Percona工作节点 1mysql-0(主要)CPU:4 |内存:16GiMySQL 路由器盒Longhorn 容量:200Gi工作节点 2mysql-1(辅助)CPU:4 |内存:16GiMySQL 路由器盒Longhorn 容量:200Gi工作节点 3mysql-2(辅助)CPU:4 |内存:16GiMySQL 路由器盒Longhorn 容量:200GiLonghorn 分布式存储每卷 3 个副本 |快照|备份到 S3/NFSNVMe SSD — 节点 1NVMe SSD — 节点 2NVMe SSD — 节点 3

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 -

适用于 MySQL 的 Longhorn 存储

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 通过使用第 2 层 (ARP) 或 BGP 模式将外部 IP 地址分配给 LoadBalancer 类型的 Kubernetes 服务来填补这一空白。

# 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

二进制日志 (binlog) 时间点恢复

二进制日志记录每个数据修改事务。与完整备份相结合,它们可以实现时间点恢复 (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 监控和管理 (PMM) 进行监控

Percona 监控和管理 (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

PMM 的查询分析在生产中特别有价值。它捕获在服务器上执行的每个查询(通过性能架构或慢速查询日志),通过指纹聚合它们,并显示平均延迟、检查的行与发送的行和锁定时间等指标。这是您识别降低应用程序性能的查询的方法。

生产配置调整

默认 MySQL 配置针对小型通用工作负载进行了调整。具有专用数据库服务器的生产环境需要显着不同的设置。以下是关键参数以及如何调整它们的大小。

InnoDB 缓冲池

InnoDB 缓冲池是 MySQL 在内存中缓存表和索引数据的地方。它是最有影响力的配置参数。对于专用 MySQL 服务器,将其设置为可用 RAM 的 70–80%。

[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

采用 Litmus 或混沌网格的混沌工程

结构化混沌工程工具系统地注入故障并测量爆炸半径。 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'

在故障转移测试期间测量什么

  • 恢复时间目标 (RTO)— 从故障检测到服务恢复需要多长时间? InnoDB Cluster 通常可以达到 5-30 秒。 Percona XtraDB Cluster 可以更快,因为没有选举(所有节点都是可写的)。
  • 恢复点目标 (RPO)— 故障转移期间丢失了多少数据?使用同步复制(单主模式下的组复制,PXC),已提交事务的 RPO 为零。对于异步复制(ClusterSet 跨区域),RPO 等于复制滞后。
  • 应用程序错误率— 在故障转移窗口期间有多少应用程序请求失败?这不仅测试数据库故障转移,还测试应用程序的连接重试逻辑和 MySQL 路由器的重新路由速度。
  • 连接耗尽时间— 与旧主设备的现有连接需要多长时间才能耗尽并重新连接到新主设备?

运行手册:主节点故障检查表

  1. 验证集群已选择新的主集群:cluster.status()
  2. 确认 MySQL 路由器正在路由到新的主路由器:检查路由器日志和连接计数
  3. 监控剩余辅助节点上的复制延迟:SELECT * FROM performance_schema.replication_group_member_stats
  4. 如果故障节点可以恢复,则重新加入它:cluster.rejoinInstance('gradmin@failed-node:3306')
  5. 如果故障节点无法恢复,请将其删除并添加新节点:cluster.removeInstance('gradmin@failed-node:3306', {force: true})
  6. 验证集群健康状况:所有成员均在线,无复制错误,备份计划完好无损
  7. 更新您的容量计划:使用 2 个节点运行意味着您的容错能力为零,直到第三个节点恢复为止

安全强化

生产 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 控制— 在具有云原生存储类的 EKS/AKS/GKE 上使用 MySQL Operator 或 Percona Operator。
  • 多云或混合云— 将 Percona Operator 与 PXC 结合使用,或将 MySQL Operator 与 InnoDB Cluster 结合使用。 Kubernetes 抽象层使您的 MySQL 部署可跨云移植。
  • 裸机或边缘— 将 k3s 与 Rancher、Longhorn 存储、MetalLB 以及 MySQL Operator 或 Percona Operator 结合使用。
  • 最大写入吞吐量,需要多主— 将 Percona XtraDB 集群 (Galera) 与 Percona Operator 结合使用。所有节点都接受具有同步认证的写入。
  • 具有灾难恢复功能的全球分布— 使用 InnoDB ClusterSet 进行区域之间的异步复制。接受异步复制的 RPO 与本地写入的延迟优势之间的权衡。

生产 MySQL HA

操作清单

在声明您的 MySQL HA 部署已投入生产之前,请验证此清单上的每一项。

  1. 集群运行状况— 所有成员均报告联机状态。组复制未显示任何错误。
  2. 自动备份— 按计划运行 CronJob 或操作员管理的备份。通过定期恢复测试验证备份。
  3. 监控— PMM 或 Prometheus/Grafana 收集 MySQL 指标。针对复制滞后、连接饱和、缓冲池命中率低于 99% 以及磁盘空间配置的警报。
  4. 故障转移测试— 在过去 30 天内测试了主要故障转移。 RTO 和 RPO 已测量且符合 SLA 目标。
  5. 连接路由— MySQL 路由器或 ProxySQL 运行状况检查和负载平衡。 应用程序连接字符串指向路由器,而不是单个 MySQL 实例。
  6. 安全性— 所有连接都需要 TLS。静态加密已启用。凭证存储在秘密管理器中。审核日志记录处于活动状态。每个应用程序的最低权限数据库用户。
  7. 资源限制— Kubernetes 资源请求和限制设置适当。 PodDisruptionBudgets 到位。 Pod 反关联性将 MySQL Pod 跨区域传播。
  8. 容量计划— 监控存储利用率,并在 70% 和 85% 时发出警报。已测试体积膨胀。记录垂直和水平缩放程序。
  9. 运行手册— 主故障转移、节点更换、备份恢复、版本升级和紧急只读模式的记录程序。
  10. 混沌测试— 计划定期进行混沌实验,以验证弹性假设。

结论

MySQL 在生产中的高可用性不是单一的技术选择 - 它是一个跨复制层、编排平台、存储子系统、监控堆栈及其周围操作流程的连锁决策系统。具有组复制功能的 InnoDB Cluster 提供了基础的 HA 原语。 Oracle 和 Percona 的 Kubernetes 操作员可自动执行生命周期管理,否则会消耗大量工程时间。为了方便起见,云管理服务贸易控制。 k3s、Rancher 和 Longhorn 的裸机部署证明您不需要云提供商来运行生产级 MySQL HA。

最关键的一点是,高可用性是整个系统的属性,而不仅仅是数据库的属性。它包括您的应用程序如何处理连接故障和重试,您的代理层如何检测故障节点并进行路由,您的监控如何在用户注意到之前发出警报,您的备份策略如何实现从仅 HA 无法处理的场景中恢复,以及您的团队如何实践故障转移程序,以便它们在真实事件的压力下干净地执行。

精心构建,定期测试,并将您的操作手册视为随每个事件和每个混乱实验而演变的动态文档。这就是 MySQL 作为生产中可靠、高度可用的数据平台的原因。