一文带你了解 「图数据库」Nebula 的存储设计和思考( 二 )


问题目录

  • 边的 value 存储边属性吗?
  • 强 Schema 的设计原因
  • 存一份边的设计
  • 图空间如何做物理隔离
  • Meta 如何存储 Schema
  • 存储未来规划
  • VID 遍历点和边的原理
  • 数据预校验
  • Nebula 监测
  • Nebula 的事务
  • 数据膨胀问题
  • 磁盘容量本身不均怎么处理
  • Nebula 的 RocksDB “魔改”
边的 value 存储边属性吗?和上面底层存储里讲的那样 , 创建 Edge 的 schema 时候会指定边类型上的属性 , 这些属性会作为底层 RocksDB key 的 value 存储起来 , 这个 value 的占位是定长的 , 和下面这个问题类似:
强 Schema 的设计原因
强 schema 是因为技术原因还是产品原因? 因为考虑到 string 类型是变长的 , 每行长度本身就不固定 , 感觉跟无 schema 无区别 。如果非定长 , 那查询时怎么知道该查询到哪里呢? 是有标志位么?
其实本质上原因是用强 Schema 的好处是快 , 先说下常见的简单数据类型 , 比如:int 和 double , 这样的数据类型长度是固定的 , 我们会直接在 value 相应的位置进行编码 。再说下 string 类型 , 在 Nebula 中有两种 string :一种是定长 string , 长度是固定 , 和前面的简单数据类型一样 , 在 value 的固定位置进行编码 。另外一种是变长的 string , 通常来说大家都会比较倾向于变长 string(灵活) , 非定长 string 会以指针形式存储 。
举个例子 , schema 中有个属性是变长 string 类型 , 我们不会和简单数据类型一样直接编码保存 , 而是在相应位置保存一个 offset 指针 , 实际指向 value 中的第 100 个字节 , 然后在 100 这个位置才保存这个变长 string 。所以读取变长 string 的时候 , 我们需要在 value 中读两次 , 第一次获取 offset , 第二次才能真正把 string 读出来 。通过这样的形式 , 把所有类型的属性都转化成"定长" , 这样设计的好处是 , 根据要读取的属性和它前面所有字段的占用字节大小 , 可以直接计算出要读取的字段在 value 中存储的位置 , 并把它读出来 。读取过程中 , 不需要读取无关的字段 , 避免了弱 schema 需要对整个 value 进行解码的问题 。
像 Neo4j 这种图数据库 , 一般是 No Schema , 这样写入的时候会比较灵活 , 但序列化和反序列化时都会消耗一些 CPU , 并且读取的时候需要重新解码 。
追问:如果有变长 string , 会不会导致每行数据长度不一样
可能 value 长度会不一样 , 因为本身是变长嘛 。
追问:如果每行长度不一样 , 为什么要强 schema? Nebula 底层存储用的 RocksDB , 以 block 的形式组织 , 每个 block 可能是 4K 大小 , 读取的时候也是按 block 大小进行读取 , 而每个 block 中的各个 value 长度可能是不一样的 。强 schema 的好处在于读单条数据的时候会快 。
存一份边的设计
Nebula 存边是存储了两份 , 可以只存储一份边吗?存一份边反向查询是否存在问题?
其实这是一个比较好的问题 , 其实在 Nebula 最早期设计中是只存一份边的属性 , 这适用于部分业务场景 。举个例子 , 你不需要任何的反向遍历 , 这种情况下是完全不需要存反向边 。目前来说 , 存反向边最大的意义是方便于我们做反向查询 。其实在 Nebula 比较早的版本中 , 准确说它是只存了反向边的 key , 边类型的属性值是没有存 , 属性值只存在正向边上 。它可能带来一些问题 , 双向遍历或者反向查询时 , 整个代码逻辑包括处理流程都会比较复杂 。如果只存一份边 , 反向查询的确存在问题 。
图空间如何做物理隔离大家在用 Nebula 时 , 首先会建图空间 CREATE SPACE , 在建图空间时 , 系统会分配一个唯一图空间 ID 叫 spaceId , 通过 DESCRIBE SPACE 可以获取 spaceId 。然后 Storage 发现某台机器要保存 space 部分数据时 , 会先单独建一个额外的目录 , 再建单独 RocksDB 在这个上面起 Rocks 的 instance(实例)用来保存数据 , 通过这样方式进行物理隔离 。这样设计的话 , 有个弊端:虽然 rocksdb 的 instance , 或者说整个 space 目录是互相隔离 , 但有可能存在同一块盘上 , 目前资源隔离还做的不够好 。


推荐阅读