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
(CRD Watch / Reconcile Loop)"]
HeadlessSvc["Headless Service
(mysql-radondb-headless)"]
subgraph StatefulSet["StatefulSet Replicas (3)"]
Pod0["Pod-0: MySQL / Xenon / Exp
Leader"]
Pod1["Pod-1: MySQL / Xenon / Exp
Follower"]
Pod2["Pod-2: MySQL / Xenon / Exp
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 集合决定是否需要从其他节点补偿差异数据。
sequenceDiagram
participant L as Leader Xenon
participant F1 as Follower Xenon-1
participant F2 as Follower Xenon-2
L->>F1: Heartbeat
L->>F2: Heartbeat
Note over L: Leader 宕机 / 网络分区
Note over L: Tick 超时
Note over F1: Tick 超时
F1->>L: RequestVote
F1->>F2: RequestVote
F2-->>F1: VoteGranted
Note over F1: New Leader Elected
SET GLOBAL read_only=OFF
F2-->>F1: 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
(Sidecar)
: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["全量
Day 1(周日)"] --> I1["增量(1)
Day 2"]
I1 --> I2["增量(2)
Day 3"]
I2 --> I3["增量(3)
Day 4"]
I3 --> F2["全量
Day 5(周四)"]
F2 --> I4["增量(1)
Day 6"]
I4 --> I5["增量(2)
Day 7"]
I5 --> F3["全量
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"
```text
版本管理能力:
| 能力 | 说明 |
|------|------|
| 版本发现 | 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;'"
}
```text
可在线修改的动态参数:
- `max_connections`
- `innodb_buffer_pool_size`(MySQL 8.0+)
- `slow_query_log` / `long_query_time`
- `read_only`(由 Xenon 自动管理)
- `innodb_flush_log_at_trx_commit`
- `sync_binlog`
- `general_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"
```text
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
```text
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 {{ $labels.pod }} is down"
description: "MySQL on pod {{ $labels.pod }} 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 {{ $labels.pod }}"
- 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 {{ $value }}s on {{ $labels.pod }}"
# 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 {{ $value | humanize }}% on {{ $labels.pod }}"
# 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 {{ $labels.pod }}"
# 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 {{ $value }}/s on {{ $labels.pod }}"
# 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 {{ $value | humanize }}%"
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
```text
跨 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 配额耗尽
```text
**场景 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
```text
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 空间充足
```text