题干与适用场景
每个视图查询源表或其他视图。源数据变化会使后代失效,但立即重算所有后代成本过高。系统应提供带版本的结果并暴露新鲜度,不能把不同代的父视图拼在一起。假设刷新可以异步执行,并保留全量重建作为恢复手段。
面试官考察点
- 建模依赖边、版本、失效和拓扑刷新顺序。
- 根据变化量和查询形态选择增量或全量重算。
- 处理陈旧结果、部分失败、回填、热点和缓存驱逐。
- 用血缘、清单、校验和与可重放事件证明正确性。
回答前需要澄清的问题
确认每个查询是否有新鲜度 SLO、连接是否能增量维护、更新和删除如何到达,以及读者是否宁愿接受陈旧答案而非错误。不可逆聚合发生变化时可能需要更大范围重算;只追加数据的视图更适合增量刷新。
30 秒回答框架
为每个视图保存带版本清单:依赖版本、输出位置、行数、校验和和新鲜度时间。源变化追加失效事件,调度器按拓扑顺序处理受影响后代;查询支持时使用增量刷新,否则全量重建。只有所有必需父视图匹配目标代后才原子发布新清单。读取选择完整代,策略允许时可使用有界陈旧代,并展示年龄。重放、校验和与定期全量重建用于修复偏差。
分步骤深入解答
1. 表示 DAG 和数据代
每个视图拥有稳定 ID、查询定义、父 ID 和 generation。刷新计划携带目标源水位,并记录使用的父代。如果刷新期间父视图变化,发布前拒绝该计划,使用新水位重试,不能静默混合结果。
2. 选择增量或全量刷新
以变化量、连接形态和聚合是否可逆作为判断规则。引擎能证明增量足够时只读取变化分区或行;复杂连接或删除场景使用全量刷新更简单。新清单验证前保留旧代,刷新失败不会移除最后一个正确答案。
3. 调度失效并控制热点视图
把多个源事件合并到一个目标水位,每代只处理一次受影响节点。按查询需求和新鲜度欠账排序,同时限制每个源的并发工作,避免热点上游耗尽计算资源。按视图参数和代缓存热门结果,以代号失效,而不是逐个删除所有键。
4. 恢复、回填并证明正确
持久化失效事件和刷新清单,让 Worker 崩溃后可以继续。回填使用独立目标代,只有与当前代比较后才发布。比较行数、校验和、抽样聚合与血缘水位;视图超过五分钟目标或父代不一致时告警。定期全量重建可作为检测增量漂移的基准。
高质量示范回答
我会先确认按视图的新鲜度、更新/删除行为和是否允许陈旧读取。每个视图清单包含父代、源水位、输出位置、校验和和新鲜度。失效事件进入调度器,合并工作并按拓扑刷新后代。可证明增量的查询使用增量刷新,复杂连接或删除使用全量重建,并原子发布新代。读取绝不混合代;允许时返回带年龄的有界陈旧代。重放、回填代、校验和与定期全量重建让正确性可测试。
常见错误
- 每次源变化立即刷新所有后代 → 突发时重复计算 → 按目标水位合并事件。
- 原地覆盖唯一结果 → 失败任务留下半成品 → 以不可变代原子发布。
- 假设所有聚合都可增量 → 删除或不可逆函数造成漂移 → 按查询形态决策并保留全量回退。
- 缓存没有代信息 → 父子答案可能不一致 → 缓存键绑定完整代。
- 热点视图耗尽所有 Worker → 其他新鲜度 SLO 失败 → 限制源级和视图级并发。
- 只相信行数 → 静默损坏长期存在 → 比较校验和、抽样、血缘水位和全量重建。
追问及应对
父视图刷新时子视图正在运行,怎么办?
子视图记录读取的父代。发布时若该代已不是当前代,就丢弃或按新目标水位重试,不能发布混合代。
一个原本增量的视图出现删除,还能增量刷新吗?
只有变更日志和查询语义保留足够信息来减去旧贡献时才可以。否则扩大受影响分区或安排全量重建,并说明新鲜度取舍。
如何防止回填覆盖更新数据?
为回填分配独立代和源水位。只有覆盖目标范围且不取代更新分区时才发布,并按明确范围和代规则合并清单。
视图查询远多于刷新,怎么办?
返回带年龄的最后完整代,按新鲜度欠账提高优先级,必要时预计算热门参数键。不能隐藏陈旧,也不能让读取绕过刷新并发限制。