news 2026/9/23 2:37:44

NebulaGraph 存储性能压测工具 storage-perf 实战指南:压测参数、方法选择与数据完整性校验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NebulaGraph 存储性能压测工具 storage-perf 实战指南:压测参数、方法选择与数据完整性校验

NebulaGraph 存储性能压测工具 storage-perf 实战指南:压测参数、方法选择与数据完整性校验

【免费下载链接】nebulaA distributed, fast open-source graph database featuring horizontal scalability and high availability项目地址: https://gitcode.com/gh_mirrors/nebul/nebula

storage-perf是 NebulaGraph 仓库中用于直接压测存储服务(storage service)的基准测试工具,它绕过 Graph 层、以 RPC 方式向 Storage 服务灌入读写负载,帮助开发者在部署真实业务前量化getNeighborsaddVerticesaddEdges等核心接口的吞吐与延迟。本文以 src/tools/storage-perf/README.md 为骨架,结合 StoragePerfTool.cpp 与 StorageIntegrityTool.cpp 的源码实现,完整讲解工具的全部配置参数、压测方法与输出指标含义,并介绍配套的数据完整性校验工具。读完本文,你将能够独立搭建压测环境、正确配置参数、读懂压测日志,并用环形链表方案验证存储数据在读写后的完整性。

工具概览:一个入口、两类能力

按 src/tools/storage-perf/README.md 的说明,_build/storage_perf是用于测试存储服务的性能工具。该目录下包含两个相互独立的可执行目标:

  • storage_perf:性能压测工具,源码为 StoragePerfTool.cpp,支持多种 RPC 方法的混合/单一压测;
  • storage_integrity:数据完整性校验工具,源码为 StorageIntegrityTool.cpp,其设计基于 HBase 的IntegrationTestBigLinkedList思路(README 中明确说明 "Integration test is based onIntegrationTestBigLinkedListof HBase")。

两个工具的共同点是:都直接通过 StorageClient 与 meta 服务、storage 服务通信,不经过 Graph 查询层,因此测到的是存储引擎与 RPC 链路的真实能力。

需要说明的是,从当前仓库源码看,src/tools/storage-perf/CMakeLists.txt 中两个可执行目标的nebula_add_executableinstall规则均处于注释状态,且 src/tools/CMakeLists.txt 仅在未启用 standalone 版本(NOT ENABLE_STANDALONE_VERSION)时才添加storage-perf子目录。因此在实际使用前,需要根据你的构建环境按需启用该目标的编译,README 中_build/storage_perf即为构建产物路径。

测试前置条件:空间、Tag 与 Edge

README 明确指出:测试前需要先创建图空间(graph space)、Tag 和 Edge 类型。工具默认使用的名字分别为:

  • 图空间:test
  • Tag:test_tag
  • Edge:test_edge

这三个名字分别对应源码中的默认参数FLAGS_space_nameFLAGS_tag_nameFLAGS_edge_name(StoragePerfTool.cpp)。

从源码实现看,工具的初始化流程会进一步印证这一前提(StoragePerfTool.cpp):

  1. 解析meta_server_addrs得到 meta 服务地址列表(通过NetworkUtils::toHosts),无法解析则直接退出;
  2. 创建folly::IOThreadPoolExecutor(线程数由io_threads控制)与MetaClientskipConfig_ = true),并调用waitForMetadReady()等待 meta 服务就绪;
  3. 通过getSpaceIdByNameFromCache按名字解析 SpaceID——图空间必须已存在,否则报Get SpaceID Failed并退出;
  4. 解析 Tag:若test_tag不存在,工具会自动创建一个仅含一个 STRING 类型属性col_1的 Tag schema,然后等待heartbeat_interval_secs + 1秒让 schema 同步生效;若已存在则直接使用,并读取其全部属性名用于构造请求;
  5. Edge 的处理逻辑与 Tag 完全对称:不存在则自动创建col_1属性,存在则复用。

这意味着:图空间需要你预先通过 Graph 客户端(如nebula-console)创建,而 Tag/Edge 可以由工具自动补齐,但为保证压测数据的可预期性,建议仍按 README 建议提前创建好三者。

配置参数全解析

README 给出了完整的参数参考表,下表逐项继承并补充源码中的实际定义(源码位于 StoragePerfTool.cpp):

属性名README 默认值源码默认值说明
threads21压测总线程数,每个线程独立循环发送请求
qps10001000压测工具的总目标 QPS
totalReqs1000010000压测期间的总请求数,达到后停止
io_threads1010客户端 IO 线程数(folly IOThreadPoolExecutor 线程池大小)
method"getNeighbors""getNeighbors"被测方法:getNeighborsaddVerticesaddEdgesgetVerticesgetEdges
meta_server_addrs""""meta 服务地址,如127.0.0.1:9559
min_vertex_id11最小的顶点 ID(工具内部会转换为字符串)
max_vertex_id1000010000最大的顶点 ID(工具内部会转换为字符串)
size1000—(见property_size每个请求的数据量
space_name"test""test"指定图空间名
tag_name"test_tag""test_tag"指定 Tag 名(要求其属性全部为字符串类型)
edge_name"test_edge""test_edge"指定 Edge 名(要求其属性全部为字符串类型)
random_messagefalsetrue是否向存储服务写入随机消息

源码中 README 未列出的补充参数

对照源码可以发现,README 参数表之外还有三个实际生效的 gflags(这属于 README 与源码的差异,使用时以源码为准):

属性名默认值说明
property_size1000单个属性的字符串长度(字节),即 README 中size的实际实现载体
concurrency50单次批量发出的并发请求数,与令牌桶联动
batch_num1每个请求批量包含的顶点/边数量

此外还有两个值得注意的 README 与源码默认值差异:threads(README 写 2,源码默认 1)与random_message(README 写 false,源码默认 true)。压测前应显式指定这些参数,不要依赖默认值。

参数的作用机制

  • min_vertex_id/max_vertex_id:决定随机顶点 ID 的取值区间。randomVertices()folly::Random::rand32(max - min) + min生成随机 ID(StoragePerfTool.cpp),因此区间大小直接影响数据分布范围。
  • random_message+property_sizegenData()random_message=true时为每个属性生成property_size长度的随机字符串(字符集为数字 + 大小写字母,见 StoragePerfTool.cpp);为 false 时属性值为空字符串。写入数据的真实负载大小 = 属性个数 × 属性长度。
  • meta_server_addrs:格式与 conf/nebula-metad.conf.default 中的--meta_server_addrs=127.0.0.1:9559保持一致,多个地址用逗号分隔。

支持的压测方法与其实现细节

method参数支持五种方法(README 列举了四种,源码 StoragePerfTool.cpp 实际支持五种):

method 取值底层 StorageClient 调用实现要点
getNeighborsgetNeighbors(StorageClient.h)查询随机顶点的邻居,边方向固定为EdgeDirection::BOTH,携带顶点属性与边属性请求
addVerticesaddVertices(StorageClient.h)ifNotExists=true, ignoreExistedIndex=false写入批量顶点,顶点 ID 从min_vertex_id起递增
addEdgesaddEdges(StorageClient.h)批量写入边,每条边为vintId -> vintId+1、rank 为 0
getVerticesgetProps(StorageClient.h)kVid作为输入列构造 DataSet,返回随机顶点的 Tag 属性
getEdgesgetPropskSrc/kType/kRank/kDst四列构造 DataSet,返回随机边的属性

其中getVertices/getEdges在源码中通过统一的getProps接口实现,只是传入的VertexProp/EdgeProp不同。压测数据生成上,genVertices()genEdges()都支持batch_num批量放大单请求负载(StoragePerfTool.cpp),边数据始终指向相邻递增的顶点,保证数据在拓扑上的自洽性。

压测执行流程与结果输出解读

运行模型

Perf::run()的主流程为(StoragePerfTool.cpp):初始化客户端 → 拉起threads个线程 → 每个线程在runInternal()中循环执行,直到全局finishedRequests_达到totalReqs

runInternal()的循环体包含两个关键机制:

  1. 令牌桶限流:每次通过tokenBucket_.consumeOrDrain(FLAGS_concurrency, FLAGS_qps, FLAGS_concurrency)从 folly 的DynamicTokenBucket申请令牌(StoragePerfTool.cpp),即单轮最多发concurrency个请求、总速率不超过qps
  2. 进度与指标上报:每处理 2000 个请求打印一次日志(PLOG_EVERY_N(INFO, 2000)),随后usleep(500)微休眠,避免忙循环打满 CPU。

日志输出解读

压测过程中会周期性输出类似下面的进度日志:

Progress 42%, qps=1032, latency(us) median = 342, p90 = 891, p99 = 2134

这些指标来自两个 folly 直方图对象latencies_qps_(StoragePerfTool.cpp):

  • Progress:已完成请求数占totalReqs的百分比;
  • qps:当前吞吐(qps_.rate(0));
  • latency(us) median / p90 / p99:最近一个时间窗口内请求延迟(微秒)的 50 分位、90 分位与 99 分位估计值。

每个请求的延迟通过time::WallClock::fastNowInMicroSec()在发出前与回调返回后各取一次时间戳相减得到(见各*Task()实现)。压测全部结束后还会输出总耗时与总请求数:

Total time cost 12345ms, total requests 10000

注意:getNeighborsaddEdges等任务中,若请求失败会在回调里打印Request failed及失败分片信息(addVerticesTask会打印具体的 partition 与错误码),这些信息同样是压测结论的重要输入。

Storage Integrity Tool:环形链表式数据完整性校验

README 的最后一段说明:集成测试基于 HBase 的IntegrationTestBigLinkedList。该思路在 StorageIntegrityTool.cpp 中有完整的源码实现,其核心思想是:构造一个环形链表状的数据矩阵,然后沿链表遍历,验证每条数据都能正确读写

参数与默认值

属性名默认值说明
meta_server_addrs""meta 服务地址
io_threads10客户端 IO 线程数
space_name"test_space"目标图空间名(注意与压测工具的默认test不同)
first_key"1"链表的起始 key(最小 key)
width100矩阵宽度(每行的节点数)
height1000矩阵高度(行数)

校验原理

IntegrityTest类(StorageIntegrityTool.cpp)把数据组织成一个width × height的矩阵:每个 key 的 value 是"下一个节点"的 key,所有 key-value 构成一条首尾相接的大链表。其数据排布可用源码注释中的示意图理解——首行、前驱行、当前行逐行串接,最后一行经过旋转后与首行闭合,从而形成一条可从任意节点出发、走width * height步回到起点的环形链表。

具体流程为:

  1. prepareData():先为第一行生成width个 key(从first_key开始递增);然后逐行调用insertRow()写入中间各行(每个 key 指向上一行对应位置的 key);最后将末行旋转一位再插入首行,完成闭环(StorageIntegrityTool.cpp);
  2. 写入通过client_->put(spaceId_, keyValues)批量完成,每 10000 个 key-value 打印一次进度;
  3. validate():从first_key出发,循环width * height次,每次用client_->get(spaceId_, {nextId})取回下一个 key(StorageIntegrityTool.cpp),若中途取不到值或最终没有回到起点,则校验失败并返回非零退出码。

因此,该工具不仅能验证"写入后可读回",还能验证整条数据链的连续性——任何一条数据丢失或错乱都会导致遍历中断或终点不闭合,是检测存储层数据丢失、损坏等问题的有效手段。初始化时若width * height超过int32上限会直接报错退出。

源码阅读指引

如果希望深入理解这两个工具的实现,建议按以下路径阅读:

  • 压测主逻辑:StoragePerfTool.cpp(Perf::run/runInternal/ 五个*Task方法);
  • 完整性校验:StorageIntegrityTool.cpp(prepareData/validate);
  • 底层 RPC 客户端接口:src/clients/storage/StorageClient.h(CommonRequestParam结构与getNeighbors/addVertices/addEdges/getProps声明);
  • 构建集成:src/tools/CMakeLists.txt 与 src/tools/storage-perf/CMakeLists.txt;
  • 服务端默认端口与 meta 地址配置:conf/nebula-metad.conf.default。

结合这些源码,你可以在压测前准确预估每个参数对负载模型的影响(例如concurrency决定瞬时并发、qps决定稳态速率、property_size决定单请求字节数),从而设计出贴合真实业务场景的压测方案。

【免费下载链接】nebulaA distributed, fast open-source graph database featuring horizontal scalability and high availability项目地址: https://gitcode.com/gh_mirrors/nebul/nebula

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 2:37:40

新岛八重性能优化避坑指南:3步解决代码跑不通

新岛八重性能优化避坑指南:3步解决代码跑不通 复制来的代码跑不通,看着报错信息头大?别慌,这不仅是语法问题,更是 性能优化 意识缺失的信号。很多新人觉得新岛八重这类底层逻辑难搞,其实核心就卡在三个点:环境依赖、内存泄漏、线程阻塞。今天咱们不整虚的,直接拆解大厂面试里关于 新岛八重性能优化…

作者头像 李华
网站建设 2026/9/23 2:37:34

面试被问原理答不上来?手写实现顺祝时祺逻辑全解析

面试被问原理答不上来?手写实现顺祝时祺逻辑全解析 面试现场,面试官盯着你问:“为什么你的接口响应慢,具体瓶颈在哪?”你张口结舌,只记得背了八股文,却对底层执行流毫无概念。这种 面试被问原理答不上来 的窘境,根源往往在于你只会在业务代码里调包,从未真正 手写实现…

作者头像 李华
网站建设 2026/9/23 2:37:31

2026最新抽奖活动开发避坑指南:5种实现方案横向对比

2026最新抽奖活动开发避坑指南:5种实现方案横向对比 官方文档往往长篇大论,抓不住重点?做抽奖活动开发,最怕的不是代码写不出来,而是上线后出现“超发”、“重复中奖”或“概率不均”的致命Bug。很多开发者对着 MDN Web Docs…

作者头像 李华
网站建设 2026/9/23 2:37:31

搞懂网络营销理论,代码性能优化提升50%

搞懂网络营销理论,代码性能优化提升50% 你是不是也这样?刷了几百集 Python 视频,敲过无数 Hello World,结果接到一个电商后台需求,直接懵圈。明明逻辑都懂,代码也跑得通,但一上生产环境,用户稍微一多,页面就卡得转圈,接口响应慢得像蜗牛。这时候你才发现,以前学的只是语法,真正缺的是把…

作者头像 李华
网站建设 2026/9/23 2:37:28

面试被问原理卡壳?3个步骤搞定呼哈避坑指南

面试被问原理卡壳?3个步骤搞定呼哈避坑指南 面试现场,面试官盯着你的简历,冷不丁甩出一句:“说说呼哈的核心机制,别背八股文。”你脑子瞬间一片空白,只能尴尬地笑。别慌,这种“面试被问原理答不上来”的窘境,正是技术转岗者最大的软肋。今天这份避坑指南,不聊虚的,直接带你从零搭建一个可复现的“呼哈”实战项目…

作者头像 李华
网站建设 2026/9/23 2:37:22

2026最新草棚避坑指南:3步搞懂底层逻辑

2026最新草棚避坑指南:3步搞懂底层逻辑 官方文档太长抓不住重点,是不是你打开技术百科时的第一反应?别慌,2026最新的实战经验告诉你,搞懂“草棚”这类基础概念的底层原理,根本不需要啃完那几页纸。很多初学者一看到术语就头大,其实只要把抽象概念具象化,三分钟就能建立正确的认知模型。…

作者头像 李华