Nebula Graph v2.6 当中比较重要的特性之一便是 TOSS。通过本文,我将带你全方位了解 TOSS 为何物。
从一条 GO 语句说起
众所周知,边分为无向边跟有向边两种。所以当按有向边去探索时,就可以按正向边 / 反向边做遍历,Nebula Graph 也支持这种语义。比如:
go from "101" over known reversely yield known.kdate, id($$);
上述语句从点 101 开始反向的找所有的对应邻边。但,当用户使用 Nebula 插入一条边时,命令都类似于:
insert edge known(degree) VALUES "100" -> "101":(299792458);
上述语句看上去只写了正向边,并没有输入反向边:这是因为在 Nebula 设计时,当用户插入一条边时,系统会默默地在后台写入一条反向边。
聊聊 Nebula Graph 如何插入一条边
以上文的那条 INSERT 语句为例,后台的执行流程有:
- Nebula Console 将
INSERT
对应的 request 发给连接的 Nebula Graph Server; - Nebula Graph Server 收到后,根据正向边的信息对应补充出反向边的信息,并将这个 AddEdgeRequest 分别发往正反向边对应的主机;
- Nebula Storage Server 收到这个 AddEdgeRequest 后,在本地(通过 raft)插入对应的边,并将结果返回给 Graph Server;
- Nebula Graph Server 收到两边的结果后,返回给 Nebula Console;
流程图如下:
这里,对网络 / 分布式编程比较熟悉的同学可能现在就看出问题了:因为 Graph 对于两个 Storage 的调用使用 RPC,那么当 INSERT
操作执行的次数足够多,就一定会遇到一边 RPC 成功,另一边 RPC 失败(超时)的情况。换句话说,可能出现一个 INSERT
正向边成功,反向边失败的情况。
这种结果会反馈给客户端:如果用户有正反向边属性一致的需求,就需要对 failed 的 request 做无限重试。但是 Nebula Graph 做为一个数据库,将数据的原子性交由外部(客户端)来保证还是不合适的。
于是,诞生了一个需求——保证正反向边的原子性,即变更边时,正反边要么同时变更成功,要么同时变更失败。这便是 TOSS(Transaction on storage side)的由来,用于保证对边进行 INSERT
、UPDATE
或 UPSERT
操作的最终一致性。
TOSS 使用方法
随着 Nebula v2.6.0 的发布,TOSS 功能已经上线。但基于性能和稳定性考虑,Nebula Graph 默认将该功能设为 default disable 状态。有正反向边一致性需求的小伙伴们可以在 Nebula Graph Server的配置中找到 enable_experimental_feature
这个选项,将它设为 true 并重启 graphd。如下:
--enable_experimental_feature=true
那么之后的 INSERT
/ UPDATE
/ UPSERT
就会有一致性的保证了。(跟之前一样做 CREATE SPACE
/ CREATE EDGE
/ INSERT
/ UPDATE
即可,不需要额外操作)