RadonDB MySQL 面试题
30 道题- 分类
- 数据库
- 子分类
- mysql
- 题目数
- 30 道
1 RadonDB MySQL 的整体架构是什么?核心组件有哪些?
答案:
RadonDB MySQL 是面向 Kubernetes 的云原生 MySQL 高可用数据库集群解决方案,由青云科技(QingCloud)开源的 RadonDB 社区维护。其架构基于 Kubernetes StatefulSet 部署,核心组件包括 MySQL(数据库引擎)、Xenon(高可用管理器)、Backup Sidecar(备份代理)以及 Operator(控制器)。
| 组件 | 职责 | 部署形态 |
|---|---|---|
| MySQL | 数据库引擎,承载数据存储与查询 | StatefulSet 容器,每副本一个 Pod |
| Xenon | 高可用管理器,负责 Raft 选举、主从切换、故障检测 | 与 MySQL 同 Pod 的 Sidecar 容器 |
| Backup Sidecar | 执行全量/增量备份与恢复,基于 XtraBackup | 与 MySQL 同 Pod 的 Sidecar 容器 |
| Operator | CRD 控制器,管理集群生命周期(创建/扩缩容/升级/删除) | 独立 Deployment,一个集群一个 Operator 实例 |
| Metrics Exporter | 采集 MySQL 运行时指标,暴露 Prometheus 格式 | Sidecar 容器,集成 Prometheus ServiceMonitor |
| Init Container | 初始化数据目录、搭主从复制、从备份恢复 | Pod 启动时执行,一次性任务 |
每个 MySQL Pod 包含三个核心容器(MySQL + Xenon + Metrics Sidecar),共享同一网络命名空间和存储卷。Xenon 通过本地 Unix Socket 管理 MySQL,Backup Sidecar 通过 Job/CronJob 机制触发备份任务。
graph TD
Operator["RadonDB Operator<br/>(CRD Watch / Reconcile Loop)"]
HeadlessSvc["Headless Service<br/>(mysql-radondb-headless)"]
subgraph StatefulSet["StatefulSet Replicas (3)"]
Pod0["Pod-0: MySQL / Xenon / Exp<br/>Leader"]
Pod1["Pod-1: MySQL / Xenon / Exp<br/>Follower"]
Pod2["Pod-2: MySQL / Xenon / Exp<br/>Follower"]
end
Operator -->|"Watch / Manage"| HeadlessSvc
HeadlessSvc --> Pod0
2 Xenon 高可用管理器的核心原理是什么?
答案:
Xenon 是基于 Raft 协议实现的 MySQL 高可用管理器,以 Sidecar 模式与 MySQL 进程同 Pod 运行。它通过本地 Unix Socket 直接管理 MySQL 的生命周期、复制状态和故障切换。
Xenon 的核心工作流:
- Raft 选举:集群内所有 Xenon 节点构成 Raft Group,通过心跳和投票选出单一 Leader。Leader 即为主节点(Master/Primary),Follower 即为从节点(Slave/Secondary)。
- 心跳检测:Leader 周期性向 Follower 发送心跳(默认 3s / 6s 超时)。Follower 在超时窗口内未收到心跳即触发新的选举。
- MySQL 接管:Xenon 通过 Unix Socket 直接执行
STOP SLAVE/START SLAVE/CHANGE MASTER TO等 MySQL 命令。选举出的 Leader 将本地 MySQL 提升为可写(read_only=OFF),Follower 将本地 MySQL 设为只读(read_only=ON)并建立复制。 - 故障检测与切换:检测到 Leader 故障或网络不可达后,Raft 自动选举新 Leader,新 Leader 接管 MySQL 写入。整个切换流程通常在 10-30 秒内完成。
- GTID 一致性保证:Xenon 依赖 GTID(Global Transaction Identifier)保证主从数据一致性。所有事务通过 GTID 标识,Failover 时新 Leader 基于 GTID 集合决定是否需要从其他节点补偿差异数据。
Xenon 心跳与选举流程:
Leader Xenon Follower Xenon-1 Follower Xenon-2
│ │ │
│──── Heartbeat ────────────►│ │
│──── Heartbeat ────────────────────────────────────►│
│ │ │
│ (Leader 宕机 / 网络分区) │
│ │ │
│ (Tick 超时) │ (Tick 超时) │
│ │ │
│◄──── RequestVote ──────────│ │
│ │── RequestVote ───────►│
│ │◄── VoteGranted ───────│
│ │ │
│ │ New Leader Elected │
│ │ SET GLOBAL read_only=OFF │
│ │◄── Replication ───────│
3 RadonDB 如何实现 MySQL 主从复制与自动故障转移?
答案:
RadonDB 的主从复制基于 MySQL 原生 GTID 复制,由 Xenon 管理其生命周期。Operator 初始化集群时自动配置所有节点的半同步复制(Semi-Synchronous Replication)。
复制建立流程:
- Operator 创建 Init Container,在 Pod-0 上初始化 MySQL 数据目录并启动 MySQL。
- Xenon-0 通过 Raft 选举成为初始 Leader,设置
read_only=OFF。 - Pod-1 的 Init Container 通过 XtraBackup 从 Pod-0 全量复制数据。
- Pod-1 启动 MySQL,Xenon-1 通过 Raft 获知 Leader 为 Pod-0,自动执行
CHANGE MASTER TO建立复制。 - Pod-2 同理从 Leader 复制数据并建立复制链。
故障转移过程:
- Xenon Follower 在心跳超时(默认 6s)后判定 Leader 失联。
- Follower 发起 Raft RequestVote,获得多数票后成为新 Leader。
- 新 Leader 执行
STOP SLAVE,将本地 MySQL 设置read_only=OFF。 - 新 Leader 通过 GTID_PURGED 确认与旧 Leader 的数据差异,必要时从其他节点补偿。
- 其余 Follower 通过 Raft 感知 Leader 变更,自动
CHANGE MASTER TO指向新 Leader。 - Operator 更新 Service 的 Selector/Endpoint 指向新 Leader,写流量自动切至新主节点。
| 机制 | 配置 | 说明 |
|---|---|---|
| 复制模式 | Semi-Synchronous(半同步) | 至少一个从库确认收到 binlog 后事务才提交成功 |
| 复制协议 | GTID | 全局事务 ID,保障 Failover 后数据一致性 |
| 复制过滤 | replicate-wild-do-table / replicate-wild-ignore-table | 选择性复制 |
| 只读保护 | super_read_only=ON | Follower 节点禁止写入 |
4 Xenon 的 Raft 选举机制如何工作?
答案:
Xenon 实现了完整的 Raft 共识协议,用于在 MySQL 集群中选举 Leader 和维护一致性。
Raft 选举核心概念:
| 概念 | 说明 |
|---|---|
| Term(任期) | 全局单调递增的逻辑时钟,每次选举开始新 Term |
| Leader | 当前 Term 中处理所有写请求的节点 |
| Follower | 被动接收日志的节点 |
| Candidate | 发起选举的中间状态 |
| Quorum | 多数派(N/2+1),3 节点集群需 2 票 |
选举触发条件:
- Leader 心跳超时(
raft-timeout,默认 3000ms) - 集群初始化时为 Term 0,所有节点争选
- Leader 主动降级(如收到
SIGTERM)时触发新选举
选举流程:
- Follower 心跳超时后,递增 Term(Term += 1),自身转为 Candidate。
- Candidate 向所有节点发送
RequestVoteRPC,携带自身 Term、最后一条日志的 Index 和 Term。 - 接收节点判断:Candidate 的 Term 必须 >= 自身 Term,且 Candidate 的日志不比自身旧(
LastLogIndex更大或同 Index 时LastLogTerm更新)。 - 若获多数票,Candidate 转为 Leader,立即发送心跳广播新 Leader 身份。
- 若未获多数票(或发现更高 Term 的消息),Candidate 退回 Follower,等待新一轮选举。
投票权重:Xenon 支持为不同节点配置不同投票权重(admit-defeat-hearbeat-count),生产环境三节点等权(各 1 票)为推荐配置。
# Xenon 选举相关配置参数
{
"raft-timeout": 3000, # 心跳超时(毫秒)
"raft-election-timeout": 6000, # 选举超时(毫秒)
"raft-heartbeat-interval": 150, # 心跳间隔(毫秒)
"leader-start-command": "mysql -e 'SET GLOBAL read_only=OFF;'",
"leader-stop-command": "mysql -e 'SET GLOBAL read_only=ON;'"
}
5 RadonDB CRD 资源的核心字段有哪些?
答案:
RadonDB 通过 Kubernetes CRD(Custom Resource Definition)描述 MySQL 集群的期望状态,Operator 负责 Reconcile Loop 将实际状态持续向期望状态收敛。
核心 CRD 类型:
MysqlCluster:描述 MySQL 集群拓扑MysqlVersion:描述 MySQL 镜像版本MysqlBackup:描述备份任务MysqlRestore:描述恢复任务
MysqlCluster CRD 关键字段:
apiVersion: mysql.radondb.com/v1beta1
kind: MysqlCluster
metadata:
name: my-cluster
spec:
mysqlVersion: "8.0.30" # MySQL 版本
replicas: 3 # 副本数(奇数,至少 1)
image: radondb/mysql:8.0.30 # MySQL 镜像
xenonImage: radondb/xenon:1.1.7 # Xenon 镜像
backupImage: radondb/percona-xtrabackup:2.4 # 备份镜像
mysqlOpts: # MySQL 配置参数
innodb_buffer_pool_size: "2G"
max_connections: 1000
slow_query_log: "ON"
character-set-server: "utf8mb4"
xenonOpts: # Xenon 配置参数
raft-timeout: 3000
raft-election-timeout: 6000
resources: # 资源配额
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
persistence: # 持久化存储
size: "100Gi"
storageClassName: "local-storage"
backup: # 备份策略
schedule: "0 2 * * *" # Cron 表达式,每天凌晨 2 点
keepNum: 7 # 保留最近 7 个备份
type: "full" # full / incremental
monitoring: # 监控配置
exporterImage: radondb/mysqld-exporter:0.14.0
serviceMonitorLabels:
team: dba
service: # 服务暴露方式
type: ClusterIP # ClusterIP / NodePort / LoadBalancer
nodePort: 30306
Status 子资源反映集群实时状态:
status:
conditions:
- type: Ready
status: "True"
lastTransitionTime: "2025-03-15T10:00:00Z"
leader: my-cluster-0 # 当前主节点
replicas: 3 # 实际副本数
readyReplicas: 3 # Ready 状态副本数
6 RadonDB 在 Kubernetes 上的部署架构(StatefulSet / Headless Service)如何设计?
答案:
RadonDB 基于 Kubernetes StatefulSet 部署,每个 Pod 分配唯一且稳定的网络标识和持久化存储,满足有状态应用对稳定身份和存储顺序的要求。
部署架构要点:
| Kubernetes 资源 | 用途 | 说明 |
|---|---|---|
| StatefulSet | 管理 MySQL Pod 的生命周期 | 有序启停(0→1→2),每个 Pod 绑定独立 PVC |
| Headless Service | Pod 间服务发现 | clusterIP: None,DNS 记录直接指向 Pod IP |
| Service | 业务读写接入 | ClusterIP/NodePort/LoadBalancer,通过 Label 路由到 Leader |
| PersistentVolumeClaim | 持久化存储 | 每个 Pod 独立 PVC,StatefulSet 生成的固定命名(data-my-cluster-0) |
| ConfigMap | MySQL/Xenon 配置 | 挂载为配置文件 |
| Secret | 凭证管理 | root 密码、复制用户密码、备份密钥 |
# Headless Service - 为每个 Pod 提供稳定 DNS
apiVersion: v1
kind: Service
metadata:
name: my-cluster-headless
spec:
clusterIP: None
selector:
app: mysql
cluster: my-cluster
ports:
- name: mysql
port: 3306
# 读写 Service - 由 Operator 动态将 Label 指向 Leader
apiVersion: v1
kind: Service
metadata:
name: my-cluster
spec:
type: ClusterIP
selector:
app: mysql
cluster: my-cluster
role: leader # Operator 动态管理此 Label
ports:
- name: mysql
port: 3306
DNS 解析规则:
my-cluster-headless.default.svc.cluster.local→ 所有 Pod IP(SRV 记录)my-cluster-0.my-cluster-headless.default.svc.cluster.local→ Pod-0 IP(A 记录)my-cluster.default.svc.cluster.local→ 当前 Leader IP
Pod 拓扑分布:通过 podAntiAffinity 确保同集群 MySQL Pod 分布在不同 Kubernetes 节点上,避免单节点故障导致多个副本同时不可用。
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: mysql
cluster: my-cluster
topologyKey: kubernetes.io/hostname
7 RadonDB 的备份与恢复机制(XtraBackup + CronJob)如何实现?
答案:
RadonDB 使用 Percona XtraBackup 执行物理热备份,通过 Kubernetes CronJob 定时触发备份任务的执行。
备份流程:
- Operator 根据
MysqlCluster.spec.backup.schedule创建MysqlBackupCRD。 - Operator 根据 CRD 创建 Job,Job 以 Sidecar 模式在 Leader Pod 中执行
xtrabackup --backup。 - XtraBackup 直接读取 MySQL 数据目录(
/var/lib/mysql),不需要锁表,基于 InnoDB 的 MVCC 机制实现一致性备份。 - 备份文件通过
xbstream打包,上传到对象存储(S3 / MinIO / Ceph RGW)或 PersistentVolume。 - 备份完成后 Operator 更新
MysqlBackupCRD 的 Status(Completed/Failed),根据keepNum自动清理过期备份。
备份类型:
| 类型 | 命令 | 说明 |
|---|---|---|
| 全量备份 | xtrabackup --backup --target-dir=/backup/full | 备份全部数据文件 |
| 增量备份 | xtrabackup --backup --target-dir=/backup/inc --incremental-basedir=/backup/full | 仅备份自上次全量以来的变更页 |
| 选择性备份 | xtrabackup --backup --databases="db1 db2" | 只备份指定库 |
恢复流程:
- 创建
MysqlRestoreCRD,指定源备份和恢复目标集群。 - Operator 创建 Init Container,挂载备份卷或从对象存储下载备份。
- Init Container 执行
xtrabackup --prepare对备份做 Crash Recovery(前滚 Redo Log,回滚未提交事务)。 - 恢复完成后启动 MySQL,Xenon 自动建立复制拓扑。
# 全量备份 CronJob 示例
apiVersion: mysql.radondb.com/v1beta1
kind: MysqlBackup
metadata:
name: my-cluster-backup-20250315
spec:
clusterName: my-cluster
type: full # full / incremental
storage:
type: s3
s3:
bucket: radondb-backups
endpoint: s3.example.com
region: us-east-1
secretName: s3-credentials
备份周期推荐:
- 生产关键库:每日全量 + 每 6 小时增量
- 一般业务库:每周全量 + 每日增量
- 备份保留:至少保留最近 14 天的每日备份
8 RadonDB 的读写分离如何实现?
答案:
RadonDB 集群具备两种数据库访问入口,天然支持读写分离。
读写入口设计:
| Service | Label Selector | 用途 |
|---|---|---|
my-cluster | role: leader | 写流量接入,始终指向当前 Leader Pod |
my-cluster-readonly | role: follower | 读流量接入,负载均衡到所有 Follower Pod |
读写分离架构:
Application
├── Write ──► Service(role:leader) ──► Leader Pod (read_only=OFF)
│
└── Read ──► Service(role:follower) ──► Follower Pod-1 (read_only=ON)
──► Follower Pod-2 (read_only=ON)
应用层实现方式:
- 双数据源配置(Spring / Django / Rails):配置两个数据源,写操作走 Leader,读操作走 Follower。
- 数据库中间件(ProxySQL / ShardingSphere / Vitess):在应用与数据库之间部署 SQL 路由中间件,根据 SQL 类型自动分流。
- 连接池路由(HikariCP Read/Write Split):利用连接池的读/写数据源分离能力。
# 只读 Service 示例
apiVersion: v1
kind: Service
metadata:
name: my-cluster-readonly
spec:
type: ClusterIP
selector:
app: mysql
cluster: my-cluster
role: follower
ports:
- name: mysql
port: 3306
Follower 节点默认设置 super_read_only=ON,从数据库层面杜绝意外写入。Xenon 在 Leader 切换后自动更新两个 Service 的 Label Selector,确保路由始终指向正确的角色。
9 RadonDB 如何与 Prometheus 集成实现监控?
答案:
RadonDB 部署 mysqld-exporter Sidecar 容器采集 MySQL 运行时指标,通过 Prometheus ServiceMonitor 或 PodMonitor 接入 Prometheus。
监控架构:
graph TD
Prometheus["Prometheus"]
ServiceMonitor["ServiceMonitor CRD"]
Grafana["Grafana"]
Exporter["mysqld-exporter<br/>(Sidecar)<br/>:9104"]
MySQL["MySQL"]
Prometheus --> ServiceMonitor --> Grafana
Prometheus -->|"Scrape /metrics"| Exporter
ServiceMonitor --> Exporter
Exporter -->|"Localhost:3306"| MySQL
核心监控指标:
| 指标类别 | 关键指标 | 说明 |
|---|---|---|
| 连接状态 | mysql_global_status_threads_connected | 当前连接数 |
| QPS/TPS | mysql_global_status_queries, com_select/insert/update/delete | 查询与事务吞吐量 |
| 缓冲池 | mysql_global_status_innodb_buffer_pool_read_requests, _reads | 缓冲池命中率 |
| 复制延迟 | mysql_slave_status_seconds_behind_master | 主从延迟(秒) |
| 慢查询 | mysql_global_status_slow_queries | 慢查询累计数 |
| 锁等待 | mysql_global_status_innodb_row_lock_waits | 行锁等待次数 |
| 磁盘使用 | mysql_global_variables_datadir_size_bytes | 数据目录大小 |
| 线程状态 | mysql_global_status_threads_running | 活跃线程数 |
# ServiceMonitor CRD 示例
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-cluster-mysql
labels:
release: prometheus
spec:
selector:
matchLabels:
app: mysql
cluster: my-cluster
endpoints:
- port: metrics
interval: 30s
path: /metrics
告警规则示例:
MySQLDown:mysql_up == 0MySQLReplicationLag:mysql_slave_status_seconds_behind_master > 30MySQLHighThreads:mysql_global_status_threads_connected > 800MySQLSlowQueriesHigh:rate(mysql_global_status_slow_queries[5m]) > 10
10 RadonDB 如何实现滚动升级与零停机运维?
答案:
RadonDB 的滚动升级由 Operator 协调,按 Follower → Leader 的顺序逐个重建 Pod,保障升级期间集群始终可写。
升级流程:
- 版本镜像准备:更新
MysqlCluster.spec.image为新版本镜像。 - Follower 升级:Operator 从最高索引 Follower 开始(Pod-2 → Pod-1),逐个滚动重建。
- 删除旧 Pod → PVC 保持绑定 → 新 Pod 以 Init Container 方式启动旧版本 MySQL → 对比数据目录一致性 → 替换为新版本镜像 → 重新加入复制
- Leader 降级:所有 Follower 升级完成后,Operator 触发 Leader 主动退位。
- Operator 发送 Leader Transfer 指令(Patch Xenon API)→ 当前 Leader 放弃 Leader 身份 → Raft 自动选举出新 Leader(已升级的 Follower)
- 原 Leader 升级:已降为 Follower 的原 Leader Pod 被删除重建,升级完成后重新加入复制。
- 验证:确认所有 Pod Ready,Leader 可写,Follower 复制正常。
升级过程中的保护机制:
PodDisruptionBudget(PDB)限制不可用副本数(minAvailable: 2),确保滚动升级期间至少 2 个 Pod 在线。- Init Container 校验数据目录与镜像兼容性,不兼容则拒绝启动。
- Xenon 的 Raft 机制保证 Leader 切换期间无写入丢失。
# PDB 示例
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-cluster-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: mysql
cluster: my-cluster
升级命令:
kubectl patch mysqlcluster my-cluster --type='merge' \
-p '{"spec":{"image":"radondb/mysql:8.0.35"}}'
11 RadonDB 的存储配置(PersistentVolume)如何规划?
答案:
RadonDB 每个 MySQL Pod 绑定独立的 PersistentVolumeClaim(PVC),StatefulSet 的 volumeClaimTemplates 确保每个副本拥有独立的持久卷。
存储规划要素:
| 规划维度 | 方案 | 说明 |
|---|---|---|
| 存储类型 | Local PV / Rook Ceph / Longhorn / OpenEBS | 优先 Local PV 获取更高 IOPS,其次分布式存储保障可迁移性 |
| 卷大小 | 生产环境不低于 100Gi | 预留足够空间应对数据增长和 binlog 膨胀 |
| 访问模式 | ReadWriteOnce(RWO) | 每个 PV 只能被一个 Pod 挂载 |
| 存储类 | 按性能分级(fast / standard) | 不同业务库使用不同性能级别 |
| 扩容策略 | allowVolumeExpansion: true | 支持在线扩容 PVC 而不重启 Pod |
# MySQLCluster 持久化配置
spec:
persistence:
size: "200Gi"
storageClassName: "local-ssd"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
存储性能基线:
| 级别 | IOPS(4K 随机读) | 吞吐量 | 延迟 | 适用场景 |
|---|---|---|---|---|
| Local SSD / NVMe | 300000+ | 2GB/s+ | <1ms | 核心交易库 |
| Rook Ceph (SSD) | 50000+ | 500MB/s | 2-3ms | 一般业务库 |
| 云厂商云盘(ESSD PL3 / Premium SSD) | 100000+ | 1GB/s | <1ms | 云上部署 |
| Longhorn (SSD) | 30000+ | 300MB/s | 3-5ms | 一般业务库 |
存储空间规划公式:
总需求 = (数据大小 + 索引大小) × 1.5(碎片/膨胀) + binlog 保留大小 + 临时表空间 + 快照/克隆预留
12 RadonDB 的 XtraBackup 全量与增量备份的区别是什么?
答案:
XtraBackup 是 Percona 提供的 MySQL 物理在线热备份工具,RadonDB 利用其对不同备份粒度实现灵活的备份策略。
| 维度 | 全量备份 | 增量备份 |
|---|---|---|
| 原理 | 备份数据集中所有 InnoDB 页面 | 仅备份自上次全量/增量以来变更的页面(LSN 差异) |
| 命令 | xtrabackup --backup --target-dir=/backup/full | xtrabackup --backup --target-dir=/backup/inc --incremental-basedir=/backup/full |
| 数据量 | 等于当前数据集大小 | 取决于变更量,通常远小于全量 |
| 备份时间 | 分钟级(100Gi 约 5-15 分钟) | 秒级到分钟级 |
| 恢复复杂度 | 低,直接 Prepare → Copy Back | 高,需先 Prepare 全量,再逐一 Apply 增量 |
| 恢复时间 | 分钟级(100Gi 约 10-30 分钟) | 分钟级(取决于增量层数) |
| 存储开销 | 高(每个全量一份完整副本) | 低(仅存储差异页) |
| 适用场景 | 周期性基线备份 | 频繁的时间点保护 |
备份策略组合:
graph LR
F1["全量<br/>Day 1(周日)"] --> I1["增量(1)<br/>Day 2"]
I1 --> I2["增量(2)<br/>Day 3"]
I2 --> I3["增量(3)<br/>Day 4"]
I3 --> F2["全量<br/>Day 5(周四)"]
F2 --> I4["增量(1)<br/>Day 6"]
I4 --> I5["增量(2)<br/>Day 7"]
I5 --> F3["全量<br/>Day 8(周日)"]
XtraBackup Prepare 流程:
xtrabackup --prepare --apply-log-only --target-dir=/backup/full(全量 Prepare)xtrabackup --prepare --apply-log-only --target-dir=/backup/full --incremental-dir=/backup/inc1(Apply 第一个增量)xtrabackup --prepare --target-dir=/backup/full --incremental-dir=/backup/inc2(Apply 最后一个增量,不加--apply-log-only)xtrabackup --copy-back --target-dir=/backup/full(恢复到数据目录)
恢复时间对比:
| 备份链 | 步骤数 | 典型恢复时间(100Gi 数据) |
|---|---|---|
| 纯全量 | 1 | 10-20 分钟 |
| 全量 + 1 增量 | 2 | 12-25 分钟 |
| 全量 + 5 增量 | 6 | 20-40 分钟 |
| 全量 + 10 增量 | 11 | 30-60 分钟 |
13 RadonDB 的故障检测与 Leader 切换流程是怎样的?
答案:
RadonDB 的故障检测依赖 Xenon 的 Raft 心跳机制,由所有 Follower 节点独立判断 Leader 是否存活。
故障检测层次:
| 检测层 | 机制 | 阈值 | 说明 |
|---|---|---|---|
| Raft 心跳 | Leader 定期向 Follower 发送心跳 | 心跳间隔 150ms,超时 3000ms | Xenon 进程级检测 |
| MySQL 探活 | Xenon 通过 Unix Socket 定期 mysqladmin ping | 通常 1s | 防止 Xenon 正常但 MySQL 僵死 |
| Readiness Probe | Kubernetes Liveness/Readiness Probe | failureThreshold: 3 | 容器级检测 |
故障检测时间线:
T+0s Leader 故障(OOM/NodeFailure/XenonCrash)
T+0~3s Follower 心跳超时(raft-timeout: 3000ms)
T+3s Follower 转为 Candidate,发送 RequestVote
T+3~4s 获得多数票,新 Leader 选出
T+4s 新 Leader 执行 leader-start-command(read_only=OFF)
T+4~5s 新 Leader 广播心跳,Follower 感知新 Leader 身份
T+5~8s Follower CHANGE MASTER TO 新 Leader
T+5~10s Operator 更新 Service Label(role: leader 指向新 Pod)
T+10~30s 应用感知连接中断 → 重连 → 恢复写入
Leader 切换类型:
| 切换类型 | 触发条件 | 数据影响 | RTO |
|---|---|---|---|
| 计划内切换(Planned) | 滚动升级、维护窗口、手动 kubectl cordon | 无数据丢失 | 5-10s |
| 故障切换(Unplanned) | Leader Pod OOM、节点宕机 | 可能丢失未同步的事务(半同步则 0 丢失) | 10-30s |
| 脑裂切换(Split-Brain) | 网络分区导致双 Leader | Raft Quorum 保障仲裁后唯一 Leader | 15-30s |
# 手动触发 Leader 切换
kubectl exec -it my-cluster-0 -c xenon -- xenoncli raft transfer
# 查看集群当前状态
kubectl exec -it my-cluster-0 -c xenon -- xenoncli cluster raft
kubectl exec -it my-cluster-0 -c xenon -- xenoncli mysql status
14 RadonDB 的日志管理(Error / Slow Query / Binlog)如何配置?
答案:
RadonDB 的日志体系覆盖 MySQL 服务器日志、二进制日志(Binlog)和慢查询日志,通过 ConfigMap 集中管理配置,通过 Sidecar(如 Filebeat / Fluent Bit)采集并输出到集中式日志平台。
| 日志类型 | MySQL 参数 | 输出路径 | 用途 |
|---|---|---|---|
| Error Log | log_error | stderr(容器日志) | 启动错误、崩溃、复制错误、表损坏 |
| Slow Query Log | slow_query_log, long_query_time | stderr 或数据目录文件 | 性能瓶颈分析、索引优化 |
| General Log | general_log | stderr(默认关闭) | 连接和查询审计(生产环境关闭) |
| Binlog | log_bin, binlog_format | 数据目录下 binlog.xxxxxx | 主从复制、PITR(时间点恢复) |
| Relay Log | relay_log | 数据目录下 | Follower 从中继日志重放 Leader 事务 |
# MySQLCluster 日志相关配置
spec:
mysqlOpts:
# Error Log
log_error_verbosity: "2" # 1:errors 2:errors+warnings 3:errors+warnings+notes
# Slow Query
slow_query_log: "ON"
long_query_time: "1.0" # 超过 1 秒计入慢查询
log_queries_not_using_indexes: "ON"
log_slow_admin_statements: "ON"
min_examined_row_limit: "1000" # 扫描行数超过 1000 才记录
# Binlog
log_bin: "ON"
binlog_format: "ROW" # ROW 格式利于复制一致性
binlog_row_image: "FULL"
sync_binlog: "1" # 每次事务同步 binlog 到磁盘
expire_logs_days: "7" # binlog 保留 7 天
max_binlog_size: "500M"
binlog_cache_size: "32768"
日志采集架构:
MySQL Container stdout/stderr
│
├──► kubectl logs (临时查看)
│
└──► Fluent Bit / Filebeat DaemonSet
│
├──► Elasticsearch / Loki
│
└──► Grafana (日志查询)
配置日志持久化(将日志写入持久化 Volume):
spec:
mysqlOpts:
log_output: "FILE" # 输出到文件而非 stderr
slow_query_log_file: "/var/lib/mysql/slow-query.log"
general_log_file: "/var/lib/mysql/general.log"
15 RadonDB 如何实现集群扩缩容?
答案:
RadonDB 支持水平扩缩容(增减 Replica)和垂直扩缩容(调整 CPU/内存),由 Operator 协调执行。
水平扩容(增加 Follower)
- 修改
MysqlCluster.spec.replicas为目标副本数(如 3 → 5)。 - Operator Reconcile 检测到
spec.replicas > status.replicas,创建新 Pod(my-cluster-3)。 - Init Container 从当前 Leader 通过 XtraBackup 全量复制数据。
- 新 Pod 启动 MySQL 和 Xenon,Xenon 加入 Raft Group 成为 Follower。
- Xenon 自动执行
CHANGE MASTER TO指向当前 Leader,建立复制。
水平缩容(减少 Follower)
- 修改
replicas为目标副本数(如 5 → 3)。 - Operator 从最高索引 Pod 开始删除(
my-cluster-4→my-cluster-3)。 - 被删除的 Pod 对应的 PVC 保留(StatefulSet 不自动删除 PVC),需手动清理。
- Raft 成员列表自动剔除已删除节点。
垂直扩缩容(调整资源)
- 修改
MysqlCluster.spec.resources.requests/limits。 - Operator 按滚动更新策略(先 Follower 后 Leader)逐个重建 Pod。
- 设置
MysqlCluster.spec.updateStrategy.type: OnDelete可在手动删除时触发重建。 - PVC 扩容(若支持
allowVolumeExpansion):kubectl patch pvc data-my-cluster-0 -p '{"spec":{"resources":{"requests":{"storage":"200Gi"}}}}'
扩容注意点:
| 约束 | 说明 |
|---|---|
| 副本数为奇数 | 满足 Raft 多数派投票要求(1 / 3 / 5 / 7) |
| PodAntiAffinity | 扩容需确保目标 Node 不被已有 Pod 占用 |
| 存储容量 | 新 Pod 需匹配存储类支持的容量 |
| 网络带宽 | XtraBackup 数据同步占用带宽,生产环境限制传输速率 |
| Binlog 同步压力 | 新 Follower 追赶数据期间的 IO 压力 |
16 RadonDB 的 MysqlVersion CRD 与版本管理机制是什么?
答案:
MysqlVersion CRD 定义可用的 MySQL 镜像版本元数据,Operator 通过该 CRD 校验升级路径的兼容性,并管理不同 MySQL 版本对应的镜像、Sidecar 版本和配置模板。
apiVersion: mysql.radondb.com/v1beta1
kind: MysqlVersion
metadata:
name: mysql-8.0.30
spec:
version: "8.0.30"
mysqlImage: "radondb/mysql:8.0.30"
xenonImage: "radondb/xenon:1.1.7"
mysqlExporterImage: "radondb/mysqld-exporter:0.14.0"
backupImage: "radondb/percona-xtrabackup:8.0.30"
initImage: "radondb/mysql:8.0.30"
# 升级限制:仅允许从指定版本平滑升级
upgradeConstraints:
- from: "8.0.28"
- from: "8.0.29"
- from: "8.0.30"
版本管理能力:
| 能力 | 说明 |
|---|---|
| 版本发现 | Operator 启动时加载所有 MysqlVersion CRD,构建版本映射表 |
| 升级校验 | 创建集群时指定 spec.mysqlVersion,Operator 查找匹配的 MysqlVersion CRD |
| 滚动升级 | 更新 MysqlCluster.spec.mysqlVersion,Operator 按升级约束执行滚动升级 |
| 多版本共存 | 不同集群可使用不同 MySQL 版本,同一集群所有 Pod 版本一致 |
| 镜像替换 | 通过修改 MysqlVersion.spec.mysqlImage,所有引用该版本的集群均可感知变更 |
升级路径约束:MySQL 版本升级存在限制——只能跨越一个 GA 版本(如 8.0.28 → 8.0.34 不等同于 8.0.28 → 8.0.30 → 8.0.34 两次升级),Operator 依据 upgradeConstraints 拒绝跨版本直升。
# 查看支持的 MySQL 版本
kubectl get mysqlversion
# 修改集群使用的 MySQL 版本
kubectl patch mysqlcluster my-cluster --type='merge' \
-p '{"spec":{"mysqlVersion":"8.0.35"}}'
17 RadonDB 的参数配置管理(ConfigMap 热更新)如何实现?
答案:
RadonDB 通过 ConfigMap 管理 MySQL 和 Xenon 的运行时配置,支持静态配置(需重启生效)和动态参数(在线修改 SET GLOBAL 生效)两类变更方式。
配置分布:
| 配置来源 | 管理方式 | 生效方式 |
|---|---|---|
spec.mysqlOpts | 写入 ConfigMap,挂载为 my.cnf | 静态参数需重启,动态参数可在线修改 |
spec.xenonOpts | 写入 ConfigMap,挂载为 xenon.json | 需重启 Xenon Sidecar |
| 动态参数 | mysql -e 'SET GLOBAL xxx=yyy' | 立即生效 |
| 持久化动态参数 | 写入 ConfigMap 同时执行 SET GLOBAL | 重启后从 ConfigMap 重新加载 |
apiVersion: v1
kind: ConfigMap
metadata:
name: my-cluster-config
data:
my.cnf: |
[mysqld]
server-id=100
innodb_buffer_pool_size=2G
max_connections=1000
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
slow_query_log=ON
long_query_time=1.0
binlog_format=ROW
sync_binlog=1
gtid_mode=ON
enforce-gtid-consistency=ON
xenon.json: |
{
"raft-timeout": 3000,
"raft-election-timeout": 6000,
"admit-defeat-hearbeat-count": 5,
"leader-start-command": "mysql -e 'SET GLOBAL read_only=OFF; SET GLOBAL super_read_only=OFF;'",
"leader-stop-command": "mysql -e 'SET GLOBAL super_read_only=ON; SET GLOBAL read_only=ON;'"
}
可在线修改的动态参数:
max_connectionsinnodb_buffer_pool_size(MySQL 8.0+)slow_query_log/long_query_timeread_only(由 Xenon 自动管理)innodb_flush_log_at_trx_commitsync_binloggeneral_log
配置变更最佳实践:
# 1. 修改 ConfigMap 后重新应用
kubectl apply -f configmap.yaml
# 2. 执行滚动重启,使静态参数生效
kubectl rollout restart statefulset my-cluster
# 3. 仅修改动态参数(无需重启)
kubectl exec -it my-cluster-0 -- mysql -e "SET GLOBAL max_connections=2000;"
18 RadonDB 与 Percona Operator 的对比分析?
答案:
两者都提供 Kubernetes 上运行 MySQL 集群的能力,但在架构、高可用机制、备份方式等方面存在差异。
| 维度 | RadonDB | Percona Operator for MySQL (PXC) |
|---|---|---|
| 高可用机制 | Xenon Raft + GTID 半同步复制 | Galera Cluster(Multi-Master/Active-Active) |
| 写入模型 | 单 Leader(Leader/Follower) | 多 Master(任意节点可写,提交时跨节点认证) |
| 一致性模型 | 最终一致性(半同步) | 强一致性(Galera 基于 Paxos 的认证复制) |
| 故障切换 RTO | 10-30 秒(Raft 选举 + 复制重建) | 0 秒(任意节点可写,故障节点自动从集群剔除) |
| 备份工具 | XtraBackup | XtraBackup |
| 最低节点数 | 1(无 HA)或 3(HA) | 3(Galera 要求奇数票) |
| 跨 DC 延迟敏感性 | 低(异步/半同步) | 高(Galera 写操作受最慢节点制约) |
| 读扩展 | 读写分离 Service | ProxySQL 集成,透明读写分离 |
| 存储引擎 | InnoDB | InnoDB(Galera 支持 wsrep API 的 InnoDB) |
| Operator 实现语言 | Go | Go |
| 社区活跃度 | RadonDB 社区(青云主导) | Percona(企业支撑) |
选型建议矩阵:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 跨 AZ/跨 DC 部署 | RadonDB | Xenon Raft 对跨 DC 延迟容忍度高于 Galera |
| 强一致性需求 | Percona PXC | Galera 提供写操作强一致性保证 |
| 读密集型业务 | RadonDB | 读写分离 Service 简单高效 |
| 大量并发写入 | RadonDB | Galera 多 Master 写入的流控机制可能成为瓶颈 |
| 运维复杂度 | RadonDB | Xenon + MySQL 标准复制,运维心智成本低 |
19 RadonDB 与 KubeBlocks 的对比分析?
答案:
KubeBlocks 是 ApeCloud 开源的数据库 Kubernetes Operator 平台,提供统一的数据库管理抽象层。RadonDB 是独立 MySQL Operator,两者定位不同但存在交集。
| 维度 | RadonDB | KubeBlocks |
|---|---|---|
| 定位 | 单一 MySQL 数据库 Operator | 多数据库通用 Operator 平台 |
| 支持数据库 | MySQL | MySQL / PostgreSQL / Redis / MongoDB / Kafka 等 |
| 高可用 | Xenon Raft + GTID | 集成 Xenon / Patroni / Sentinel 等 HA 组件 |
| 抽象层 | 仅 MySQL 领域模型 | Add-on 插件化,新增数据库类型以 Add-on 方式接入 |
| 运维面板 | 无内建 UI | KubeBlocks Dashboard(Web UI) |
| 备份恢复 | 内建 XtraBackup + CronJob | 统一 Backup API,支持多种备份目标 |
| 参数管理 | ConfigMap + OpsRequest CRD | ClusterDefinition 中声明式定义 + Reconfiguring |
| CLI 工具 | kubectl 直接操作 | kbcli 命令行 |
| 水平扩容 | 直接修改 replicas | kbcli cluster horizontal-scaling |
| 垂直扩容 | 修改 resources + 滚动重启 | kbcli cluster vertical-scaling |
核心差异:
- RadonDB 以 MySQL 为中心的深度优化(Xenon Raft、XtraBackup 集成、MySQL 配置模板),在 MySQL 专项场景深度更高。
- KubeBlocks 以通用平台为设计目标,通过 Add-on 机制统一管理多数据库,在异构数据库统一治理场景更有优势。
- KubeBlocks 的 Reconfiguring(参数变更)支持在线/滚动/重启多种策略,抽象层次更高。
- RadonDB 的 Xenon Raft 选举与 KubeBlocks 的 Xenon Add-on 共享同一组件。
20 RadonDB 与 KubeDB 的对比分析?
答案:
KubeDB 是 AppsCode 开发的 Kubernetes 原生数据库 Operator,覆盖多种数据库类型。两者在 MySQL 管理上的对比:
| 维度 | RadonDB | KubeDB |
|---|---|---|
| 开发商 | 青云科技 / RadonDB 社区 | AppsCode |
| 架构 | Xenon Raft + MySQL 半同步 | MySQL Group Replication / 单实例 / Semi-Sync |
| 高可用方案 | Xenon(内建 HA Manager) | MySQL Group Replication(MGR)/ Semi-Sync |
| TLS/SSL | 支持 TLS 加密传输 | 内建 cert-manager 自动化 TLS 证书 |
| 备份 | XtraBackup + S3/MinIO | Stash(AppsCode 自研备份框架) |
| 监控 | Prometheus mysqld-exporter + ServiceMonitor | Prometheus 内建集成 + Grafana Dashboard |
| 许可证 | Apache 2.0 | 社区版 Apache 2.0 / 企业版付费 |
| Hooks | 无显式 Hook 机制 | 支持 Init / Backup / Restore 等 Hook 脚本 |
| Schema 管理 | 不涉及 | 支持以 YAML 方式声明 Schema(Table/View/Procedure) |
| 归档 | 无 | 支持将旧数据归档至对象存储 |
| 弹性伸缩 | 修改 Replicas / Resources | HPA/ VPA 集成 + 自动扩缩容 |
核心差异:
- KubeDB 的 Stash 备份框架提供比 RadonDB CronJob 更丰富的备份治理(保留策略、回滚、跨集群恢复)。
- KubeDB 内建 cert-manager 集成简化了 TLS 证书生命周期管理。
- RadonDB 的 Xenon Raft 比 KubeDB 的 Semi-Sync 方案在故障检测和自动切换方面更加自动化。
- KubeDB 企业版功能(Auto-Scaling、Schema Management、Database Proxy 集成)在部分场景不可用(需付费)。
21 RadonDB 的分布式事务有哪些限制?
答案:
RadonDB MySQL 集群基于 MySQL 异步/半同步主从复制,不提供分布式事务支持。架构为共享存储(单 Leader 写入),而非 Shared-Nothing 分片架构。
事务支持范围:
| 事务类型 | 支持状态 | 说明 |
|---|---|---|
| 单节点事务 | 完全支持 | ACID 事务,通过 InnoDB 保证 |
| 跨节点写入事务 | 不支持 | 无分布式事务协调器 |
| 跨分片事务(XA) | 不支持 | RadonDB 不做数据分片 |
| 两阶段提交(2PC) | 不支持 | 无全局事务管理器 |
| 读已提交(Read Committed) | 支持 | InnoDB 默认隔离级别 |
| 可重复读(Repeatable Read) | 支持 | InnoDB 默认隔离级别 |
| 读未提交(Read Uncommitted) | 支持 | 不推荐使用 |
| 串行化(Serializable) | 支持 | 性能开销大,谨慎使用 |
| 保存点(Savepoint) | 支持 | MySQL 原生 Savepoint |
数据分布模型:
graph TD
subgraph Leader["Leader (my-cluster-0)"]
Data["db1 / db2 / db3 (全量数据)<br/>所有写入在此完成"]
end
Leader -->|"Binlog Replication"| Follower1["Follower<br/>(只读副本)<br/>全量数据"]
Leader -->|"Binlog Replication"| Follower2["Follower<br/>(只读副本)<br/>全量数据"]
对比分片架构(如 Vitess / ShardingSphere):
| 维度 | RadonDB | 分片架构 |
|---|---|---|
| 数据分布 | 全量副本 | 按 Shard Key 分片存储 |
| 写扩展 | 垂直扩展(单机升级) | 水平扩展(增加分片) |
| 跨分片 JOIN | N/A(无分片) | 不支持或通过中间件模拟 |
| 事务语义 | 完整 ACID | 单分片 ACID,跨分片最终一致 |
| 运维复杂度 | 低 | 高(需管理分片键、路由规则、再平衡) |
22 RadonDB 的 Service 暴露方式有哪些?
答案:
RadonDB 提供三种 Service 暴露方式,分别适用于集群内部访问、开发测试远程连接和生产环境 LoadBalancer。
| Service 类型 | 访问范围 | 适用场景 | 注意事项 |
|---|---|---|---|
| ClusterIP | Kubernetes 集群内部 | 同集群内应用访问数据库 | 默认方式,最安全 |
| NodePort | 集群节点 IP + 指定端口 | 开发调试、VPN 访问 | 端口范围 30000-32767 |
| LoadBalancer | 云厂商 LB / MetalLB | 外部应用访问数据库 | 需 LB 控制器支持 |
# ClusterIP(默认)
spec:
service:
type: ClusterIP
# NodePort
spec:
service:
type: NodePort
nodePort: 30306
# LoadBalancer
spec:
service:
type: LoadBalancer
loadBalancerIP: "10.0.0.100"
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
Service Endpoint 动态切换:Operator 实时监控 Xenon Raft 状态,当 Leader 切换后立即更新 Service 的 Label Selector(role: leader 指向新 Leader),确保写流量自动切到新主节点。
只读 Service 配置:
apiVersion: v1
kind: Service
metadata:
name: my-cluster-readonly
labels:
app: mysql
cluster: my-cluster
spec:
type: ClusterIP
selector:
app: mysql
cluster: my-cluster
role: follower
ports:
- name: mysql
port: 3306
targetPort: 3306
Pod 端口映射:
| 端口 | 用途 | 说明 |
|---|---|---|
| 3306 | MySQL 服务端口 | 数据库连接 |
| 9104 | mysqld-exporter Metrics | Prometheus 采集 |
| 8080 | Xenon HTTP API | Xenon 状态查询与管理 |
23 RadonDB 的 TLS 加密与安全配置如何实现?
答案:
RadonDB 支持 MySQL 客户端与服务器之间的 TLS 加密通信,以及节点间复制链路的 TLS 加密。
TLS 配置架构:
spec:
tls:
enabled: true
# 引用包含 TLS 证书的 Secret
secretName: mysql-tls-secret
# 可选:指定 SAN(Subject Alternative Name)
issuerRef:
name: mysql-ca-issuer
kind: Issuer
Secret 内容要求(mysql-tls-secret):
| Key | 内容 | 说明 |
|---|---|---|
ca.crt | CA 根证书 | 签发客户端和服务端证书 |
tls.crt | 服务端证书 | MySQL 服务端使用的 X.509 证书 |
tls.key | 服务端私钥 | 对应服务端证书的私钥 |
MySQL TLS 配置项(Xenon 自动设置):
[mysqld]
ssl_ca=/etc/mysql/certs/ca.crt
ssl_cert=/etc/mysql/certs/tls.crt
ssl_key=/etc/mysql/certs/tls.key
require_secure_transport=ON
安全配置集成:
| 安全维度 | 配置 | 效果 |
|---|---|---|
| 传输加密 | require_secure_transport=ON | 所有客户端连接必须使用 TLS |
| 复制加密 | Slave 连接自动使用 MASTER_SSL=1 | 主从复制链路加密 |
| 密码策略 | validate_password 插件 | 密码复杂度校验 |
| 连接限制 | max_connect_errors / connect_timeout | 防暴力破解 |
| 网络安全 | NetworkPolicy 仅允许白名单 CIDR | 最小化暴露面 |
| 审计 | General Log(关闭)+ 应用层审计 | 可审计 SQL 操作 |
# NetworkPolicy 限制数据库访问来源
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-network-policy
spec:
podSelector:
matchLabels:
app: mysql
cluster: my-cluster
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: backend
- podSelector:
matchLabels:
app: my-app
ports:
- protocol: TCP
port: 3306
用户权限最小化:
-- 应用用户仅授权必要库表
CREATE USER 'app_user'@'%' IDENTIFIED BY 'secure_password' REQUIRE SSL;
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'%';
-- 监控用户仅授予查询权限
CREATE USER 'monitor'@'%' IDENTIFIED BY 'monitor_password' REQUIRE SSL;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'monitor'@'%';
24 RadonDB 的监控告警规则如何配置?
答案:
RadonDB 复用 Prometheus + Alertmanager + Grafana 栈实现监控告警,告警规则通过 PrometheusRule CRD 定义。
告警分层设计:
| 层级 | 告警类型 | 紧急程度 |
|---|---|---|
| P0 / Critical | MySQL 进程停止、主从复制中断、磁盘满 | 立即响应 |
| P1 / Warning | 复制延迟 > 30s、连接数 >80%、缓冲池命中率 <95% | 15 分钟内响应 |
| P2 / Info | 慢查询增长、磁盘使用 >70%、连接异常断连 | 工作时间处理 |
PrometheusRule 示例:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: mysql-alerts
labels:
release: prometheus
spec:
groups:
- name: mysql-critical
rules:
# P0: MySQL 实例宕机
- alert: MySQLDown
expr: mysql_up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "MySQL instance XQOPEN $labels.pod XQCLOSE is down"
description: "MySQL on pod XQOPEN $labels.pod XQCLOSE has been down for more than 1 minute."
runbook_url: "https://wiki.example.com/mysql-down"
# P0: 复制中断
- alert: MySQLReplicationBroken
expr: mysql_slave_status_slave_io_running == 0 or mysql_slave_status_slave_sql_running == 0
for: 1m
labels:
severity: critical
annotations:
summary: "MySQL replication broken on XQOPEN $labels.pod XQCLOSE"
- name: mysql-warning
rules:
# P1: 复制延迟
- alert: MySQLReplicationLag
expr: mysql_slave_status_seconds_behind_master > 30
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL replication lag XQOPEN $value XQCLOSEs on XQOPEN $labels.pod XQCLOSE"
# P1: 连接数超过 80%
- alert: MySQLHighConnectionUsage
expr: (mysql_global_status_threads_connected / mysql_global_variables_max_connections) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL connection usage XQOPEN $value | humanize XQCLOSE% on XQOPEN $labels.pod XQCLOSE"
# P1: 缓冲池命中率低于 95%
- alert: MySQLLowBufferPoolHitRate
expr: (rate(mysql_global_status_innodb_buffer_pool_read_requests[10m]) - rate(mysql_global_status_innodb_buffer_pool_reads[10m])) / rate(mysql_global_status_innodb_buffer_pool_read_requests[10m]) < 0.95
for: 10m
labels:
severity: warning
annotations:
summary: "InnoDB buffer pool hit rate below 95% on XQOPEN $labels.pod XQCLOSE"
# P1: 磁盘增长预测
- alert: MySQLDiskSpacePrediction
expr: predict_linear(mysql_global_variables_datadir_size_bytes[6h], 24*3600) > 200*1024*1024*1024
for: 1h
labels:
severity: warning
annotations:
summary: "MySQL data directory predicted to exceed 200GB in 24h"
- name: mysql-info
rules:
# P2: 慢查询增长
- alert: MySQLSlowQueriesIncrease
expr: rate(mysql_global_status_slow_queries[5m]) > 10
for: 10m
labels:
severity: info
annotations:
summary: "Slow queries rate XQOPEN $value XQCLOSE/s on XQOPEN $labels.pod XQCLOSE"
# P2: 磁盘使用超过 70%
- alert: MySQLDiskSpaceUsage
expr: (mysql_global_variables_datadir_size_bytes / 200*1024*1024*1024) * 100 > 70
for: 1h
labels:
severity: info
annotations:
summary: "MySQL data directory usage XQOPEN $value | humanize XQCLOSE%"
Grafana Dashboard 推荐面板:
| 面板 | 指标 | 可视化 |
|---|---|---|
| QPS / TPS | rate(mysql_global_status_queries[1m]) | Graph(双线) |
| 连接数 | mysql_global_status_threads_connected | Graph |
| 缓冲池命中率 | 计算指标 | Gauge(0-100%) |
| 复制延迟 | mysql_slave_status_seconds_behind_master | Graph(单线,按 Pod) |
| 慢查询速率 | rate(mysql_global_status_slow_queries[5m]) | Graph |
| 表锁/行锁等待 | mysql_global_status_innodb_row_lock_waits | Graph |
| InnoDB IO | mysql_global_status_innodb_data_reads/writes | Graph |
| 事务提交/回滚 | rate(mysql_global_status_com_commit[1m]) | Graph |
25 RadonDB 的网络分区与脑裂防护机制是什么?
答案:
RadonDB 的脑裂防护依赖 Raft 协议的 Quorum 机制和 Xenon 的 Lease 检查,多层防护保证任意网络分区下仅存在一个可写 Leader。
脑裂场景分析:
| 分区类型 | 分区拓扑 | Raft Quorum | 结果 |
|---|---|---|---|
| 对称分区 | {0} 与 {1, 2} 隔离 | 节点 0: 1票(1/3) < Quorum(2),节点 1,2: 2票(2/3) >= Quorum | {1,2} 侧选出新 Leader,节点 0 降为 Follower 且 read_only=ON |
| 完全分区 | {0} / {1} / {2} 互相隔离 | 每个节点仅 1票 < Quorum | 全集群无 Leader,所有节点只读 |
| 少数派分区 | {0} 与 {1,2,3,4} 隔离(5 节点) | {0}: 1票 < Quorum(3),{1,2,3,4}: 4票 >= Quorum(3) | 多数派侧继续服务 |
脑裂防护机制层次:
| 防护层 | 机制 | 作用 |
|---|---|---|
| Raft Leader Lease | Leader 需持续获得多数节点确认 | 分区后旧 Leader 在 Lease 到期后确认失去多数派支持 |
| Xenon 降级检查 | leader-stop-command 断开时自动执行 read_only=ON | 旧 Leader 发现自身不再是 Raft Leader 后立即只读 |
MySQL super_read_only | 所有 Follower 强制 super_read_only=ON | 防止旧 Leader 残留写入 |
| Raft Pre-Vote | 防止网络恢复后已退位的节点发起无意义选举 | 防止集群恢复时的扰动 |
// Xenon 脑裂防护配置
{
"raft-timeout": 3000,
"raft-election-timeout": 6000,
"leader-start-command": "mysql -e 'SET GLOBAL read_only=OFF; SET GLOBAL super_read_only=OFF;'",
"leader-stop-command": "mysql -e 'SET GLOBAL read_only=ON; SET GLOBAL super_read_only=ON;'",
"admit-defeat-hearbeat-count": 5
}
分区恢复后的处理:
- 网络恢复后,分区节点重新收到 Raft 心跳。
- 旧 Leader 发现 Raft Term 落后,退回 Follower 状态。
- Xenon 自动
CHANGE MASTER TO指向新 Leader。 - 如果旧 Leader 在分区期间产生了未同步的写入(发生在脑裂未完全防护的场景),Xenon 根据 GTID 差异检测并触发告警——这部分数据无法恢复,需人工介入评估。
26 RadonDB 的跨可用区部署如何规划?
答案:
RadonDB 利用 Kubernetes 节点亲和性和拓扑分布约束,实现 MySQL 集群跨可用区(AZ)部署,抵御单 AZ 故障。
跨 AZ 部署架构(3 AZ 示例):
graph TD
subgraph AZ1["AZ-1 (us-east-1a)"]
subgraph NodeA["Node-A"]
Pod0["my-cluster-0<br/>MySQL<br/>Xenon<br/>PVC (SSD)"]
end
end
subgraph AZ2["AZ-2 (us-east-1b)"]
subgraph NodeB["Node-B"]
Pod1["my-cluster-1<br/>MySQL<br/>Xenon<br/>PVC (SSD)"]
end
end
subgraph AZ3["AZ-3 (us-east-1c)"]
subgraph NodeC["Node-C"]
Pod2["my-cluster-2<br/>MySQL<br/>Xenon<br/>PVC (SSD)"]
end
end
Pod0 <-->|"Raft Heartbeat (跨 AZ)"| Pod1
Pod1 <-->|"Raft Heartbeat (跨 AZ)"| Pod2
Pod0 <-->|"Raft Heartbeat (跨 AZ)"| Pod2
跨 AZ 关键配置:
spec:
replicas: 3
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: mysql
cluster: my-cluster
topologyKey: topology.kubernetes.io/zone # 跨 AZ 分布
存储层跨 AZ 方案:
| 方案 | 说明 | 优缺点 |
|---|---|---|
| 云厂商跨 AZ 云盘 | 每个 AZ 独立 PV | 性能最优,依赖云平台 |
| Rook Ceph 跨 AZ 集群 | OSD 分布在多个 AZ,副本数>=3 | 统一存储层,跨 AZ 延迟增加 |
| 每个 AZ 独立 Local PV | 无共享存储 | 性能最高,无跨 AZ 存储依赖 |
跨 AZ 复制延迟考量:
| 场景 | 机房间延迟 | 复制模式 | 对写入事务的影响 |
|---|---|---|---|
| 同 AZ | <0.5ms | 半同步 | 几乎无额外延迟 |
| 跨 AZ(同 Region) | 1-3ms | 半同步 | 每个事务增加 1-3ms(等一确认) |
| 跨 Region | 30-100ms | 异步 | 无延迟影响,但故障时可能丢失数据 |
Raft 选举跨 AZ 影响:跨 AZ 部署时 Raft 心跳延迟略有增加,将 raft-timeout 从默认3000ms 调整为5000ms 可避免因跨 AZ 网络抖动导致的误触发选举。
// 跨 AZ 部署 Xenon 建议配置
{
"raft-timeout": 5000,
"raft-election-timeout": 10000,
"raft-heartbeat-interval": 250
}
27 RadonDB 的性能优化参数有哪些?
答案:
RadonDB 基于 MySQL InnoDB 存储引擎的性能优化参数覆盖缓冲池、日志、并发控制、查询优化等多个维度。
InnoDB 核心参数:
| 参数 | 推荐值(生产环境) | 说明 |
|---|---|---|
innodb_buffer_pool_size | 物理内存的 60-70% | 缓冲池,缓存数据和索引 |
innodb_buffer_pool_instances | 8(buffer_pool_size >= 8G 时) | 减少缓冲池竞争 |
innodb_log_file_size | 2G | Redo Log 大小,大值减少 checkpoint 频率 |
innodb_log_buffer_size | 256M | Redo Log 缓冲,减少磁盘 IO |
innodb_flush_log_at_trx_commit | 1 | 每次事务刷盘(安全),可设为 2 提升性能但丢失 1s 数据 |
innodb_flush_method | O_DIRECT | 绕过 OS 页缓存,避免双重缓存 |
innodb_io_capacity | SSD:2000-4000,HDD:200 | 后台 IO 速率,影响刷脏页速度 |
innodb_io_capacity_max | SSD:8000-12000 | 脏页比例高时的最大 IO 速率 |
innodb_read_io_threads | 8 | 预读线程 |
innodb_write_io_threads | 8 | 刷脏页线程 |
innodb_page_cleaners | 8 | 脏页清理线程 |
innodb_purge_threads | 4 | Undo Log 清理线程 |
innodb_adaptive_hash_index | ON | 自适应哈希索引,加速热点数据查找 |
连接与线程:
| 参数 | 推荐值 | 说明 |
|---|---|---|
max_connections | 500-2000 | 最大连接数,取决于应用并发量 |
thread_cache_size | 100-200 | 线程缓存,避免频繁创建销毁 |
table_open_cache | 4000 | 表缓存 |
table_definition_cache | 2000 | 表定义缓存 |
back_log | 500 | TCP 连接队列大小 |
Binlog 与复制:
| 参数 | 推荐值 | 说明 |
|---|---|---|
sync_binlog | 1(安全) | 每次事务同步 binlog 到磁盘 |
binlog_cache_size | 64K-1M | binlog 事务缓存 |
binlog_group_commit_sync_delay | 0 | Group Commit 延迟(微秒),0=不延迟 |
slave_parallel_workers | 4-8 | 并行复制 worker 线程数 |
slave_parallel_type | LOGICAL_CLOCK | 基于逻辑时钟的并行复制 |
查询优化:
| 参数 | 推荐值 | 说明 |
|---|---|---|
tmp_table_size | 128M | 内存临时表最大大小 |
max_heap_table_size | 128M | MEMORY 表最大大小 |
sort_buffer_size | 4M-16M | 排序缓冲区 |
join_buffer_size | 4M-16M | JOIN 缓冲区 |
read_buffer_size | 2M | 顺序扫描缓冲区 |
read_rnd_buffer_size | 4M | 随机读缓冲区 |
eq_range_index_dive_limit | 200 | 等值范围索引下探限制 |
生产环境 InnoDB 配置推荐:
[mysqld]
# InnoDB 核心
innodb_buffer_pool_size = 16G
innodb_buffer_pool_instances = 8
innodb_log_file_size = 2G
innodb_log_buffer_size = 256M
innodb_flush_log_at_trx_commit = 1
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_page_cleaners = 8
# 连接
max_connections = 1000
thread_cache_size = 200
table_open_cache = 4000
# Binlog
binlog_format = ROW
sync_binlog = 1
binlog_cache_size = 1M
# 复制
slave_parallel_workers = 8
slave_parallel_type = LOGICAL_CLOCK
28 RadonDB 的故障排查流程是什么?
答案:
RadonDB 故障排查遵循分层定位原则,从顶层集群状态到底层日志逐级排查。
排查层级与工具:
| 层级 | 检查内容 | 命令 |
|---|---|---|
| 集群层 | CRD Status、Pod 状态、事件 | kubectl describe mysqlcluster / kubectl get events |
| Pod 层 | 容器状态、探活、资源 | kubectl describe pod / kubectl top pod |
| Xenon 层 | Raft 状态、集群成员、Leader 身份 | xenoncli cluster raft / xenoncli mysql status |
| MySQL 层 | 连接、复制、锁、慢查询 | SHOW PROCESSLIST / SHOW SLAVE STATUS / SHOW ENGINE INNODB STATUS |
| 系统层 | CPU / Memory / Disk IO / 网络 | top / iostat / ping / dstat |
常见故障排查:
场景 1:集群 Pod 不 Ready
排查步骤:
1. kubectl describe pod my-cluster-0 → 查看 Events
2. kubectl logs my-cluster-0 -c init → Init Container 日志
3. kubectl logs my-cluster-0 -c mysql → MySQL 启动日志
4. kubectl logs my-cluster-0 -c xenon → Xenon 启动日志
常见原因:
- Init Container 数据目录校验失败 → PVC 损坏或目录为空
- MySQL 挂载卷权限问题 → fsGroup / runAsUser 未正确设置
- Xenon 无法连接 MySQL → /var/run/mysqld/mysqld.sock 不存在
- 磁盘空间不足 → PV 配额耗尽
场景 2:主从复制中断
-- 第 1 步:检查从库复制状态
SHOW SLAVE STATUS\G
-- 关键字段:
-- Slave_IO_Running / Slave_SQL_Running: 应为 Yes
-- Seconds_Behind_Master: 延迟秒数
-- Last_IO_Error / Last_SQL_Error: 错误信息
-- 常见错误及修复:
-- Error 1236 (binlog 被清理 / GTID 不一致)
STOP SLAVE;
RESET SLAVE;
CHANGE MASTER TO ...;
START SLAVE;
-- Error 1062 (主键冲突 / 重复数据)
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
-- Error 1032 (记录不存在 / DELETE/UPDATE 时找不到行)
STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE;
场景 3:Raft 集群分裂
# 查看 Raft 状态
kubectl exec -it my-cluster-0 -c xenon -- xenoncli cluster raft
# 手动重建 Raft 集群
kubectl exec -it my-cluster-0 -c xenon -- xenoncli cluster add --address my-cluster-1:8801
kubectl exec -it my-cluster-0 -c xenon -- xenoncli cluster add --address my-cluster-2:8801
# Xenon 日志排查
kubectl logs my-cluster-0 -c xenon | grep -E "raft|leader|election|timeout"
场景 4:备份失败
# 查看 Backup Job 状态
kubectl get mysqlbackup
kubectl describe mysqlbackup my-cluster-backup-xxx
# 查看 Job Pod 日志
kubectl logs job/my-cluster-backup-xxx
# 常见原因:
# - S3/MinIO 认证失败 → Secret 中的 AK/SK 错误
# - 磁盘空间不足 → 备份路径空间不足
# - MySQL 连接失败 → Xenon 未处于正常状态
# - 备份进程超时 → 数据集过大,xtrabackup 超时
场景 5:性能下降
-- 查看当前活跃查询
SHOW FULL PROCESSLIST;
-- 查看 InnoDB 引擎状态(锁争用 / 事务状态)
SHOW ENGINE INNODB STATUS\G
-- 查看当前锁等待
SELECT * FROM information_schema.innodb_lock_waits;
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'mydb';
-- 查看慢查询
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 20;
-- 查看表统计信息
SELECT TABLE_NAME, TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'mydb';
29 RadonDB 的 CLI 工具(radondb-mysql-operator 命令行)如何使用?
答案:
RadonDB Operator 提供 radondb-mysql-operator 命令行工具和 kubectl 插件,用于集群管理、状态查看和运维操作。
核心 CLI 命令:
# 查看 Operator 版本
radondb-mysql-operator version
# 查看集群列表
kubectl get mysqlcluster
# 查看集群详细状态
kubectl describe mysqlcluster my-cluster
# 创建集群
kubectl apply -f mysql-cluster.yaml
# 手动触发备份
kubectl apply -f - <<EOF
apiVersion: mysql.radondb.com/v1beta1
kind: MysqlBackup
metadata:
name: my-cluster-manual-backup-$(date +%Y%m%d%H%M%S)
spec:
clusterName: my-cluster
type: full
EOF
# 从备份恢复
kubectl apply -f mysql-restore.yaml
# 查看备份列表
kubectl get mysqlbackup
# 删除集群(保留 PVC)
kubectl delete mysqlcluster my-cluster
Xenon CLI(xenoncli):
# 进入 Xenon 容器
kubectl exec -it my-cluster-0 -c xenon -- /bin/bash
# 查看 Raft 集群状态
xenoncli cluster raft
# 查看 Raft 成员
xenoncli cluster members
# 查看当前节点 MySQL 状态(角色、复制、GTID)
xenoncli mysql status
# 查看当前节点为 Leader 还是 Follower
xenoncli mysql role
# 手动触发 Leader 转移
xenoncli raft transfer
# 查看 Xenon 日志级别
xenoncli log level
MySQL 运维命令:
# 通过 kubectl 直接进入 MySQL
kubectl exec -it my-cluster-0 -- mysql -uroot -p"${MYSQL_ROOT_PASSWORD}"
# 查看主从复制状态
kubectl exec -it my-cluster-1 -- mysql -e "SHOW SLAVE STATUS\G"
# 查看当前 Leader
kubectl get pods -l app=mysql,cluster=my-cluster,role=leader
# 查看所有可用的只读副本
kubectl get pods -l app=mysql,cluster=my-cluster,role=follower
# 临时重启 Xenon(不影响 MySQL)
kubectl exec -it my-cluster-0 -c xenon -- kill -HUP 1
Operator 日志查看:
# 查看 Operator 日志
kubectl logs -f deployment/radondb-mysql-operator -n radondb-system
# 按关键字过滤
kubectl logs deployment/radondb-mysql-operator -n radondb-system | grep -i "reconcile\|error\|leader"
30 RadonDB 生产环境最佳实践有哪些?
答案:
RadonDB 生产环境部署需覆盖部署架构、资源规划、安全加固、备份策略、监控告警、升级运维六大领域。
部署架构
| 实践 | 说明 |
|---|---|
| 最少 3 副本 | 满足 Raft Quorum(多数派投票 + 半同步 ACK) |
| 跨可用区部署 | 抵御单 AZ 故障,拓扑 Key 使用 topology.kubernetes.io/zone |
| PodAntiAffinity 强制分散 | 避免多个副本落在同一 Node |
| 单独命名空间 | 如 radondb-prod,区分环境 |
| Operator 高可用 | Operator Deployment replicas >= 2,避免 Operator 单点 |
资源规划
| 资源 | 推荐值 | 说明 |
|---|---|---|
| 内存 Request = Limit | 如 16Gi = 16Gi | QoS 为 Guaranteed,避免 OOM 驱逐 |
| CPU Request < Limit | Request 4核 / Limit 8核 | 允许 Burst,收益可控 |
innodb_buffer_pool_size | 内存 Limit × 60-70% | 避免 OOM |
| PV 大小 | 磁盘 × 1.5-2 倍预估 | 预留增长空间 |
| PV StorageClass | allowVolumeExpansion: true | 支持在线扩容 |
| 资源隔离 | 使用不同 Node Pool | 数据库与其他负载避免混部 |
安全加固
- TLS 加密传输:
require_secure_transport=ON - 密码策略:启用
validate_password插件,最小长度 12 位 - 废弃匿名用户和 test 数据库
- 网络隔离:NetworkPolicy 仅允许业务 Pod CIDR 访问 3306 端口
- Secret 管理:密码存储于 Kubernetes Secret,不在 CRD Spec 中明文
- 定期审计:至少每季度执行安全基线扫描
- RBAC:Operator 使用最小权限 ServiceAccount
备份策略
| 数据等级 | 备份策略 | 保留期 | 异地副本 |
|---|---|---|---|
| P0(核心) | 每日全量 + 每 6 小时增量 | 30 天 | 有(跨 Region S3 复制) |
| P1(重要) | 每日全量 + 每日增量 | 14 天 | 有 |
| P2(一般) | 每日全量 | 7 天 | 无 |
| P3(非关键) | 每周全量 | 4 周 | 无 |
- 备份验证:每月至少一次恢复演练,验证备份可用性和恢复时间
- 备份加密:S3 端开启 SSE(Server-Side Encryption)
- 备份监控:备份作业失败告警,延迟超过窗口告警
监控告警
| 告警 | 阈值 | 通知级别 |
|---|---|---|
| MySQL 不可用 | mysql_up == 0 for 1min | Critical,立即处理 |
| 复制中断 | Slave_IO/SQL_Running == No for 1min | Critical,立即处理 |
| 复制延迟 | Seconds_Behind_Master > 30s for 5min | Warning,15min 内处理 |
| 磁盘使用 | 使用率 > 80% | Warning,4h 内处理 |
| 连接使用率 | Threads_connected / max_connections > 80% for 5min | Warning,30min 内处理 |
| 缓冲池命中率 | Hit Rate < 95% for 10min | Info,工作时间处理 |
| 慢查询 | Slow_queries > 10/s for 10min | Info,工作时间处理 |
升级运维
- 升级窗口:选择业务低峰期(如每周四凌晨 2:00-4:00)
- 升级验证:先在 staging 环境验证整个升级流程,确认无误后操作生产
- 灰度策略:先升级一个 Follower,观察复制延迟和业务性能,确认正常后逐级升级
- 回滚方案:保留旧版本镜像和备份,确认回滚路径可行
- PDB 配置:
minAvailable: ceil(replicas/2)+1,确保滚动升级期间 Raft 多数派存活 - 变更管理:每次变更记录 CRD 变更前后的 YAML 快照
容量管理
| 指标 | 检查频率 | 扩容触发条件 |
|---|---|---|
| 磁盘使用率 | 每周 | 连续 2 周超过 70% |
| CPU 使用率 | 每周 | 连续 2 周峰值超过 70% |
| 内存使用率 | 每周 | 连续 2 周超过 80% |
| 连接数 | 每周 | 连续 2 周峰值超过 70% |
附录:快速检查清单
# 集群健康检查
kubectl get mysqlcluster # CRD 状态 Ready
kubectl get pods -l cluster=my-cluster # 所有 Pod Running
kubectl exec -it my-cluster-0 -c xenon -- xenoncli cluster raft # Raft 正常
kubectl exec -it my-cluster-1 -- mysql -e "SHOW SLAVE STATUS\G" # 复制正常
# 备份检查
kubectl get mysqlbackup # 最近备份 Completed
# 验证备份文件存在于 S3/MinIO
# 资源检查
kubectl top pods # CPU/Memory 未达上限
kubectl get pvc # PV 空间充足