重构完成后沉淀的关键架构决策(ADR),给自己看的备忘。
90-重构路线.md / 91-重构备忘.md / 92-重构进度.md 三份过程文档会在重构收尾时删除,关键决策、权衡、反悔条件压到这里留档。新增一条决策时,复制以下模板到 §2 列表内。编号连续,不复用已弃用编号。
### ADR-NN 决策标题
- **状态**:已采纳 / 被 ADR-MM 取代 / 已弃用
- **背景**:当时面对的问题、约束、触发决策的场景。
- **决策**:最终选了什么方案,一句话。
- **后果**:带来的好处、新增的代价、影响到的模块。
- **候选方案**:考察过但否决的方案,以及否决理由。
- **反悔条件**:什么条件下会重新评估或反悔。
状态:草案
老 spark-sql-starter 的 get_date_range 支持 20260401-20260410 范围格式自动展开;DataX 入口从未用过。本项目调度用 DolphinScheduler,DS 原生支持业务日期补数(时间区间选定后,按调度周期逐日实例化 task)。用户老 DS 配置即 -start-date=${dt} -stop-date=${cdt} 单日传参。
决策:DataX 入口只接受单日语义(start_date / stop_date 对应一个 dt 分区);按天展开 / 批量补数 / 回溯全部交由 DS 工作流承担。
后果:
workspace/ 下临时 dispatcher候选方案:DataX 入口层实现"日期范围自动展开 + 多 json 分发多 worker"——否决,理由是重复 DS 职责 + 引入状态管理复杂度
反悔条件:项目从 DS 迁走到无补数功能的调度系统;或出现"必须在 DataX 层展开"的硬场景
状态:草案
DataX 老入口 single-job-starter.sh 内置 -random + workers.ini 权重加权随机选 worker + ssh 分发。DS 自身亦有 worker group 机制(group 绑定机器列表、task 落到 group 内一台 worker)。两层叠加:DS 选 node01 → node01 上 DataX 再 random 到 node03。【查证 kb/91 §4.4】:用户老 DS 配置不传 -random,说明 DS 层已完成分发,DataX 只在本机跑——两层分发在实际运营中就没被"同时启用"过
决策:DataX 入口不做 worker 分发;分布式执行在 task 粒度靠 DS worker group 承担。DataX 入口的 select_worker 等同"返回 current_host",ssh 分支可删,workers.ini 可移除
后果:
worker.py / ssh 远端执行 / workers.ini 可裁);维护成本下降-parallel)场景无法在 DataX 层散到多 worker,要分布式必须在 DS 层拆成多 task候选方案:保留 DataX 两层分发——否决,"两层独立随机"破坏 DS worker group 语义
反悔条件:DS 换成无 worker group 支持的调度器;或单 task 内批量规模大到 DS 拆分成本过高
update_time 过滤单日窗口 [day-start, day-stop) 同步时,源库在同步执行期间持续写入——跨零点的记录 update_time 会从 N 号"漂到" N+1 号,单日窗口无法捕获漂移记录。漂移概率和漂移数据量的相关变量:
业界一般做法:小数据量、用户低活跃度的场景下,通常凌晨 0:30 前后跑 T+1,漂移窗口 30 分钟、活跃度低,单日固定窗口 [day-start, day-stop) 即可,忽略极少量漂移数据是可接受的工程权衡。
本项目特殊性:业务高峰在凌晨 6 点前,同步定时必须避开高峰定在 6 点后,漂移窗口 6 小时;且若干用户行为集中在 0-6 点,漂移窗口和活跃度两个放大因子都踩中,漂移不能忽略——需要单独设计。
极端场景佐证:某用户习惯 0-6 点更新自己的数据,若走业界做法的单日固定窗口,数仓永远只能看到该用户最早的 create_time 版本,最新状态永远抓不到。
决策:
where update_time >= '{day-start} 00:00' AND update_time < '{day+1-stop} 00:00',在关闭侧加 1 天 buffer 覆盖漂移dt = stop-1 统一落当日分区PARTITION (dt),按每行 update_time 真实日期归位INSERT OVERWRITE(覆盖式) —— 每次 ods 跑覆盖对应 dt 分区。不丢数据:数据只会向后漂移一天(某条 update_time=N 号 的记录若 N 号 raw 没抓到漂到 N+1 号,N+1 号 raw 必然抓到——漂移不会再漂到 N+2 号),N+1 号 ods 覆盖 dt=N 号 时能补齐INSERT INTO 追加 + 单分区内 (pk, max(update_time)) 去重 —— 同 pk 在同 dt 分区内只保留最新 update_time 一条。保留"每日 ods 跑时刻的 dt=X 版本"轨迹(审计、回溯),防止覆盖后丢失"update 恰为当天"的中间快照后果:
候选方案:
[day-start, day-stop) 固定区间(无 buffer):业界小公司通用做法,本项目因漂移窗口 + 活跃度双放大否决now 右界 [day-start, now):可复现性、复跑、补数场景难处理,否决[day-start, day+6h-stop):和具体同步时刻耦合,调定时就得改窗口,否决(pk, max(update_time)) 去重:破坏拉链表基础,否决REPEATABLE READ snapshot isolation:业务库长事务风险,否决反悔条件:迁 CDC