遍历说明

遍历(Traverse / ListTraverse)用于全量扫描一张表的所有记录,常用于数据导出、迁移、对账、批量改造等场景。本文说明遍历的原理、限制、注意事项,以及"遍历开始后能否中途停止 / 续传"这一关键问题。

1. 遍历原理

遍历是 SDK 侧驱动的一个状态机 + 游标扫描过程,不是一次请求一次性返回全表。

1.1 整体流程

GetTraverser(zoneId, table)         // 取得遍历器,进入 ST_READY
        │
   Start()                          // 进入 ST_NORMAL,先拉取表的 shard 列表
        │
   ┌────▼─────────────────────────────────────┐
   │ 按 shard 逐个扫描:                        │
   │  对当前 shard 发遍历请求,带上 offset 游标  │
   │  tcapsvr 返回一批记录 + 新 offset + 完成标志 │
   │  当前 shard 扫完 → offset 归 0,切下一个 shard│
   └────┬─────────────────────────────────────┘
        │  所有 shard 扫完
   ST_IDLE → Stop()                 // 结束并释放遍历器
  • 基于 shard + offset 的游标:表被划分为多个 shard(路由范围 [0, 10000))。SDK 先发 GetShardListReq 拿到 shard 列表,再对每个 shard 携带 offset 反复请求,tcapsvr 每次返回一批记录并回带下一个 offset是否完成标志,直到该 shard 扫完,再切到下一个 shard。
  • SDK 收包驱动:发出请求后,业务必须持续驱动收包,SDK 内部会在收到一批后自动续发下一批请求。
  • 丢包检测与重发:SDK 通过应答 sequence检测丢包,游标只在按序正确收到一个包后才推进。一旦发现缺包(收到的序号大于期望值),该乱序包会被丢弃(不交付业务),并从上次已确认的 offset 重发后续请求(go-back-N),SDK自动处理丢包场景,对业务透明
  • 主备切换检测:遍历请求会带回处理它的 svrId,SDK 通过 CheckIfSwitchMS 校验,若中途发生主备切换会被感知(可能导致当前 shard 需要从头重扫)。

1.2 遍历不是快照

遍历读取的是 tcapsvr 当前数据按 shard+offset 推进的游标结果,不是某一时刻的一致性快照。遍历持续期间表数据的增、删、改可能导致:

  • 遍历开始后新写入的记录,可能被遍历到,也可能漏掉;
  • 遍历期间被删除的记录,可能已经读到、也可能读不到;
  • 极端情况下(如 offset 重排、主备切换重扫)存在少量重复或遗漏

因此遍历适合"近似全量"的导出 / 对账,不应作为强一致的事务快照使用。

如需某一时刻的一致性快照(精确全量导出、离线分析、按时间点重建数据等),不要用在线遍历,推荐改用基于备份的方案:

  • 分析文本导出:把表数据导出为文本,供离线分析 / 全量处理;
  • 数据构造:基于备份按时间点构造数据,得到一致的全量快照。

2. 遍历限制

限制项 说明
单请求应答数 SetResNumPerReq(num) 控制一个遍历请求让服务端连续回多少个单位的应答,SDK 收齐后才发下一个请求(流水线批量大小):
· Generic 表:num 为一个请求对应的应答包数目(不是记录数),即服务端连续回 num 个数据包后 SDK 再续发;
· List 表:num 为一个请求返回的 list key 数目(不是包数,一个 key 可能因元素多再分多个包)。
默认 1,最大 100,传 0 返回失败。调大可减少请求往返、提升吞吐,但sdk更容易丢包重试,默认推荐为1
总记录数 SetLimit(n):最多遍历 n 条,-1 表示不限制(全表)
返回字段 SetFieldNames 指定要返回的 key/value 字段(TDR 表用字段名 / PB 表用字段路径),字段数最多 256 个TCAPLUS_MAX_VALUE_FIELD_NUM,3.46.0 之前为 128);不指定则返回整条记录
条件过滤 SetCondition 支持服务端过滤,语法见 条件过滤和更新语法说明
并发遍历数 单个 client 实例最多同时进行 8 个遍历,超出会取不到遍历器
读 slave SetOnlyReadFromSlave(true) slave遍历,减小对master的影响,详见 读分流说明 §5.5

3. 遍历注意事项

  1. 必须持续驱动收包:遍历不会自己跑完。要在循环里不断 RecvResponse 直到状态变为完成。
  2. 遍历对 tcapsvr 有压力:全表扫描是后台重操作,建议结合读 slave(见读分流说明)降低对 master 的冲击,并控制 SetResNumPerReq 与遍历节奏。
  3. 做好超时与异常兜底:大表遍历耗时长,要处理瞬时错误(进入 ST_RECOVERABLE 后按流控间隔 Resume)、不可恢复错误(ST_UNRECOVERABLE 只能 Stop 重试遍历)。
  4. Stop 后对象不可再用:调用 Stop() 之后该遍历器被回收并重置,不得再对其做任何操作,否则行为未定义。
  5. 一致性:遍历非快照(见 §1.2),对账类场景要容忍少量重复 / 遗漏,或在业务侧做去重。

4. 遍历开始后无法中途"暂停"

遍历一旦 Start(),要么驱动它自然跑到结束(ST_IDLE),要么 Stop() 直接终止,没有"暂停后原地继续"的能力。

4.1 为什么不能暂停

  • 遍历进度(当前 offset、当前 shard、shard 列表、遍历器内部 id)全部保存在遍历器对象的内存里
  • 一旦 Stop(),遍历器被 Reset(offset 归 0、shard 列表清空、状态回到空闲)并归还给内部池,进度全部丢失
  • Resume() 看起来像"继续",但它只用于同一进程、同一遍历对象在遇到瞬时中断(限流 busy、单批超时、丢包)后的错误恢复,依赖内存里尚存的进度。它不能Stop() 之后、更不能在进程退出 / 重启后恢复。

所以:"遍历到一半,先停掉,过段时间再从断点继续"——靠 Resume() 是做不到的。

5. 与其它文档的关系

results matching ""

    No results matching ""