Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/SKILL-INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

引擎特定的现场材料按引擎分组,每个引擎一个子目录:

- [`cases/mariadb/`](cases/mariadb/) — 16 个 mariadb addon 案例
- [`cases/mariadb/`](cases/mariadb/) — 17 个 mariadb addon 案例
- [`cases/valkey/`](cases/valkey/) — 2 个 valkey 案例
- [`cases/oracle/`](cases/oracle/) — 7 个 oracle 案例
- [`cases/oceanbase/`](cases/oceanbase/) — 3 个 oceanbase 案例
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# MariaDB semisync 持久化修法演进案例 — alpha.83 false-success → alpha.88 完整闭环

> **Audience**: 任何想理解"reconfigure 持久化修法在 KB chart immutability 约束下如何分多个 alpha 版本收口"的 addon dev / test
> **Status**: case study (历史现场材料)
> **Applies to**: MariaDB addon semisync topology;可推广到任何"reconfigure 仅 runtime-apply + 引擎进程重启可能丢值"的 addon
> **Applies to KB version**: KB 1.2.0-alpha.1 系列
> **Affected by version skew**: no — 修法本身是 addon chart 内部演进,跟 KB 版本独立

通用方法论见 [`../../troubleshoot/addon-reconfigure-set-global-persist-race-guide.md`](../../troubleshoot/addon-reconfigure-set-global-persist-race-guide.md);本案例只记录 MariaDB semisync 这条线**4 个 alpha 版本如何逐步收口**的演进过程。

## 先用白话理解这条案例

修一个看似简单的 bug,最后花了 4 个 alpha 版本(alpha.83 → .84 → .85 → .86/.87 → .88),不是因为 root cause 难找,是因为:

1. KB **CmpD immutability 规则**:cmpd YAML 内容一变就要 bump chart 版本;否则 CmpD 进 `Unavailable: immutable fields can't be updated`
2. **每次新版本 dry run 都揭出下一层 bug**:persistence 方案换了 3 种,每种都被新的 corner case 否定
3. **`set -e` + `var=$(failing_cmd)` 静默退出**:debug 时反复"跑到一半就退出,没 log",最后才发现是 shell mode 问题

这条案例的价值是:给其他 addon team 看"为什么持久化修法会变成 4 个版本",避免重蹈"以为一两个 commit 就能解,结果套娃"的陷阱。

## 时间线

### alpha.83 — 暴露问题

- **现场**:T6 reconfigure OpsRequest `phase=Succeed`,但 pod1 `SHOW GLOBAL VARIABLES slow_query_log` 返回 OFF(chart 默认值),不是 ON(user 期望值)
- **直接证据**:
- K8s container `restartCount=0`,看似 "engine 没重启"
- mariadbd 进程 PID 在 reconfigure 窗口里**变化**(kbagent / supervisor 拉起的新进程)
- mariadb error log 有 `Normal shutdown` 序列
- **诊断**:reconfigureAction 跑 `SET GLOBAL slow_query_log=ON` 成功;switchover/promote 路径让 mariadbd 进程重启;ConfigMap 挂载的 my.cnf 在重启时**还没同步**到新值;mariadbd 启动读旧 my.cnf → 加载 chart 默认 OFF
- 详细 trap 类型见 `mariadb-reconfigure-set-global-without-persist-race-case.md`
- **alpha.83 现场结论**:要持久化层

### alpha.84 — 第一次持久化尝试(`!includedir` + ConfigMap 同步)

- **设计**:chart-rendered ConfigMap 的 my.cnf 末尾加 `!includedir /var/lib/mysql/runtime-overrides.d/`;init container 创建空目录;reconfigureAction 在 SET GLOBAL 成功后**也** 把新值写到 `/var/lib/mysql/runtime-overrides.d/<param>.cnf`
- **dry run 结果**:FAIL
- **新 bug**:KB ParametersDefinition 校验时把 `!includedir` 当成无效的 ini key,拒绝了整个 ConfigMap merge
- **教训**:KB 的 ini parser 严格;任何非标准 ini directive(包括 `!includedir`)都不能让 PD merge 经过
- **alpha.84 → alpha.85 触发**:CmpD immutability — cmpd YAML 改了,必须 bump chart 版本

### alpha.85 — 第二次持久化尝试(chart 自定义 ConfigMap mount)

- **设计**:放弃 my.cnf 的 `!includedir`;在 chart values 加 `image.syncer.tag` pin(顺手解决 syncer image skew);reconfigureAction 改成直接写 `/var/lib/mysql/conf.d/runtime-overrides.cnf`,依赖 mariadbd 默认会 scan `conf.d/`
- **dry run 结果**:FAIL on first restart
- **新 bug**:mariadbd 启动**不**自动 scan `/var/lib/mysql/conf.d/`;那是 my.cnf 配置过 `!includedir` 才会的行为;而 alpha.84 已经把 `!includedir` 撤了 — 自相矛盾
- **教训**:mariadbd 启动配置加载路径是 my.cnf 引导的;要外部目录被读必须有"启动时显式被读"的机制
- **alpha.85 → alpha.86 触发**:又一次 CmpD immutability,再 bump

### alpha.86/.87 — 第三次持久化尝试(`mariadbd --defaults-extra-file`)

- **设计**:cmpd-semisync.yaml 的 mariadbd 启动 command 加 `--defaults-extra-file=/var/lib/mysql/runtime-overrides.cnf`;reconfigureAction 写 per-param 文件到 `/var/lib/mysql/runtime-overrides.d/`,loader 文件用 `!includedir` 指 dir;mariadbd 启动 `--defaults-extra-file` 读 loader 文件,loader 文件**不**经过 KB 的 INI parser(因为它在 PVC 上,不在 ConfigMap 里),所以 `!includedir` 合法
- **alpha.86 dry run 结果**:FAIL 在 reconfigureAction 的 parse smoke 步骤
- **新 bug**:reconfigureAction 在写 per-param 文件后跑 `mariadbd --help -- --defaults-extra-file=...` 验证 loader 文件语法 OK;但 kbagent 的 runtime PATH **不含** mariadbd(kbagent 镜像只有 mariadb client,不含 server);shell 报 `mariadbd: command not found`;`set -e` + `var=$(failing_cmd)` 静默退出整个 action,**没有任何 stderr**
- **debug**:花了 30 分钟才定位到是 PATH + set-e 组合的 silent exit;用 `command -v mariadbd` 检查证明 binary 不存在
- **alpha.86 → alpha.87 触发**:又一次 CmpD immutability
- **alpha.87 dry run 结果**:parse smoke 仍 FAIL
- **新 bug 同源**:尝试改 parse smoke 用 `command -v mariadbd && ... || true` 兜底,但 kbagent runtime 环境的 PATH 跟 ssh 调试时不同;ssh 看到 mariadbd 是因为 mariadb container 里有,kbagent action 不一定在 mariadb container 里运行
- **教训**:addon action 不要假设 PATH 跟 ssh 进容器一致;要么显式 `command -v` 兜底,要么干脆放弃这一步

### alpha.88 — 完整闭环

- **设计**(drop parse smoke):
- 保留 `mariadbd --defaults-extra-file=/var/lib/mysql/runtime-overrides.cnf` 启动参数
- 保留 loader 文件 `!includedir` + per-param 文件
- **删掉** reconfigureAction 里的 parse smoke 步骤 — 反正即使过了也不能在 kbagent runtime PATH 里跑;mariadbd 启动失败 KB controller 会重试,没有静默 fail 风险
- 保留所有注入防御(temp + atomic rename / WARN-only 失败模式 / per-param 独立文件)
- **alpha.88 dry run 结果**:PASS
- **N=3 scoped verify**:3 个 fresh cluster 在 alpha.88 chart + KB controller PR #10252 patch 组合下都通过 T6 reconfigure + forced mariadbd restart + cleanup
- **闭环条件**:所有 4 层防御都生效:
1. semisync PD 补齐让 KB Configure controller 走 dynamic 路径,不必要的 rolling restart 被消除
2. reconfigureAction `SET GLOBAL` 仍即时生效
3. reconfigureAction 写持久化 per-param 文件,atomic + WARN-only
4. mariadbd 启动 `--defaults-extra-file` 读 loader → `!includedir` → 加载所有 override 文件

## 跨 4 个版本的关键教训

| # | 教训 | 解释 |
|---|---|---|
| 1 | KB CmpD immutability 强制 chart 版本 bump | 任何 cmpd YAML 内容变都要 bump alpha;持久化修法在 cmpd 上动了 4 次 → 4 个 alpha |
| 2 | KB INI parser 严格拒绝非标准 directive | `!includedir` 不能放在 ConfigMap 里的 my.cnf;必须放在 PVC 上的 loader 文件,被 `--defaults-extra-file` 引导而不是被 KB parser 看到 |
| 3 | mariadbd 启动读 conf.d/ 是 my.cnf 配置过 `!includedir` 才发生的 | 不是自动行为;放弃 `!includedir` 就要换 `--defaults-extra-file` 机制 |
| 4 | kbagent runtime PATH 不含 mariadbd(只有 client)| addon action 不能假设有 server binary;validate / parse smoke 这类要小心 |
| 5 | `set -e` + `var=$(failing_cmd)` silent exit | 见 misjudgment checklist 第 2 条;这次浪费了 30min debug |
| 6 | parse smoke 在 runtime PATH 不对的环境里只能去掉 | KB controller 重试机制 + mariadbd 启动失败 log 已经足够 fail-visible,parse smoke 是 redundant gate |

## 现场证据归档

| 阶段 | evidence sha | scope |
|---|---|---|
| alpha.83 false-success root cause | `9502a88ff4a89c17af87649f83c9662bab1b51a699c77e3541a3dd53115fec67` | OpsRequest Succeed + pod1 SQL OFF |
| alpha.85 PD-only fix | `fd99720bdabce115a5aa1ba64913d9a576dca2d7bbbb51e7623ee1cebff50f1e` | PD 补齐 + controller log 显示走 dynamic path |
| alpha.88 N=1 scoped PASS | `03a2ecdcf3c84... (test4)` | 完整 4 层防御都生效 |
| alpha.88 N=3 scoped PASS(多 fresh cluster) | `50d99cd66... (test4 n2b)` + `b9cfc33786ce... (test5 n3b)` | 3 fresh clusters;含 KB controller PR #10252 patch image |

## 推广到其他 addon

如果你的 addon 也要做"reconfigureAction + 持久化"的修法,先扫这个清单避坑:

1. **不要在 chart-rendered ConfigMap 的 my.cnf 里写 `!includedir`** — KB INI parser 拒绝
2. **要让 engine 启动读外部目录,必须有显式机制**:要么 my.cnf 里有合法的 include 语法(**且** KB parser 容忍),要么 engine 启动 args 加 `--defaults-extra-file=...` 之类
3. **reconfigureAction 不要 parse smoke 检查 server binary 是否在 PATH** — kbagent runtime 不一定有 server binary;engine 启动失败 KB controller 重试机制已足够 fail-visible
4. **持久化文件路径选 PVC,不要 ConfigMap-volume**:避开 kubelet sync 延迟 + 避开 KB INI parser
5. **per-param 独立文件 + atomic rename + WARN-only 失败模式**:reconfigure 多次不互相覆盖;写失败不让 action fail(runtime 已生效;持久化是 defense-in-depth)
6. **每次 cmpd 改动都 bump chart 版本**:CmpD immutability 是硬约束

## 相关文档

- 通用方法论:[`../../troubleshoot/addon-reconfigure-set-global-persist-race-guide.md`](../../troubleshoot/addon-reconfigure-set-global-persist-race-guide.md)
- 同 case 的 false-success 单点:[`mariadb-reconfigure-set-global-without-persist-race-case.md`](mariadb-reconfigure-set-global-without-persist-race-case.md)
- misjudgment 第 2 条:[`../../troubleshoot/addon-debug-misjudgment-checklist-guide.md`](../../troubleshoot/addon-debug-misjudgment-checklist-guide.md)(`set -e` + `var=$()` silent exit)
- syncer image pin(alpha.85 顺手解决):[`../../troubleshoot/addon-syncer-image-version-pin-guide.md`](../../troubleshoot/addon-syncer-image-version-pin-guide.md)

## 一句话总结

MariaDB semisync 持久化修法跨 4 个 alpha 版本(alpha.83 暴露 → .84 `!includedir` 拒绝 → .85 conf.d/ 不被读 → .86/.87 parse smoke silent fail → .88 drop parse smoke 收口)的真正难点不是 root cause,而是 KB CmpD immutability 把每次 cmpd 改动强制成新 alpha 版本,加上 KB INI parser 严格 + kbagent runtime PATH 受限两条独立约束共同放大调试成本。