
Solana AccountsDB 复制设计解析为 RPC 服务构建账户状态副本节点【免费下载链接】solanaWeb-Scale Blockchain for fast, secure, scalable, decentralized apps and marketplaces.项目地址: https://gitcode.com/GitHub_Trending/so/solana本文基于 Solana 仓库中的设计提案 accounts-db-replication.md标题AccountsDB Replication for RPC Services完整解析 Solana 如何通过独立的账户数据库副本replica节点将最昂贵的账户扫描类 RPC 请求从主验证节点上卸载出去。读完后你将理解该方案的动机、复制拓扑、六大核心组件的设计、一致性模型、兼容性与容错机制、副本节点对外暴露的 RPC 接口清单以及该提案在实现计划Action Items层面的分解方式。问题背景RPC 负载拖慢验证节点提案开篇明确了要解决的问题验证节点在承载繁重 RPC 负载时会落后于网络其根源被认为是 CPU 负载与锁竞争lock contention的叠加效应其中最昂贵的 RPC 请求是各类账户扫描account scans例如getProgramAccounts这类需要对账户数据做大范围遍历的调用。从源码结构可以印证这一点Solana 主验证节点的 JSON-RPC 由 JsonRpcService 实现它持有BankForks、BlockCommitmentCache、OptimisticallyConfirmedBank等核心结构RPC 处理逻辑集中在 rpc.rs 中——get_account_info约 L428、get_multiple_accountsL449、get_program_accountsL482、get_supplyL899、get_stake_activationL1753、get_token_accounts_by_ownerL1927等账户相关方法都直接读取运行时状态。这些请求与验证节点主循环POH、分片接收、投票共享同一进程因此锁竞争与 CPU 争抢直接影响出块能力。提案的核心思路正是把这部分负载拆分出去。方案总览独立运行的 AccountsDB 副本方案的核心是引入一组 AccountsDBreplicas与主验证节点分离运行专门用于卸载账户扫描请求。提案规定了副本的职责边界——副本节点只做三件事向验证节点请求并拉取账户更新request and pull account updates响应客户端的账户状态类 RPC 请求管理自身 AccountsDB 与 AccountsBackgroundService 的 clean清理与 shrink收缩维护。复制拓扑上副本通过一套新的 RPC 机制与主验证节点通信拉取复制所需的元信息和账户更新。约束条件是主验证节点只支持一个副本节点但该副本节点可以再把信息转发给一个或多个其他副本从而形成一棵复制树replication tree。启动流程是快照引导加增量追平副本节点初次启动时从一个验证节点下载最新快照snapshot据此构建 bank 与 AccountsDB之后持续向主验证节点查询新 slot并请求对方发送该 slot 上更新过的账户写入自己的 AccountsDB。同一套 RPC 复制机制还可用于副本与副本之间的复制——这要求副本同时实现客户端与服务端两种角色。在客户端 RPC 服务一侧新组件JsonRpcAccountsService负责响应账户相关请求其定位类似于现有的JsonRpcService但只承载 AccountsDB 相关调用。此外副本会周期性打快照保证重启后若快照未过旧即可快速恢复。一致性模型按 slot 一致的最终一致提案的 Consistency Model 一节定义了两条关键语义AccountsDB 信息从主验证节点到副本是异步复制的因此查询副本时副本可能没有最新 slot 的信息——整体属于最终一致eventually consistent但对于某一个特定 slot副本在confirmed与finalized两个确认级别上提供的信息与其对端验证节点一致。因此V1 只支持在这两个确认级别上查询。这一设计与 Solana 现有的BlockCommitmentCache 乐观确认optimistic confirmation体系一致——这也是提案中服务器端需要从BankForks、BlockCommitmentCache和OptimisticallyConfirmedBank三个结构中合成槽位信息的由来。Solana 副本节点的六大核心组件提案将新引入的可执行文件命名为solana-replica-node文档中 RPC node 与 replica node 互换使用它是独立于solana-validator的可执行程序当前仓库中验证节点入口位于 validator 目录。副本由以下组件构成ReplicaSlotConfirmationRequestor客户端侧槽位确认该服务周期性地向对端验证节点或副本发送ReplicaSlotConfirmationRequest请求获取最新槽位信息。请求中携带last_replicated_slot——副本已完成账户信息拉取的最新槽位。该组件维护ReplWorkingSlotSet并管理BankForks、BlockCommitmentCache针对最高已确认 slot以及乐观确认 bank 的生命周期。ReplicaSlotConfirmationServer服务端侧槽位确认该服务响应ReplicaSlotConfirmationRequest返回ReplicaSlotConfirmationResponse。响应内容是一个向量主验证节点所知的、晚于请求中last_replicated_slot的新 slot 列表。该服务同时运行在主验证节点中它从BankForks、BlockCommitmentCache和乐观确认 bank 中获取用于复制的槽位集合。ReplicaAccountsRequestor客户端侧账户拉取该服务对尚未完成 AccountsDB 复制的某个 slot向对端发送ReplicaAccountsRequest拉取该 slot 的ReplicaAccountInfo数据。数据结构上ReplicaAccountInfo包含ReplicaAccountMeta、Hash 和 AccountDataReplicaAccountMeta在现有AccountMeta的信息基础上额外记录账户数据的字节长度。ReplicaAccountsServer服务端侧账户流式下发该服务响应ReplicaAccountsRequest返回ReplicaAccountsResponse其中包含ReplAccountInfo的数量与向量。它运行在主验证节点以及承担中继职责的副本节点中。两个实现要点值得注意流式下发不必落盘服务器可以从 AccountCache 或存储中流式发送账户信息。这与从 AccountsDB 制作快照包的机制类似但差别在于存储无需先刷盘flush到磁盘再向客户端流式传输——若账户数据还在缓存中可以直接流式发出清理竞争处理流式服务期间必须小心避免该 slot 的账户数据被清理clean掉。若尝试复制某个 slot 时发现它已被后续 rooted slot 的更新导致账户数据被清理副本应当放弃该 slot改试更晚的未清理的 root slot。Tombstone 机制区分未更新与清零提案特别指出一个复制语义问题被零 lamports 清理掉的账户信息也必须复制。也就是说必须能区分两种情况——某账户在给定 slot 中未被更新因此在该 slot 没有存储条目与某账户持有 0 lamports 且已被历史清理。方案是引入一种 Tombstone墓碑机制记录每个 slot 上被清理掉的死亡账户墓碑本身在超过以 epoch 为单位的保留期后可以删除。任何尝试复制墓碑已被删除的 slot 都会失败此时副本应跳过该 slot、改试更晚的 slot。这一设计对应着 AccountsDB 中真实存在的清理逻辑——clean_accounts 的职责正是清除零 lamports 账户与旧根账户状态作为垃圾回收并且只删除整个根历史都可以清除的账户即祖先中不存在活跃 append vec 的账户。副本若缺少墓碑信息就无法还原账户曾经存在但被清零的事实getAccountInfo的语义就会出错。JsonRpcAccountsService对外 RPC 服务这是副本节点上响应客户端账户信息查询的 RPC 服务。提案明确了服务边界的划分现有JsonRpcService继续负责非 AccountsDB 的其他客户端调用而副本节点只服务 AccountsDB 调用。与现有实现的差异在于 bank 的加载方式现有JsonRpcService需要BankForks、OptimisticallyConfirmedBank和BlockCommitmentCache来加载 Bank见 rpc_service.rs 中RpcRequestMiddleware持有的这些结构而JsonRpcAccountsService改为使用从ReplicaSlotConfirmationResponse获得的信息来构建 AccountsDB 视图——因为副本并不完整回放区块它没有与主节点逐 block 一致的 bank 生成路径。AccountsBackgroundService后台维护该服务同样运行在副本中负责周期性打快照、AccountsDB 收缩shrinking与账户清理cleaning。由于现有代码依赖BankForks副本中需要保留该结构。当前仓库中对应实现位于 accounts_background_service.rs其轮询间隔INTERVAL_MS为 100ms、清理检查周期CLEAN_INTERVAL_BLOCKS为 100 个 blockL39-L40这与提案副本自行管理 clean shrink的分工完全吻合。兼容性、部署配置与容错协议兼容性Compatibility出于协议兼容考虑所有请求都带有复制版本replication version初始值为 1备选方案是直接使用验证节点版本号。RPC 服务端必须检查请求版本遇到不支持的版本直接失败。复制配置Setup为限制复制对双方产生的不利影响主验证节点与副本节点都可以配置一份允许与其结成复制对的副本节点列表副本节点则配置为其服务的验证节点。这实际上是复制关系的双向白名单。容错Fault Tolerance保证复制容忍故障的主要责任在副本一侧。请求失败时副本必须重试retry。副本节点对外接口清单提案列出了JsonRpcAccountsService支持的客户端 RPC API。这些接口在现行 rpc.rs 中均有对应实现如get_program_accounts、get_largest_accounts、get_supply、get_stake_activation、get_token_accounts_by_owner等。支持的 API19 个API类别getAccountInfo账户查询getBlockCommitment确认级别getMultipleAccounts账户查询getProgramAccounts账户扫描getMinimumBalanceForRentExemption租金getInflationGovenor原文拼写通胀getInflationRate通胀getEpochSchedule纪元getRecentBlockhash区块哈希getFees费用getFeeCalculatorForBlockhash费用getFeeRateGovernor费用getLargestAccounts账户统计getSupply供给统计getStakeActivation质押getTokenAccountBalanceTokengetTokenSupplyTokengetTokenLargestAccountsTokengetTokenAccountsByOwnerToken 扫描getTokenAccountsByDelegateToken 扫描明确不提供的 API18 个getInflationReward、getClusterNodes、getRecentPerformanceSamples、getGenesisHash、getSignatueStatuses原文拼写、getMaxRetransmitSlot、getMaxShredInsertSlot、sendTransaction、simulateTransaction、getSlotLeader、getSlotLeaders、minimumLedgerSlot、getBlock、getBlockTime、getBlocks、getBlocksWithLimit、getTransaction、getSignaturesForAddress、getFirstAvailableBlock、getBlockProduction。从清单划分可以看出接口裁剪的内在逻辑副本拥有完整的账户状态视图因此账户、Token、租金、费用、通胀、纪元等状态类查询可以服务而区块数据、交易签名、区块生产统计、交易发送/模拟等依赖 ledger/Blockstore/TPU 的能力一律不服务——这些能力仍留在主验证节点上。实现计划Action Items提案以 10 项任务收尾勾勒出从框架到集成的落地路径构建副本框架与可执行文件集成快照恢复代码用于引导bootstrapAccountsDB开发ReplicaSlotConfirmationRequestor与ReplicaSlotConfirmationServer的接口代码开发其详细实现管理ReplEligibleSlotSet生命周期新增与删除 root管理ReplWorkingSlotSet的增删接口服务端合成BankForks/BlockCommitmentCache/OptimisticallyConfirmedBank信息的组件以及客户端侧的状态维护开发ReplicaAccountsRequestor与ReplicaAccountsServer的接口代码开发其详细实现并开发复制账户存储的序列化/反序列化器serializer 与 deserializer开发JsonRpcAccountsService的接口代码详细实现JsonRpcAccountsService并重构代码与JsonRpcService共享部分逻辑与副本中的AccountsBackgroundService集成实现收缩、清理与快照指标Metrics与性能测试。需要说明的是在当前仓库快照中尚未检索到ReplicaSlotConfirmationRequestor、ReplicaAccountsRequestor等组件的 Rust 实现solana-replica-node也还不是独立可执行目标——该提案处于设计文档阶段上述组件如JsonRpcService、clean_accounts、AccountsBackgroundService均有现成实现可供对接。这也提示读者文中接口语义以提案原文为准落地形态可能随版本演进而调整。小结AccountsDB 复制提案给出了一套验证节点专注共识、副本节点专注读服务的解耦架构通过槽位确认 账户拉取两个 RPC 循环实现异步复制用墓碑机制保证零余额账户的语义正确用 root slot 回退策略应对清理竞争用版本字段与双向白名单保障协议兼容与部署安全最终让副本仅服务 19 个账户状态类 API。对关心 Solana RPC 容量规划与验证节点性能隔离的开发者该提案是理解其账户存储体系accounts-db、accounts_index与 RPC 服务层rpc之间协作方式的一份核心设计文档。【免费下载链接】solanaWeb-Scale Blockchain for fast, secure, scalable, decentralized apps and marketplaces.项目地址: https://gitcode.com/GitHub_Trending/so/solana创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考