ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

xrpld NodeStore 深度解析:NodeObject 数据结构、可插拔后端与基准测试指南

xrpld NodeStore 深度解析:NodeObject 数据结构、可插拔后端与基准测试指南 xrpld NodeStore 深度解析NodeObject 数据结构、可插拔后端与基准测试指南【免费下载链接】rippledDecentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C项目地址: https://gitcode.com/GitHub_Trending/ri/rippled本指南以 rippled 仓库的 include/xrpl/nodestore/README.md 为骨架系统讲解 xrpld 的节点存储层NodeStore从承载账本条目的 NodeObject 数据结构到可运行时切换的多种持久化后端Backend再到[node_db]配置的完整写法与官方基准测试的用法。读完本文你将掌握 NodeStore 的存储格式、各后端选型依据、配置文件编写要点以及如何用--unittestNodeStoreTiming复现后端性能对比实验。一、NodeStore 是什么NodeStore 是 xrpld 用来持久化账本数据的存储层。xrpld 将所有账本条目统一抽象为 NodeObject进行读写并在进程退出后通过持久化数据库保存这些对象当某个 NodeObject 不在内存缓存中时会按需从数据库读回。这一点在 include/xrpl/nodestore/Database.h 的类注释中表述得很明确All ledger data is stored as node objects and as such, needs to be persisted between launches. Furthermore, since the set of node objects will in general be larger than the amount of available memory, purged node objects which are later accessed must be retrieved from the node store.由于 NodeObject 集合通常远大于可用内存被淘汰的对象后续被访问时必须从 NodeStore 重新取回因此持久化层的读写性能直接决定了节点同步与账本访问的整体表现。二、NodeObject账本条目的最小载体2.1 三个核心字段根据 include/xrpl/nodestore/NodeObject.h 的实现一个NodeObject由三个字段构成mType类型一个枚举值说明 blob 中装的是什么内容。源码中NodeObjectType枚举的完整取值见 include/xrpl/nodestore/NodeObject.h#L18-L24共四类业务对象加两个辅助值ledger账本头ledger header。transaction一笔已签名的交易signed transaction。account node账本账户状态树account state tree中的节点。transaction node账本交易树transaction tree中的节点。另有两个非业务枚举值Unknown 0与Dummy 512表示无效或缺失的对象。mHash哈希对 blob 内容的 256 位哈希uint256用于唯一标识该对象。README 描述为“256-bit hash of the blob”而 NodeObject.h 注释 进一步说明该哈希实际上是half-SHA512SHA-512 的一半且不校验哈希与数据是否匹配这一职责由上层的 SHAMap 承担见see SHAMap。mData数据变长的序列化数据块即对象的主体载荷。2.2 mData 的物理存储格式README 给出了 blob 的字节布局表这是理解磁盘上数据形态的关键字节位置含义说明0...7unused预留未使用8typeNodeObjectType 枚举值9...enddata对象数据主体即序列化后第 9 字节起才是真正的对象数据体。NodeObject在 NodeObject.cpp 中的实现非常轻量构造函数直接以Blob移动接管调用方的数据缓冲createObject是唯一合法的构造入口并通过PrivateAccess技巧将构造函数对外隐藏。2.3 键长与批量写限制每个 NodeObject 的哈希键固定为32 字节kKeyBytes 32见 NodeObject.h#L39后端实例一旦创建便与固定键长绑定见 Backend.h 注释。批量写入的预分配大小为 256单批最大写入数限制为 65536实际使用时可能达到该值的两倍因为旧批次写出时新批次已在增长见 include/xrpl/nodestore/Types.h#L10-L19。后端操作返回Status枚举Ok / NotFound / DataCorrupt / Unknown / BackendError自定义状态从CustomCode 100起Types.h#L24-L32。三、Backend可插拔的持久化接口NodeStore 通过Backend抽象接口屏蔽具体数据库引擎允许在运行时按配置选择不同的 key/value 数据库README 原文lets different key/value databases to be chosen at run-time。这是 NodeStore 性能持续被研究改进的架构基础。include/xrpl/nodestore/Backend.h 定义了核心接口从中可以看到一个持久化后端必须实现的能力open(createIfMissing)/close()/isOpen()生命周期管理打开时若库文件缺失可自动创建并允许调用方捕获异常。fetch(hash, pObject)按哈希取单个对象支持并发调用。store(object)/storeBatch(batch)单个或批量写入store支持并发storeBatch保证不与自身或store并发执行。sync()强制落盘。forEach(f)遍历库中全部对象通常在**数据库导入import**期间使用。getWriteLoad()估算待处理写操作数量供诊断使用。fdRequired()声明后端预期需要的文件描述符数量用于启动前的资源预检。getName()返回人类可读的后端名用于诊断输出。后端的创建由Factory完成include/xrpl/nodestore/Factory.hManager作为单例统一注册、查找工厂并构造数据库include/xrpl/nodestore/Manager.h。Manager::makeDatabase的注释说明参数中type键是必需的决定后端选择多数后端还要求path字段Database析构时会完成所有挂起操作、冲刷待写数据并关闭文件。在 Database.h 层还有两处值得注意的设计双层缓存fetchNodeObject提供同步Synchronous与异步Asynchronous通过asyncFetch两种取数方式Database内部维护读写统计计数store/fetch 次数、命中率、耗时等可通过getCountsJson输出到 JSON 供监控。earliest_seqearliestLedgerSeq_默认取 XRP 账本网络允许的最早账本序号 32570可通过[node_db]段的earliest_seq覆盖仅建议单元测试或替代网络修改Database.h#L235-L241。四、配置[node_db]选择后端与调优后端选择与数据库路径全部通过配置文件中的[node_db]段指定格式为一行或多行大小写不敏感的keyvalue对。4.1 README 给出的最小示例typeRocksDB pathrocksdb compression1其中type不区分大小写决定后端HyperLevelDBLevelDB 的改进版README 标注为 preferred即当时推荐项。LevelDBGoogle 的 LevelDB已弃用deprecated。none不使用任何后端。RocksDBFacebook 的 RocksDB构建于 LevelDB 之上。SQLite使用 SQLite。path后端数据文件的存放目录。compression压缩开关0关闭、1开启默认开启。对应到 RocksDBFactory.cpp#L175 的实现RocksDB 后端默认使用 Snappy 压缩rocksdb::kSnappyCompression。4.2 当前仓库示例配置中的实战参数需要特别指出README 写于多年以前而当前仓库的实际推荐后端已演变为 NuDB。cfg/xrpld-example.cfg#L1648-L1653 中的真实配置如下[node_db] typeNuDB path/var/lib/xrpld/db/nudb nudb_block_size4096 online_delete512 advisory_delete0结合 cfg/xrpld-example.cfg 的完整注释[node_db]段可用的键还包括type当前可选NuDBRipple Labs 自研、专为 xrpld 与固态硬盘优化、无论历史数据多少都保持高速全平台可用与RocksDB通用开源 KV 存储适合非 SSD 系统存储数据越多性能越差不建议保留全量历史并推荐配合 online_delete 使用。pathNuDB 与 RocksDB 均必需数据库存放位置相对路径以 xrpld.cfg 所在位置为基准。cache_size可选数据库记录缓存大小默认 16384设 0 使用默认值。cache_age可选记录在缓存中的保留时长分钟默认 5 分钟注意若配置了online_delete旋转式 NodeStore 不使用该缓存缓存不会被创建。fast_load可选布尔值进程启动时先从磁盘加载最后持久化的账本再与网络同步IOPS 充足时可能显著改善启动性能默认 0。earliest_seq可选默认 32570匹配 XRP 主网最早允许序号替代网络可调整最小 1。online_delete可选最小 256开启历史账本自动清理至少保留该数量的账本记录在线且必须大于等于ledger_history。nudb_block_sizeNuDB 专属实验性NuDB 内部存储的块大小必须是 409632768 之间的 2 的幂默认 4096。小块适合常规 SSD 与 ext4/NTFS/HFS 文件系统819216384 对高端 NVMe SSD 及 ZFS/Btrfs 等写时复制文件系统更友好32768 适合内存充裕的企业级高速场景。数据库创建后不可修改只能重建整库。配合online_delete的清理行为参数advisory_delete0/11 时需通过管理 RPCcan_delete手动允许删除、delete_batch每次批量删除的最大记录数默认 100、back_off_milliseconds批次间等待毫秒数默认 100、age_threshold_seconds最新已验证账本超过该秒数则暂停清理默认 60、recovery_wait_seconds节点失同步时检查间隔默认 2、max_waiting_ledgers等待期间允许被验证的最多账本数最小 64默认等于 online_delete 值。此外配置段[import_db]配合--import命令行选项可把指定数据库一次性迁移进[node_db]指定的当前数据库cfg/xrpld-example.cfg#L1130-L1136。4.3 RocksDB 的进阶调优项README 提到的 RocksDB 后端在源码中开放了大量直接可配选项RocksDBFactory.cpp#L100-L218cache_mb块缓存大小MB未显式hard_set时默认 256 会被提升为 1024。filter_bits/filter_full配置 Bloom 过滤器位数及其是否只过滤块级NewBloomFilterPolicy。open_files最大打开文件数未hard_set时 2000 会被提升为 8000同时fdRequired随之计算。file_size_mb目标文件大小MB默认 8 会提升为 256并联动推导max_bytes_for_level_base与write_buffer_size。bg_threads/high_threads后台低/高优先级线程数高优先级线程同时用于后台 flush。universal_compaction非 0 时启用 Universal 压缩风格。b_bt_options/options直接透传 RocksDB 的BlockBasedTableOptions与Options字符串通过GetBlockBasedTableOptionsFromString/GetOptionsFromString解析。启动时后端会把生效的 DBOptions 与 CFOptions 以 debug 日志打印RocksDBFactory.cpp#L213-L217便于核对实际生效参数。五、基准测试NodeStoreTimingREADME 指出NodeStore.Timing测试通过执行一组读/写负载来横向对比当前可用的 nodestore 后端运行方式为$xrpld --unittestNodeStoreTiming同时可以通过--unittest-arg传入备用数据库配置字符串从而在不修改主配置文件的情况下对比不同后端参数的效果。这使该测试成为评估 RocksDB 调优参数的标准工具。从当前仓库的测试代码看后端覆盖列表仍在演进src/tests/libxrpl/nodestore/Backend.cpp#L30-L41 中backendTypes()返回nudb并在编译期宏XRPL_ROCKSDB_AVAILABLE与XRPL_ENABLE_SQLITE_BACKEND_TESTS使能时追加rocksdb与sqlite该测试用多线程并行执行 N 个读/写任务注释明确说明其镜像了旧版 Timing 测试的 parallel-for 语义任务按原子计数器分区而非重复即旧版NodeStore.Timing的后继实现。此外 src/test/nodestore/DatabaseConfig_test.cpp 对数据库配置如[sqlite]段的safety_level及对应 PRAGMA做了覆盖验证。六、附录RocksDBQuick 的历史结论2014 年README 的 Addendum 提醒读者下文讨论的RocksDBQuick后端已从代码中移除其不工作且无人维护它的实现思路是调用 RocksDB 的若干Optimize*方法一次性设置大部分参数而主线 RocksDB 后端则直接开放大量配置项。如需参考 RocksDBQuick 的代码可回溯到本仓库 1.2 及更早版本。以下结论形成于约 2014 年基于更新版本的 RocksDB 可能需要重新验证README 标注 TBD。该讨论记录了用 RocksDBQuickFactory 作为测试平台、对比其与 xrpld.cfg 中既有推荐配置的性能结论要点如下写前日志WAL与双队列问题WAL 开启时高负载下插入速度很快被堵住。BatchWriter类通过把写入排队并在独立线程执行避免阻塞主线程但 RocksDB 本身已有专职线程把 memtable flush 到磁盘而 memtable 本身就是内存队列——于是形成了“两个队列 中间一层持久性保证”的结构。若以 memtable 作为唯一队列并在恰当时机例如账本 close 之后手动触发rocksdb::Flush()可获得类似但更可预测的持久性保证同时省去一个线程与不必要的内存占用。另一种观点是网络上总有大量其他 xrpld 实例在运行节点随时可从对等节点取回数据因此并不需要如此强的保证。块内查找应从二分搜索改为哈希索引旧实现中块内查找使用二分搜索但 xrpld 的使用模式几乎不会连续访问相邻的 key/value因此对块做哈希索引更合理。RocksDB 对 memtable 与 block 都提供多种哈希索引选项需要更多测试来确定最优选择。缓存的取舍现有Database实现本身已有两层缓存因此 Factory 层的块级 LRU 缓存意义不大但若哈希索引与新的 Bloom 过滤器能让“不存在的 key”查找更快则缓存可以下沉到 Factory 层。基准测试的可重复性差多次运行结果可能差异明显推测与 RocksDB 压缩compaction过程的异步性有关。基准是人为构造的高写负载数据集用于测量不同读访问模式因此需要多次运行才能形成有效判断——这与当时 keyvadb 的基准测试时间高度可重复形成鲜明对比。此外 200 万两个插入基准完成后实际为 400 万个 key/value 的数据集规模偏小不足以给出全貌。profiler 的意外收获在 profiler 中运行基准时可清晰观察 RocksDB 的内部行为模式由此决定试验哈希索引并发现原生 CRC32 指令未被使用。旧 sst 文件不生效如果用已有 sst 文件集测试该 Factory旧 sst 文件在未来的压缩操作完成之前不会受益于任何索引变更。这些结论至今仍对理解“为何 NodeStore 采用当前架构”具有参考价值写路径需要权衡队列深度与持久性、读路径偏好哈希索引而非顺序访问优化、缓存层次需要与上层 Database 缓存协同、以及基准测试必须多轮重复才能下结论。七、总结NodeStore 是 xrpld 账本持久化的核心存储单元所有账本条目统一为NodeObject由类型NodeObjectType、32 字节 half-SHA512 哈希与变长 blob 组成blob 第 8 字节起依次是类型与数据体include/xrpl/nodestore/NodeObject.h。架构分层Backend抽象接口 Factory/Manager工厂机制让后端可在运行时按[node_db]配置自由切换Database层在其上提供缓存、异步读取与统计include/xrpl/nodestore/Backend.h、include/xrpl/nodestore/Database.h。配置实战当前推荐后端是 NuDB示例配置见 cfg/xrpld-example.cfg#L1648-L1653RocksDB 作为备选开放了大量直通调优项src/libxrpl/nodestore/backend/RocksDBFactory.cpp。验证手段$xrpld --unittestNodeStoreTiming可在不同后端间运行读写负载基准--unittest-arg可注入临时配置后继测试实现见 src/tests/libxrpl/nodestore/Backend.cpp。部署或调优节点时建议结合自身存储硬件SSD/NVMe/文件系统、历史保留策略online_delete与可接受的内存占用先在基准测试中多轮验证再决定type、nudb_block_size等关键参数因为部分参数如块大小在数据库创建后不可更改。【免费下载链接】rippledDecentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C项目地址: https://gitcode.com/GitHub_Trending/ri/rippled创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表