深蓝黑背景的品牌封面:中央大标题「单点 API 受限,如何全量采集入 Hive」,副标题「并发控制 · 限速重试 · 批量落仓」,左上标注栏目「AI 工程面试题解专栏」,右上标注「面试 · Day 10」,背景为数据流点阵装饰与青紫光晕 图 1:本文封面,主题为受限单点 API 的全量采集入仓。

先说场景。面试里遇到这样一道题:一批观测站点的数据要收进数仓,但数据方只给了一个查询 API,一次只能查一个站点的数据。问:怎么方便快速地把所有站点的数据拿全、落进 Hive?本文是历史题目复盘,题目来自本地历史面试资料(见文末来源说明),与任何公司当前招聘无关。

题意拆开看,约束只有两条

一是「单点查询」:没有批量接口,总量 = 站点数 × 天数(或别的参数维度),请求次数是参数空间的笛卡尔积,小不了。二是「对方是别人的服务」:调用必然有限速和偶发失败,不能由着自己猛打。整条解题思路就是在这两条约束下,把「快」和「稳」同时做出来。

第一步:把参数空间切成任务清单

先枚举出所有「站点 × 日期」的组合,生成一份任务清单。这一步看起来平凡,价值很大:任务清单是可持久化、可核对、可断点续传的——跑挂了重启,对照清单勾掉已完成的,接着跑剩下的,不用从头再来。

第二步:并发 worker 池,但戴着令牌桶

管道架构图:左侧数据源只提供单点查询 API,按参数空间(站点 × 日期)切分成任务清单;中间并发 worker 池在令牌桶限速器约束下抓取,失败进入指数退避重试;右侧采集结果先落本地缓冲合并成小批次,再按分区批量写入 Hive;底部强调两个关键:并发数不得超过 API 限速、断点续传与幂等写入保证可重跑 图 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