图 1:本文封面,主题为受限单点 API 的全量采集入仓。
先说场景。面试里遇到这样一道题:一批观测站点的数据要收进数仓,但数据方只给了一个查询 API,一次只能查一个站点的数据。问:怎么方便快速地把所有站点的数据拿全、落进 Hive?本文是历史题目复盘,题目来自本地历史面试资料(见文末来源说明),与任何公司当前招聘无关。
题意拆开看,约束只有两条
一是「单点查询」:没有批量接口,总量 = 站点数 × 天数(或别的参数维度),请求次数是参数空间的笛卡尔积,小不了。二是「对方是别人的服务」:调用必然有限速和偶发失败,不能由着自己猛打。整条解题思路就是在这两条约束下,把「快」和「稳」同时做出来。
第一步:把参数空间切成任务清单
先枚举出所有「站点 × 日期」的组合,生成一份任务清单。这一步看起来平凡,价值很大:任务清单是可持久化、可核对、可断点续传的——跑挂了重启,对照清单勾掉已完成的,接着跑剩下的,不用从头再来。
第二步:并发 worker 池,但戴着令牌桶
图 2:受限单点 API 的并发采集与入仓管道。
单线程顺序调一万次 API,时间全耗在等待上;开固定大小的 worker 池,共享一个任务游标,谁空闲谁取下一个任务,吞吐立刻翻几倍。但并发数不是越大越好:上游接口有调用频率限制,超了就是限流报错甚至封禁。标准做法是在 worker 池前面加一个令牌桶限速器——桶按固定速率发令牌,拿到令牌才能发请求,把总速率牢牢压在对方限额以内。并发提吞吐,限速保安全,两个机制各管一段。
第三步:失败重试要懂退避
网络抖动、对方限流都会造成偶发失败。直接立刻重试,等于在对方最忙的时候继续加压。指数退避是标准答案:第一次失败等 20 毫秒,第二次等 40,再失败等 80,逐次翻倍,并设最大尝试次数,超了就把任务记入失败清单报警,由人介入。偶发失败被退避吸收,持续故障被暴露出来,两种性质的问题分开处理。
第四步:攒批、按分区落 Hive
采集到的记录先落本地缓冲,攒成小批次再写入数仓,避免每来一条就写一次产生海量小文件。入仓按日期或站点分区。Hive 官方文档对 LOAD DATA 的说明很明确:加载是把数据文件复制或移动到表(或指定分区)对应位置的纯搬运操作,加载时不做转换——所以采集侧要把格式整理好,写入时指定 PARTITION。配合 INSERT OVERWRITE PARTITION 可以实现按分区覆盖重跑:同一天的数据重采后直接覆盖旧分区,结果和重跑前一致,这就是幂等写入。
两条红线收个尾
一是并发上限永远不超过 API 的限速配额,否则越急越慢。二是全流程可重跑:任务清单记录进度,落仓按分区幂等覆盖,任意环节中断都能续上。这两条答出来,题目才算真正闭环。
面试官可能顺着追问什么
追问一:限速值从哪来?答案是不能拍脑袋——看对方文档,没有文档就从小并发起步逐步加压探测,摸到限流阈值后留出余量。追问二:中途挂了怎么办?任务清单持久化到数据库或本地文件,每条任务带状态字段,重启后跳过已完成项,这就是断点续传。追问三:重试太多次仍然失败的记录去哪了?进死信清单,告警后人工兜底,绝不能让少数失败任务卡住整体进度,也不能悄悄丢掉。追问四:采集和入仓怎么保证一致?先写暂存区,校验条数与唯一键之后再装载正式表,避免半截数据直接对查询可见。
AI 工程关联
这道题几乎是 AI 数据管道的最小模型:训练数据采集同样面对受限 API、并发限速、失败重试、落仓管理。把「参数空间切分 + 令牌桶 + 退避重试 + 幂等落仓」四件套讲顺,再带上断点续传和死信兜底两个追问点,就覆盖了数据工程面试里采集类问题的八成考点。
如果对方 API 的限速规则是「每分钟 100 次」而不是平滑限速,你的令牌桶参数会怎么配?欢迎讨论。
参考资料
- Hive LanguageManual DML(Apache 官方文档:LOAD DATA 是把数据文件复制/移动到表或指定分区位置的纯搬运操作、加载时不做转换;INSERT OVERWRITE PARTITION 可按分区覆盖写入) — https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML