From 68a6836e5ad89304967bb1a52007560309f77867 Mon Sep 17 00:00:00 2001 From: Wei Cao Date: Tue, 19 May 2026 23:50:51 +0800 Subject: [PATCH] docs(cases/mariadb): add semisync persist alpha.83 to alpha.88 evolution case --- docs/SKILL-INDEX.md | 2 +- ...rsist-alpha83-to-alpha88-evolution-case.md | 116 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 docs/cases/mariadb/mariadb-semisync-persist-alpha83-to-alpha88-evolution-case.md diff --git a/docs/SKILL-INDEX.md b/docs/SKILL-INDEX.md index 87aee16..a01f68e 100644 --- a/docs/SKILL-INDEX.md +++ b/docs/SKILL-INDEX.md @@ -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 案例 diff --git a/docs/cases/mariadb/mariadb-semisync-persist-alpha83-to-alpha88-evolution-case.md b/docs/cases/mariadb/mariadb-semisync-persist-alpha83-to-alpha88-evolution-case.md new file mode 100644 index 0000000..08e3292 --- /dev/null +++ b/docs/cases/mariadb/mariadb-semisync-persist-alpha83-to-alpha88-evolution-case.md @@ -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/.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 受限两条独立约束共同放大调试成本。