Skip to main content

写入架构

BlockDB 为区块链计算场景设计:上游数据总是按区块粒度产出,天然就是一批一批的行。因此 BlockDB 的写入以 batch 批量写为预设,而不是传统的单行写。区别只在于 batch 的规模——小的、近实时的 batch 走实时写;大的、回填场景的 batch 走批量写。

一切写均为异步

BlockDB 一切写操作均为异步:SDK 不暴露 sync 参数,所有写入接口返回 WriteResult { affectedRows, jobID },不代表数据已立即落库。 因此,普通的写入接口不满足经典的写后读一致性——写请求返回后立刻读,不保证能读到刚写入的数据。 但这个”缺口”在 BlockDB 的逻辑模型中被弥补:
  • Block 表:写入成功后,write 服务通过 Kafka 发布 BlockSubscribeEvent。下游通过 Subscribe 接收事件后再读取该区块的数据,BlockDB 保证此时数据已落库可见。在订阅驱动的计算链路中:写 → 事件 → 读,是严格满足写后读一致性的。
  • Time 表:写入后通过 GetValue 对 _archive 表查询,同样能获取已落库的历史桶数据。
因此,虽然底层写是异步的,但通过 Block 表和 Time 表的读写订阅接口,在区块链计算场景中严谨满足一致性需求。

SDK 写接口总览

实时写

批量写(S3 中转,上限 1000 万行)

批量写统一走一个 gRPC 服务 BatchWriteService。在 InitWriteJob 请求中,通过选择 strategy 字段来指定目标表类型:
例如,发起一个 Time 表批量写任务:
所有写方法返回统一的 WriteResult { affectedRows, jobID }。

实时写架构

实时写由简单的无状态 writer 负责,内部采用内存异步队列 + 多线程响应式写入:
  1. 入队:写入请求进入内存异步队列(asyncqueue),立即返回 jobID。用户不会因后端落库速度而阻塞。
  2. 消费:多个 worker 线程并发从队列中取任务,批量写入底层物理数据库。
  3. 流量整形:队列容量有上限,当后端落库跟不上时触发拒绝(返回 QUEUE_OVERLOAD),将无上限的实时流量转为有上限的写入流量,保护底层数据库。
设计目标:实时流量不阻塞用户提交;空闲线程几乎立即响应写入请求,达到近实时。

批量写架构

当写入规模达到百万行级别(上限 1000 万行)时,实时写的内存队列不可行。批量写通过 S3 对象存储中转 + 异步 worker 实现:

任务生命周期

  1. InitWriteJob:客户端发起写入任务申请。BlockDB 在表的 _write 表中创建一条 job 记录,返回 S3 presigned 上传 URL 与 jobID。
  2. 上传数据文件:客户端将数据上传到返回的 S3 URL。
  3. CommitWriteJob:客户端调用提交接口,BlockDB 将 job 状态置为待处理,后台 worker 开始消费。
  4. Worker 执行:worker 从 S3 拉取任务文件,执行排序、去重、批量插入等步骤后落库。

架构特点

  • 提交吞吐无上限:任务通过 S3 中转,不占用实时内存通路,可连续高吞吐提交。
  • 落库速度快:worker 以批处理方式工作,实际写入速度可达数十万~百万行/s(视表类型与底层数据库规模)。
  • 可取消:堆积的写入任务可通过 CancelWriteJob API 取消,释放 S3 资源及 _write 表中的对应 job 记录。
  • 任务状态可查:job 在 _write 表中维护,包括已初始化、已提交、处理中、完成或失败等状态,便于运维排查。

实时写 vs 批量写