Forráskód Böngészése

docs(kb): ADR-15 动态分区写入加 DISTRIBUTE BY dt;kb/90 待办 2 改指存量压实

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tianyu.chu 3 hete
szülő
commit
b157c0a5da
2 módosított fájl, 34 hozzáadás és 2 törlés
  1. 2 2
      kb/90-演进路线.md
  2. 32 0
      kb/93-架构决策.md

+ 2 - 2
kb/90-演进路线.md

@@ -28,9 +28,9 @@
 | # | 待办 | 落点 | 参见 |
 |---|------|------|------|
 | 1 | `publish.sh` 部署路径与项目名更新(发布目录 `/home/bigdata/release/poyee-data-warehouse/`) | `bin/publish.sh`(如重建) | — |
-| 2 | Hive 小文件合并工具重新实现(`alter table ... concatenate` 压实,连接 / 表过滤参数化,剥业务命名) | `dw_base/ops/` | §一 |
+| 2 | 存量小文件压实工具(`ods`/`dwd`/`dws` ~70 万文件一次性压实;现有 `dw_base/utils/hdfs_merge_small_file.py` 不支持外部表 + 逐分区起 job,需重写;顺带清其中硬编码的旧项目 metastore 口令) | `dw_base/ops/` | §一 · `93` ADR-15 |
 | 3 | 分区保留工具重新实现(元表驱动 + 保留天数参数化 + 例外 dt 白名单) | `dw_base/ops/` | §一 |
 | 4 | 数据质量首批 + runner(schema drift 探查 + PG/Hive 行数比对) | `dw_base/dq/` + `bin/dq-runner.py` | `93` ADR-07(表数 ≥ 5 张启动) |
 | 5 | TAPD API 集成 + Claude Code hook 同步操作(hook 主动同步,非 commit→任务 ID 联动;细节待展开) | `dw_base/pm/` + hook | — |
 | 6 | DWS 上线前回算窗对齐 DWD 滚动 N=30(`jobs/dws` 现 N=2,未上线;上线前改滚动 30 与 DWD 同口径) | `jobs/dws/` | `25-dws建模` §1.4 · ADR-09 |
-| 7 | 小表小文件分治实施(类 1 raw+ods 全量快照 + 月末/2099 生命周期;类 2 raw TTL 保留窗);类 1 表名 `_inc_d`→`_ful_d` | `jobs/raw`·`jobs/ods` + `dw_base/ops/` | `93` ADR-14(复用待办 2 / 3) |
+| 7 | 动态分区写入加 `DISTRIBUTE BY dt`(`ods`/`dwd`/`dws` 约 12 个 SQL);执行顺序 改 SQL → 补数 → 压实(待办 2) | `jobs/ods`·`jobs/dwd`·`jobs/dws` | `93` ADR-15 |

+ 32 - 0
kb/93-架构决策.md

@@ -621,3 +621,35 @@
   - 真实小文件在 `ods` + `dwd`(合计占全仓文件数 92.8%)。病因不是本 ADR 认定的「raw 分区数无限增长」,而是**动态分区写入的每分区文件数**(见 ADR-15)。
   - 本 ADR §候选方案里「分区内 `concatenate` 压实——每分区已 1 文件,无可合」这条否决,对 `raw` 成立、对 `ods`/`dwd` 不成立:后者每分区躺着几十上百个 KB 级文件,正是压实的适应症。
   - 类 1 四表(panini ×2 / prd_checklist / tzy_merchant)全部零下游,止于 ods;其全量快照改造与小文件无关,若要做只应出于建模语义,不在本轮。类 2 的 raw TTL 唯一驱动力是小文件,前提消失,一并作废。
+
+### ADR-15 动态分区写入加 `DISTRIBUTE BY dt`
+
+- **状态**:草案
+
+- **背景**:`ods` / `dwd` / `dws` 三库合计 ~70 万文件、均值 4KB~143KB(实测数据见 ADR-14 §实测证伪)。查证两处成因:
+  - `conf/spark-tuning.conf` 全局 `spark.sql.shuffle.partitions 200`
+  - 全仓库 `DISTRIBUTE BY` 仅出现一次(`jobs/ods/usr/ods_usr_traces_apd_d.sql`)
+
+  动态分区写入 + 200 reducer + 无 `DISTRIBUTE BY` → 每个 dt 分区被最多 200 个 task 各写一个文件。对照组坐实该归因:写**静态**分区的 `tdm`(1,467 文件)/ `dim`(715 文件)文件数正常,写**动态**分区的 `ods` / `dwd` / `dws` 全部爆炸,无例外。
+
+  `dwd` 的 31 万文件主要来自历史 backfill(~1800 个 dt 分区 × ~200 文件),非日调度累积——日调度滚动 N=30 是 `INSERT OVERWRITE`,只重写不累积。
+
+- **决策**:所有 `INSERT OVERWRITE ... PARTITION (dt)` 动态分区写入,SQL 末尾加 `DISTRIBUTE BY dt`;单分区体量大的表(埋点 traces 等)按体量加随机分桶 `DISTRIBUTE BY dt, CAST(RAND() * N AS INT)`,N 按 128MB/文件 估。
+
+  建模、分区语义、ADR-03 的 dt 归位逻辑**一律不动**——小文件是物理写入布局问题,与逻辑数据组织正交。
+
+  存量 ~70 万文件需一次性压实,工具见 `90-演进路线` 待办 2。**执行顺序:改 SQL → 补数 → 压实**,三步不可换序(不先改 SQL,补数会再造小文件;不先补数,压实要做两遍)。
+
+- **后果**:
+  - 正面:每分区文件数从 ≤200 降到 1(或按体量分桶数);写入端根治,存量压实只需做一次
+  - 负面:`DISTRIBUTE BY dt` 引入一次 shuffle,且单 reducer 写单分区,大分区写入变慢——需按体量给随机分桶,多一个需要人工判断的参数
+
+- **候选方案**:
+  - 调小全局 `spark.sql.shuffle.partitions`:伤所有 job 的计算并行度(shuffle 并行度不该为写入布局让路)——否决
+  - 只做存量压实、不改写入端:每次补数 / 日调度重新长回来——否决
+  - 动态分区改静态分区绕开:废掉 ADR-03 的 `update_time` 动态归位底座——否决
+  - 依赖 AQE 自动合并:Spark 2.4 的 `spark.sql.adaptive.enabled` 不含 `coalescePartitions`(Spark 3.0 引入)——当前环境不可用
+
+- **反悔条件**:
+  - 迁 Iceberg / Hudi(原生小文件合并)
+  - Spark 升 3.x,AQE `coalescePartitions` 可自动合并 shuffle 分区,`DISTRIBUTE BY` 可能不再必要