Doris Stream Load 超时后,为什么不能立刻换 label 重试
某制造企业每天把设备产量文件导入 Doris。一次网络抖动后,调度器认为导入失败,生成新 label 重试,结果同一批数据出现两份。排查发现,第一次请求已经提交,只是客户端没有及时拿到结果。对于允许重复行的目标表,这种“补偿”本身就是重复数据的来源。
把三个成功条件拆开
本文依据 Doris 2.1 的 Stream Load 官方文档。需要分别观察网络请求是否完成、导入事务是否成功、数据是否已经可见。HTTP 请求完成不能代替业务状态判断;客户端连接超时也不能证明服务端事务失败。
响应中的 Status 有两个容易混淆的值:Success 表示导入成功;Publish Timeout 表示导入已完成,但可见性可能延迟,不能直接按照失败重新导入。Label Already Exists 则需要继续检查 ExistingJobStatus,其中 RUNNING 表示已有任务仍在执行,FINISHED 表示已有任务成功。
为同一份输入保留身份
我会在任务发起前持久化批次号、文件摘要、目标库表和 label。重试只能读取这条登记记录,不能在网络异常分支重新生成 label。若同一批次收到不同摘要,应该进入冲突处理,不能继续沿用旧 label 并把已有任务成功解释为新文件成功。
下面是一个只解析响应、不访问集群的可运行例子,保存为 load_status.py。它刻意不把任何“尚未确定”的分支归类为成功。
import json
import sys
def classify(result):
status = result.get("Status")
if status == "Success":
return "COMMITTED"
if status == "Publish Timeout":
return "WAIT_VISIBILITY"
if status == "Label Already Exists":
previous = result.get("ExistingJobStatus")
if previous == "FINISHED":
return "COMMITTED_EXISTING"
if previous == "RUNNING":
return "WAIT_EXISTING"
return "RECONCILE"
if status == "Fail":
return "FAILED"
return "RECONCILE"
if __name__ == "__main__":
result = json.load(sys.stdin)
print(classify(result))
printf '%s\n' '{"Status":"Publish Timeout"}' | python load_status.py
printf '%s\n' '{"Status":"Label Already Exists","ExistingJobStatus":"RUNNING"}' | python load_status.py
两次预期分别输出 WAIT_VISIBILITY 和 WAIT_EXISTING。这些是本文设计的调度状态名,不是 Doris 新增的返回字段。解析器只是状态机的一部分,不能独立提供端到端幂等。
让重试跟着状态走
请求没有拿到完整响应时,先记录“结果未知”,保存请求时间与稳定 label,再核对已有事务。使用相同 label 重发时,服务端可能返回重复标签信息;这正是恢复已有结果的线索,而不是要求立刻换一个随机标签。只有明确旧任务失败,并按对应版本的重试规则完成核对后,才进入下一次实际导入。
收到 Publish Timeout 后,把动作切换为可见性确认。可以按批次字段查询行数和校验指标,确认满足发布条件再放行下游。若迟迟不可见,应调查事务发布与集群健康状态;不断重灌会增加排查变量。
已有 label 成功也不意味着可以忽略输入身份。假如运维人员在同一批次目录重新生成了文件,老 label 对应的仍是原来的内容。这里必须比较登记的文件摘要,防止把“某次成功”误认成“当前文件成功”。
幂等窗口之外还要对账
官方文档说明标签有保留期限。因此 label 适合处理一定时间范围内的请求重试,不能独立承担永久去重。本文不依赖具体保留时长,而要求批次账本覆盖历史补数周期。再次导入很久以前的批次时,应先查业务批次记录和目标数据,再决定是补缺还是更正。
另外,成功响应中的加载行数、过滤行数和业务验收是不同层次。任务成功却过滤了关键记录,仍可能不符合发布条件。建议把原始响应完整归档,在账本中提取事务号、输入摘要和统计指标;日志里只暴露必要的脱敏标识。
用故障注入检查状态机
在隔离环境里分别模拟客户端断连、已有任务仍运行和数据暂不可见。每个用例都检查是否沿用了原 label、是否保留输入摘要、是否阻止下游过早读取。不要只测试服务端明确返回失败的路径,那通常是最容易处理的一种情况。
还应让同一批次同时启动两个执行实例,确认它们最终关联到同一条登记记录。若各实例在本地独立生成任务身份,即使单个实例内部重试正确,跨实例仍可能重复提交。恢复记录应由共享持久化存储承载,不能只放在进程内存里。
小结
Stream Load 超时后的核心问题是确认已有事务,而不是尽快产生新请求。稳定 label、输入摘要、状态分类与可见性验收共同组成恢复流程,才能避免把网络异常变成重复导入。
- 点赞
- 收藏
- 关注作者
评论(0)