Skip to main content

多表区块高度对齐订阅

业务背景

在级联实时分析里,下游的目标表是一张 Block 表,按区块粒度写入:每个高度 H 的所有计算结果作为一个批次,原子写入目标表的 H 高度。因此当上游有多张表时,必须先等所有上游表都把 H 处理完毕,才能一次性计算 H、作为一个批次写入目标表;否则 H 批次会缺数据、产生脏批次。 更关键的是,计算函数里常用 get_state 读取依赖表的状态快照。读的是哪个高度版本,取决于依赖表的共识高度:只有依赖表的共识高度 ≥ H,get_state 才能返回 H 高度版本的状态数据;否则会因共识高度小于 H 而报错、拿不到 H 的状态。因此必须先等依赖表的水位推进到 H 及以上,才能执行函数。 直接同时订阅多张表的事件流,会因各表计算快慢不一,收到完全乱序的高度通知(例如 trace 已到 18000010,而 token 还在 18000005)。 SDK 内置的 Aligned 对齐状态机,把这两类等待需求区分开,在数据库变更流层面自动完成对齐。

Trigger 表与 Depends 表

Aligned 区分两类表,各自采用不同的对齐规则(类似多流 join,但两类的 join 条件不同):
  1. Trigger 表(loose_align):上游数据源。对齐规则是「所有 Trigger 表都在高度 H 就绪」——因为下游要按 H 批次写入,上游少一张就代表 H 批次缺数据。
  2. Depends 表(strict_align):计算中用 get_state 读取的状态表。对齐规则是「Depends 表的共识高度 ≥ H」——因为 get_state 只能读到不超过共识高度的快照,水位没到 H 就读不到 H 的状态。
两者的判据不同:Trigger 看「是否都产生了 H」,Depends 看「水位是否覆盖 H」。只有当 H 同时满足所有 Trigger 就绪、且所有 Depends 水位到位,才会放行 H。每个高度只放行一次,天然幂等。

完整示例

共识高度是怎么计算的

Aligned 通过查询每张 Depends 表的 _height 派生表来计算共识高度:
  • 每张 Block 表对应一张 <表名>._height 表,每行记录一段已处理的高度区间(block_height_start / block_height_end),写入侧已合并成连续区间。
  • 共识高度 = 起始高度最小那行的 block_height_end,即第一个连续区间的右边界。
  • 表还没被处理过时,共识高度取 start_height - 1——一张起始高度不为 0 的表,比起点低的高度永远不会有数据。
因此,只要 Depends 表从 start_height 起连续提交每个块(含空块),它的共识高度就会持续推进,依赖它的下游才能随之放行。

最佳实践

  • Depends 表每个块都要提交任务,包括空块:空块也要提交一个空任务来推进 _height 水位,否则 coverage 出现 gap,共识高度就停在 gap 前,下游整条管道会静默停住。
  • 单表订阅无需 Aligned:只订阅一张表直接 for ... in Subscribe(...).listen() 即可。
  • 同一张表可同时作为 Trigger 和 Depends:Aligned 会先记它的 ready、再刷新它的水位,保证 diff 区间能看到刚标上的高度。
  • Subscribe 内置重连与游标续传,直接 for ... in aligned.listen(): 消费,无需自己写重试。

相关阅读