分片会自己分裂:NEAR 重分片如何在纪元边界一分为二 图 1
分片会自己分裂:NEAR 重分片如何在纪元边界一分为二 · 图 1

分片型公链都面对同一道题:账户被分到若干分片上并行处理,可热度从来不会均匀落进每个分片。某个分片因为一两个热门应用被挤满、其他分片闲着的局面一旦持续,单纯指望用户自己搬家是不够的。NEAR 的方案是让分片本身会分裂:一个过载的分片在纪元边界一分为二,账户各回各家,下一纪元起按新格局出块。本文按 nearcore 官方文档与 NEP-0568 拆解这套重分片机制的触发位置、拆法与时间约束。

分片格局由谁决定

NEAR 用一个叫分片布局(ShardLayout)的结构决定两件事:一共有几个分片,以及每个账户归哪个分片。文档强调一个硬前提:单个账户不能被拆开分到两个分片,所以归属判断只能以账户为单位。布局有两代算法。早期的版本把账户名做哈希后对分片数取模,账户与分片的关系是散列式的;后来的版本改为预设一组边界账户,把账户名按字典序落进相邻边界之间——也就是说,a.near 可能落在零号分片,而更靠后的名字落进别的分片。布局版本记录在协议配置里,按纪元生效,改分片数量本质上就是换一版布局。

分裂发生在纪元的哪一步

状态树在纪元边界按账户归属拆成两棵子树的抽象示意

NEP-0568 描述的重分片时机非常具体:新布局被硬编码进节点程序并与协议版本绑定;当升级推进到预定纪元的最后一个区块时,后处理阶段执行分片拆分,父分片的状态劈给两个子分片;从新协议版本的第一个区块起,链就按新格局运行。拆分的工程难点在于状态树:每个分片的状态由一棵树表示,分裂要求把一棵树即时拆成两棵,让子分片在下一个区块到来前就能开始处理交易。官方文档给出的做法是借助扁平存储的快照遍历条目,按账户归属把父树的条目逐条插进对应的子树。还有一类麻烦条目——延迟收据队列——键里不含账户名,只能整段遍历后按目标分片重新入队。

状态树在纪元边界按账户归属拆成两棵子树的抽象示意

为什么必须在一个纪元内完成

文档把约束写得很直白:父分片的同步、重分片本身、子分片的追赶,三件事必须都塞进同一个纪元的时间窗里。这个约束决定了整套设计偏向保守——拆分被安排在纪元末尾这一最干净的切点,此时旧格局刚刚结账、新格局还没开工,跨分片消息和收据的迁移有明确边界可对齐。对节点运营者来说,这意味着纪元末尾的计算压力会上升:要在此前把父分片状态同步完整,否则拆分没有可用的底账。

用户和开发者看什么

重分片对普通转账与合约调用基本是透明的:地址不变,资产不需要搬动,变化只体现在某个分片的历史区块由谁产生、状态查询落在哪个分片上。需要留神的是跨纪元边界的对账逻辑:如果索引器按分片拉取区块和收据,分裂发生的那个纪元里,同一个账户的历史会先后出现在父分片与子分片的流里,游标和重放规则要能处理这种换轨。核验某笔交易时,以最终性后的交易结果和跨分片收据的落地为准,而不是某一分片视角的临时状态。

需要提醒的是,分片数量与拆分阈值属于会随协议版本演进的参数,本文描述的是 nearcore 文档与 NEP-0568 记载的机制框架,具体到当前主网用哪版布局、阈值如何设定,应以官方文档与链上配置为准。本文不构成任何投资建议。