nebula系统架构

240 阅读6分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

Nebula Graph 产品架构图:

image.png

Meta Service

Metaservice 对应的进程是 nebula-metad ,其主要的功能有:

用户管理:Nebula Graph 的用户体系包括 Goduser , Admin , User , Guest 四种。每种用户的操作权限不一。
集群配置管理:支持上线、下线新的服务器。
图空间管理:增持增加、删除图空间,修改图空间配置(Raft副本数)
Schema 管理:Nebula Graph 为强 schema 设计。 通过 Metaservice 记录 Tag 和 Edge 的属性的各字段的类型。支持的类型有:整型 int, 双精度类型 double, 时间数据类型 timestamp, 列表类型 list等;
多版本管理,支持增加、修改和删除 schema,并记录其版本号
TTL 管理,通过标识到期回收 time-to-live 字段,支持数据的自动删除和空间回收 MetaService 层为有状态的服务,其状态持久化方法与 Storage 层一样通过 KVStore 方式存储。

image.png

Storage Service

image.png

Nebula Graph 的 Storage 包含两个部分, 一是 meta 相关的存储, 称之为 Meta Service ,另一个是 data 相关的存储, 称之为 Storage Service。

这两个服务是两个独立的进程,数据也完全隔离,当然部署也是分别部署, 不过两者整体架构相差不大。

Storage Service 共有三层,最底层是 Store Engine,它是一个单机版 local store engine,提供了对本地数据的 get / put / scan / delete 操作,目前 Nebula Graph 提供了基于 RocksDB 实现的 Store Engine。

在 local store engine 之上,便是 Consensus 层,实现了 Multi Group Raft,每一个 Partition 都对应了一组 Raft Group,这里的 Partition 便是数据分片。 目前 Nebula Graph 的分片策略采用了 静态 Hash 的方式。用户在创建 SPACE 时需指定 Partition 数,Partition 数量一旦设置便不可更改,一般来讲,Partition 数目要能满足业务将来的扩容需求。

在 Consensus 层上面也就是 Storage Service 的最上层,便是 Storage interfaces,这一层定义了一系列和图相关的 API。 这些 API 请求会在这一层被翻译成一组针对相应 Partition 的 kv 操作。 正是这一层的存在,使得存储服务变成了真正的图存储,否则,Storage Service 只是一个 kv 存储。

顶点存储的key格式:

image.png

Type : 1 个字节,用来表示 key 类型,当前的类型有 data, index, system 等 Part ID : 3 个字节,用来表示数据分片 Partition,此字段主要用于 Partition 重新分布 (balance) 时方便根据前缀扫描整个 Partition 数据 Vertex ID : 8 个字节,用来表示点的 ID Tag ID : 4 个字节, 用来表示关联的某个 tag Timestamp : 8 个字节,对用户不可见,未来实现分布式事务 (MVCC) 时使用 顶点value格式:

propertity1propertity2propertity3propertity4...propertityN

边存储的key格式:

image.png

Type :1 个字节,用来表示 key 的类型,当前的类型有 data, index, system 等。 Part ID :3 个字节,用来表示数据分片 Partition,此字段主要用于 Partition 重新分布 (balance) 时方便根据前缀扫描整个 Partition 数据 Vertex ID :8 个字节,出边里面用来表示源点的 ID, 入边里面表示目标点的 ID。 Edge Type :4 个字节,用来表示这条边的类型,如果大于 0 表示出边,小于 0 表示入边。 Rank :8 个字节,用来处理同一种类型的边存在多条的情况。用户可以根据自己的需求进行设置,这个字段可存放交易时间、交易流水号、或某个排序 Vertex ID :8 个字节,出边里面用来表示目标点的 ID, 入边里面表示源点的 ID。 Timestamp :8 个字节,对用户不可见,未来实现分布式做事务的时候使用。 边value格式:

propertity1propertity2propertity3propertity4...propertityN

Query Service

image.png

Session Manager

Nebula Graph 权限管理采用基于角色的权限控制(Role Based Access Control)。

客户端第一次连接到 Query Engine 时需作认证,当认证成功之后 Query Engine 会创建一个新 session,并将该 session ID 返回给客户端。所有的 session 统一由 Session Manager 管理。

session 会记录当前的 graph space 信息及对该 space 的权限。此外,session 还会记录一些会话相关的配置信息,并临时保存同一 session 内的跨多个请求的一些信息。

客户端连接结束之后 session 会关闭,或者如果长时间没通信会切换为空闲状态。这个空闲时长是可以配置的。

客户端的每次请求都必须带上此 session ID,否则 Query Engine 会拒绝此请求。

Storage Engine 不管理 session,Query Engine 在访问存储引擎时,会带上 session 信息。

Parser

Query Engine 解析来自客户端的 nGQL 语句,分析器(parser)主要基于著名的 flex / bison 工具集。字典文件(lexicon)和语法规则(syntax)在 Nebula Graph 源代码的 src/parser 目录下。设计上,nGQL 的语法非常接近 SQL,目的是降低学习成本。

图数据库目前没有统一的查询语言国际标准,一旦 ISO/IEC 的图查询语言(GQL)委员会发布 GQL 国际标准,nGQL 会尽快去实现兼容。

Parser 构建产出的抽象语法树(Abstract Syntax Tree,简称 AST)会交给下一模块:Execution Planner。

Execution Planner

执行计划器(Execution Planner)负责将抽象树 AST 解析成一系列执行动作 action(可执行计划)。action 为最小可执行单元。例如,典型的 action 可以是获取某个节点的所有邻节点,或者获得某条边的属性,或基于特定过滤条件筛选节点或边。

当抽象树 AST 被转换成执行计划时,所有 ID 信息会被抽取出来以便执行计划的复用。这些 ID 信息会放置在当前请求 context 中,context 也会保存变量和中间结果。

Optimization

经由 Execution Planner 产生的执行计划会交给优化框架 Optimization Framework。优化框架中注册有多个 Optimizer。Optimizer 会依次被调用对执行计划进行优化,这样每个 Optimizer 都有机会修改(优化)执行计划。

最后,优化过的执行计划可能和原始执行计划完全不一样,但是优化后的执行结果必须和原始执行计划的结果一样。

Execution

Query Engine 最后一步是去执行优化后的执行计划,这步是执行框架(Execution Framework)完成的。执行层的每个执行器一次只处理一个执行计划,计划中的 action 会依次执行。执行器也会做一些有限的局部优化,比如:决定是否并发执行。

针对不同 action,执行器将通过客户端与 meta service 或 storage engine 进行通信。