题目重点:Onsite SD 以 as interactive as possible 为非功能需求,并追问 Flink/Kafka 对接与 Flink 故障恢复;区分查询延迟和数据新鲜度。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版为按维度和时间窗聚合事件并供低延迟仪表盘查询;真实业务指标与 freshness SLA 要先问。
- 事件源通过 Kafka 提供稳定 eventId 与 eventTime,Flink state checkpoint 写耐久存储,下游汇总写幂等/事务性 sink。
- 历史批量回填与流处理可能并存,但避免同一事件重复计算;准确性口径按事件时间和迟到水位说明。
解题路线
- 先区分两种延迟:用户改筛选条件的查询响应 p95 与新事件出现在看板上的新鲜度;据此决定预聚合粒度与可接受误差。
- 事件进 Kafka 后按 key 分区,Flink 解析校验、去重、按事件时间/窗口聚合并维护本地状态;checkpoint 记录算子状态和 Kafka offset 的一致快照。
- 写入查询存储时使用可幂等的 (metric,dimension,window,version) upsert 或原子 sink,避免恢复后重放导致双计;RocksDB 只是本地大状态后端,故障时仍要从远端 checkpoint 还原。
- 查询层对常见维度读预聚合,对高基数/长时间跨度做分层汇总或异步分析;批量作业用于历史重算和与流结果核对。
- 故障演练按最近 checkpoint 恢复状态和 offset、重放后续事件,观测滞后/重复/对账差额;报警覆盖 Kafka lag、checkpoint 失败、状态大小、迟到率和查询 p99。
手动走一遍
训练例:某分钟窗口已处理 e1/e2,Flink checkpoint 到 e2 后崩溃;恢复从该 checkpoint 还原聚合与 offset,后续 e3 重放一次。若 sink 在故障前写了 e3 但 checkpoint 未提交,重放会再写,故输出需以窗口键/版本幂等,不能只靠 RocksDB。
规模与取舍
摄取与聚合计算近随事件数线性,状态大小取活跃 key×窗口数;查询预聚合可把交互扫描缩到目标维度/时间桶数。题目无吞吐与 SLA,不能给固定节点数。
易错点与追问
容易失分的边界
- 说用 Flink 就保证毫秒交互查询。
- 只提 RocksDB 而没说 checkpoint 与 Kafka offset 对齐。
- 重放后 sink 非幂等导致重复聚合。
- 只做实时流、不处理历史回填与核对。
- 业务指标未定义就设计固定窗口。
继续深挖
- 迟到事件跨水位怎么办?
- 状态膨胀如何 TTL/分层?
- 批量回填与流处理如何避免双算?
- 查询维度很多时如何权衡预聚合数量?
