NebulaGraph 存储 = 自研 KVStore + RocksDB

总览:NebulaGraph 存储 = 自研 KVStore + RocksDB

  • NebulaGraph 的 Storage Service 上面暴露点/边接口(如 getNeighbors / insert vertex/edge),下面落地为 自研 KVStore,而 KVStore 的本地引擎选用 RocksDB。分布式一致性用 Multi-Group Raft,每个 **分片(Partition)**是一组 Raft 副本,每个分片有自己的 WALdocs.nebula-graph.io

  • 一台 storaged 进程可以配置多个数据目录(多块盘),每个目录一个独立的 RocksDB 实例;同一集群里可以承载多个 Graph Space,物理隔离。docs.nebula-graph.io+1

RocksDB 的工作原理(与 NebulaGraph 相关部分)

  • 写路径:先写 WAL,再写 MemTable(跳表),内存满了刷盘生成 SSTable,然后进行 Compaction(层级合并)。读取依赖 Bloom FilterIndexBlock Cache 降低 I/O。支持 Column Family(CF) 把逻辑数据分组管理。docs.nebula-graph.ioGitHub+1

  • 前缀遍历优化:RocksDB 提供 Prefix Seek / Prefix Bloom,当你的访问始终落在某个前缀内时,可以跳过不相关的 SST,图遍历场景收益很大。NebulaGraph 默认支持并提供开关与前缀长度选项。GitHub+1docs.nebula-graph.io

  • Compaction Filter(TTL):RocksDB 在 Compaction 过程中可以丢弃过期键。NebulaGraph 用它来实现 TTL(在 Tag/Edge 上配置 TTL_COL/TTL_DURATION 即可自动过期删除)。docs.nebula-graph.io

NebulaGraph 如何把“图”映射到 RocksDB(关键)

1) 键编码(Key Encoding)与物理冗余

NebulaGraph 把点和边编码成 有序 Key + Value(属性值) 存进 RocksDB,确保可用 前缀扫描 高效遍历。

  • 点(Vertex)Key 格式(v2/v3)
    Type(1B) | PartID(3B) | VID(int64 或 fixed_string) | TagID(4B)
    其中 VID 支持整型或固定长字符串(空间创建时指定)。v2 开始把 1.x 中的 Timestamp 字段移除了。docs.nebula-graph.io

  • 边(Edge)Key 格式(v2/v3)
    Type(1B) | PartID(3B) | VID(A) | EdgeType(4B, 正=out, 负=in) | Rank(8B) | VID(B) | PlaceHolder(1B)
    同一条逻辑边会以两条 KV 保存(一条 out-edge、一条 in-edge),方便从两端做邻居遍历,所以容量近似翻倍。v2 也去掉了 1.x 的 Timestamp,并新增 PlaceHolderdocs.nebula-graph.io

  • Value(属性):按 强类型 Schema 固定偏移编码,并带 Schema 版本号 以支持在线变更(新增字段等)。读取时会从 Meta 拉取/缓存 Schema 来解码。docs.nebula-graph.io

2) 分区、路由与一致性

  • 分区(Partition):对 VID 做 hash+取模把数据平均打散到不同分区;分区数在 CREATE SPACE 时指定,之后不可更改docs.nebula-graph.io

  • 一致性(Multi-Group Raft):每个分区是一组 Raft 副本,写入先到 Leader,写 Raft WAL 同步过半再成功;读默认经 Leader。NebulaGraph 还支持 Transfer LeadershipListener(向 ES 同步做全文索引)。docs.nebula-graph.io

  • Rebalance:数据/Leader 迁移支持手动触发,NebulaGraph 不做自动 rebalance 以避免影响线上业务。docs.nebula-graph.ioNebulaGraph 技术社区

3) 遍历与前缀扫描(为什么快)

  • 点与边的 Key 以 Type+PartID(+VID) 为前缀组织;启用 Prefix Bloom 后,scan / getNeighbors 这类“在同一前缀内大量顺序访问”的操作可以显著减少 SST 命中。前缀长度可配置(常见 12 或 16 字节,用来覆盖 Type+PartID+VID 等前缀),也支持 Partitioned Index/Filter 降低内存。docs.nebula-graph.io+1GitHub

4) 二级索引与全文检索

  • 属性索引:索引数据与主数据一样落到本地 RocksDB,底层是 按属性值排序的前缀扫描,因此只支持 左前缀匹配 的语义;建索引/重建索引通过 JOB 管理。NebulaGraphsiwei.io

  • 全文索引:通过 Listener 消费 WAL 同步到 Elasticsearch,适合 LIKE/正则等全文场景。NebulaGraph

5) TTL 与清理

  • 在 Tag/Edge 上设置 TTL 后,存储层通过 RocksDB Compaction Filter 自动剔除过期键,无需应用层定时任务。docs.nebula-graph.io

6) 快照与副本追赶

  • Raft 扩容/恢复时会用 RocksDB 快照(基于迭代器导出) 加速新副本追赶,减少 Leader 的重放压力。Medium

存储读写路径(一步步看)

  1. :GraphD → Storage(路由到目标分区的 Leader)→ 写入 Raft WAL & MemTable → 过半副本确认 → 返回成功 → RocksDB 后台刷盘/Compaction。docs.nebula-graph.io

  2. :GraphD → Leader → Storage 层进行 过滤/聚合下推(尽量在存储侧完成 predicate/limit 等)→ 结合 前缀 seekBloom 顺序拉取。docs.nebula-graph.io

RocksDB / NebulaGraph 常用概念清单

  • WAL / MemTable / SST(Level0…)/ Compaction:LSM-Tree 基石。docs.nebula-graph.io

  • Block Cache /(可选)Row Cache:热点数据缓存。Nebula 可配置 rocksdb_block_cacheGitHubdocs.nebula-graph.io

  • Column Family(CF):逻辑分组,便于不同数据类别用不同参数。GitHub

  • Prefix Bloom / Whole-Key Bloom / Partitioned Index-Filter:读放大优化与内存控制。docs.nebula-graph.ioGitHub+1

  • Iterator / Snapshot:范围扫描与一致性读基元。GitHub

  • Compaction Filter(TTL):内置清理策略实现 TTL。docs.nebula-graph.io

  • Raft(Leader/Follower/Learner/Listener)Multi-GroupTransfer Leadershipdocs.nebula-graph.io

  • 分区数固定(建 Space 决定)、边双写(in/out)Rank 支持并行多条边。docs.nebula-graph.io

常见调优/配置(入门指引)

  • 前缀过滤
    --enable_rocksdb_prefix_filtering=true--rocksdb_filtering_prefix_length=12|16(按你的键前缀而定);必要时启用 --enable_partitioned_index_filterdocs.nebula-graph.io

  • 压缩/层级
    --rocksdb_compression=lz4(默认)或按层配置 --rocksdb_compression_per_level;平衡 CPU 与磁盘。docs.nebula-graph.io

  • 缓存
    --rocksdb_block_cache 设为机器内存的合理比例(早期文档建议 1/3,仅作参考,线上需压测校准)。docs.nebula-graph.io+1

  • 列族/表选项
    rocksdb_column_family_options={"write_buffer_size":"67108864","max_write_buffer_number":"4","max_bytes_for_level_base":"268435456"}
    rocksdb_block_based_table_options={"block_size":"8192"} 等从 Nebula 配置注入。docs.nebula-graph.io

  • 多盘并行
    配置多个 data_path,让 Nebula 自行并行管理多个 RocksDB 实例。docs.nebula-graph.io

  • 监控
    打开 RocksDB 统计并结合 Nebula 的统计页面排查读写瓶颈。docs.nebula-graph.io

小结(怎么理解“原理”)

  • 核心思想:用 可排序的 Key 编码 把图拆成键值;用 LSM-Tree 的写入吞吐与 前缀扫描 的顺序读特性,支撑海量邻居遍历;用 Raft 保证强一致;用 TTL/索引/下推 把“图数据库行为”织入 RocksDB 的生命周期。对应到实现,就是上面提到的键布局、分区与 Raft、读写路径、以及 RocksDB 的若干特性开关。docs.nebula-graph.io

如果你接下来想落地到“如何为你的数据模型/查询模式设定键前缀、分区数、索引与 RocksDB 选项”,把你的具体规模与典型查询(点度分布、邻居深度、是否大量属性过滤等)告诉我,我可以直接给一份参数与数据布局建议表。

posted @ 2025-08-17 08:17  郭慕荣  阅读(27)  评论(0)    收藏  举报