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


Meta 如何存储 Schema【一文带你了解 「图数据库」Nebula 的存储设计和思考】我们以 CREATE TAG 为例子 , 当我们建 tag 时 , 首先会往 meta 发一个请求 , 让它把这个信息写进去 。写入形式非常简单 , 先获取 tagId , 再保存 tag name 。底层 RocksDB 存储的 key 便是 tagId 或者是 tag name , value 是它每一个字段里面的定义 , 比如说 , 第一个字段是年龄 , 类型是整型 int;第二个字段是名字 , 类型是 string 。schema 把所有字段的类型和名字全部存在 value 里 , 以某种序列化形式写到 RocksDB 中 。
这里说下 , meta 和 storage 两个 service 底层都是 RocksDB 采用 kv 存储 , 只不过提供了不一样的接口 , 比如说 , meta 提供的接口 , 可能就是保存某个 tag , 以及 tag 上有哪些属性;或者是机器或者 space 之类的元信息 , 包括像用户权限、配置信息都是存在 meta 里 。storage 也是 kv 存储 , 不过存储的数据是点边数据 , 提供的接口是取点、取边、取某个点所有出边之类的图操作 。整体上 , meta 和 storage 在 kv 存储层代码是一模一样 , 只不过往上暴露的对外接口是不一样的 。
最后 , storage 和 meta 是分开存储的 , 二者不是一个进程且存的目录在启动的时指定的也不一样 。

追问:meta 机器挂了 , 该怎么办?
是这样 , 通常来说 Nebula 建议 meta 以三副本方式部署 。这样的话 , 只挂一台机器是没有问题的 。如果单副本部署 meta 挂了的话 , 是无法对 schema 进行任何操作 , 包括不能创建 space 。因为 storage 和 graph 是不强依赖 meta 的 , 只有在启动时会从 meta 获取信息 , 之后都是定期地获取 meta 存储的信息 , 所以如果你在整个集群跑的过程中 , meta 挂了而又不做 schema 修改的话 , 对 graph 和 storage 是不会有任何影响的 。
存储未来规划
Nebula 后面在存储层有什么规划吗?性能 , 可用性 , 稳定性方面
性能这块 , Nebula 底层采用了 RocksDB , 而它的性能主要取决于使用方式 , 和调参的熟练程度 , 坦白来说 , 即便是 Facebook 内部员工来调参也是一门玄学 。再者 , 刚才介绍了 Nebula 的底层 key 存储 , 比如说 VID 或者是 EdgeType 在底层存储的相对位置某种程度上决定了部分 Query 会有性能影响 。从抛开 RocksDB 本身来说 , 其实还有很多性能上的事情可做:一是写点或者写边时 , 有些索引需要处理 , 这会带来额外性能开销 。此外 , Compaction 和实际业务 workload 也会对性能有很大影响 。
稳定性上 , Nebula 底层采用 raft 协议 , 这是保证 Nebula Graph 不丢数据一个非常关键的点 。因为只有这层稳定了 , 再往下面的 RocksDB 写入数据才不会出现数据不一致或者数据丢失的情况发生 。此外 , Nebula 本身是按照通用型数据库来设计的 , 会遇到一些通用型数据库共同面临的问题 , 比如说 DDL 改变;而本身 Nebula 是一款分布式图数据库 , 也会面临分布式系统所遇到的问题 , 像网络隔离、网络中断、各种超时或者因为某些原因节点挂了 。上面这些问题的话 , 都需要有应对机制 , 比如 Nebula 目前支持动态扩缩容 , 整个流程非常复杂 , 需要在 meta 上、以及挂掉的节点、剩余“活着”的节点进行数据迁移工作 。在这个过程中 , 中间任何一步失败都要做 Failover 处理 。
可用性方面 , 我们后续会引入主备架构 。在有些场景下所涉及的数据量会比较少 , 不太需要存三副本 , 单机存储即可 。这种全部数据就在单机上的情况 , 可以减去不必要的 RPC 调用 , 直接换成本地调用 , 性能可能会有很大的提升 。因为 , Nebula 部署一共起 3 个服务:meta、graph 和 storage , 如果是单机部署的话 , graph + storage 可以放在同一台机器上 , 原先 graph 需要通过 RPC 调用 storage 接口去获取数据再回到 graph 进行运算 。假如你的查询语句是多跳查询 , 从 graph 发送请求到 storage 这样的调用链路反复执行多次 , 这会导致网络开销、序列化和反序列化的这些损耗提高 。当 2 个进程(storaged 和 graphd)合在一起 , 便没有了 RPC 调用 , 所以性能会有个大提升 。此外 , 这种单机情况下 CPU 利用率会很高 , 这也是目前 Nebula 存储团队在做的事情 , 会在下一个大版本同大家见面 。


推荐阅读