随着 2.0 各版本的陆续发布,Nebula Graph 迎来了一系列的改动,在存储方面,影响最大的改动就是底层编码格式进行了修改。Nebula Graph 的底层存储是基于 KV 保存在 RocksDB 中,本文将介绍新老编码格式的差异,以及为什么要修改存储格式等一系列问题。
我们先简单回顾下 1.0 版本的编码格式,不熟悉的可以参考这篇博客《 Nebula 架构剖析系列(一)图数据库的存储设计》。由于在 1.0 版本中,点的 ID 只能够用整型来表示,所以底层所有 VertexID 都是以 int64 来保存的。
给定任何一个 VertexID,经过 hash,可以得到对应的 PartID,因此对于一个点和这个点的所有边(边用起点计算 hash ),都会映射到同一个分片中。需要指出的是,在 1.0 版本中,点和边的第一个字节的 Type 是相同的。也就是说,对于一个点而言,它的所有 tag 并没有在物理上连续保存,比如可能是如下保存的。对于这个 src 这个点的三个 tag ( tag1 tag2 tag3),实际上可能会被其他边隔开。
这个格式能够满足 1.0 绝大多数接口的需要,比如 fetch
和 go
都只需要指定对应前缀,就能获取对应数据。
在 GA 之前发布的版本,底层存储格式其实和 1.0 是基本相同的。如果 VertexID 是整型,和 1.0 格式完全一致。而如果 VertexID 类型支持 string,则从占用 8 个字节的 int64 改成了固定长度的 FIXED_STRING
,长度需要用户在 create space
时候指定长度。对于不足的长度系统自动使用 \0
补齐,而超过指定长度的 VertexID 会直接报错。
在 GA 版本中,我们对底层存储格式进行了若干改动,因此这次版本升级时需要通过升级工具,将原有格式的数据转换为新格式的数据。如下是在 2.0 GA 版本中采用的存储格式。
其中有几个比较大的改动:
这些改动主要是基于以下几点进行考虑的:
为什么 string ID 要使用 FIXED_STRING ? 如果不使用固定长度,则无法使用前缀进行扫描。通过长度不足补齐,使得所有点之间和边之间的各个前缀长度相同,从而进行相应的前缀查询。
在边里面还保留一个字节的占位符,主要是留给 TOSS ( transaction on storage side )使用。主要用于标识一条边的出边和入边是否完整插入了,这里不详细介绍,后续会有其他文章进行详尽的分析。
MATCH
语句中大量使用)。如果按原先同一 Type + VertexID
前缀扫描,由于点边可能掺杂在一起,会极大影响性能。而 Type 分离之后,按 VertexType + VertexID
前缀扫描,可以快速获取所有 tag 。在 1.0 版本中,由于没有取某个点的所有 tag 的需求,因此点和边可以按同一个前缀保存。不过在代码层面,还是有不小影响,例如 fetch 接口在 1.0 是按 VertexID 的前缀去扫描的,对于超级大点来说取 tag 性能比较差。另外如果使用 storage 提供的 scan 接口,想要获取全图的所有点,实际是扫描了整个 RocksDB 。
除了点和边的格式相关改动之外,索引的格式其实也有所改变。
一方面是 2.0 支持 NULL
后,索引也需要能够表示对应的语义。另一方面是在 1.0 的版本中,对于索引中 string 的字段的处理,实际是按变长 string 处理。因此在 LOOKUP
语句中只要使用了带 string 字段的索引,就只能使用等值查询。而在 2.0 的版本中,索引的 string 字段和数据中的 VertexID 一样,使用固定长度的 FIXED_STRING,LOOKUP
语句中带 string 字段的索引能够使用范围查询,例如 LOOKUP ON index1 WHERE col > "aaa"
。有关索引部分的功能和修改,后续也会再有其他文章介绍。
以上,为本次 Nebula Storage 2.0 存储格式讲解。
喜欢这篇文章?来来来,给我们的 GitHub 点个 star 表鼓励啦~~ 🙇♂️🙇♀️ [手动跪谢]
交流图数据库技术?交个朋友,Nebula Graph 官方小助手微信:NebulaGraphbot 拉你进交流群~~
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.