nebula对于并发查询的支持

  • nebula 版本:2.0.1
  • 部署方式:分布式
  • 安装方式:RPM
  • 硬盘 1T x 3
  • CPU 16C x 3
  • 内存 128G x 3

我的业务场景:

设想,一些生活类软件打算开发一套让用户自己规划出行游玩路径的应用,并且想要通过图数据库来完成路径的查询,因此在图中将每一个结点设置为一个景点,每个景点的特色用 “gourmet, authentic, cheap, sea” 等这样的字符串来表示,景点之间特色可能不同。现希望能够提供如下的功能:

用户配置起点景点的集合和终点景点的集合,并提供期望的景点特色比如 “cheap, sea",希望能够返回所有在整条路经的所有景点中都带有指定的特色关键词。

举例:一条符合要求的路径为: 海边游乐场 → 海边餐厅 → 沙滩,在这条路径中每个景点都带有 “sea” 字符串。

我所遇到的问题:

  1. 由于景点特色存储在结点属性中,当前我使用的是在循环中每次查一种景点特色,用 CONTAINS 判断结点属性中是否有这些特色,但是当用户设定的特色变多的时候,这种方法的速度就会慢下来。
  2. 为了解决上述问题,我试图采用多线程的形式,同时调用多个session进行查询,但是并没有任何改进,根据这个帖子的回复,我认为应该是由于我的多个线程最终都会在相同的数据上进行搜索,所以仍然需要排队。
  3. 由此诞生的第三个问题是,既然 nebula 不允许多个线程或用户同时操作同一片数据,我们应该如何保证多用户访问该应用的速度和效率?
2 个赞

2.0.1的版本 按照你的场景,只能使用 多个go语句拼接,你的go语句是什么样的

2 个赞

我当前的 GO 语句是类似这样:

LOOKUP ON start | YIELD $-.VertexID as head_id | \
GO FROM $-.head_id OVER edgein YIELD edgein._dst as site_1 | \
GO FROM $-.site_1 OVER Travel WHERE $^.Place.prop CONTAINS 'cheap' \
YIELD Travel._dst as site_2, $-.site_1 | \
GO FROM $-.site_2 OVER Travel \
WHERE $^.Place.prop CONTAINS 'cheap' \
AND $$.Place.prop CONTAINS 'cheap' \
YIELD Travel._dst as site_3, $-.site_2 as site_2, $-.site_3 as site_3

在这里我们创建了一个辅助结点 start, 通过 edgein 连接到用户指定的起点集合,然后一次只指定一种特色,在外部通过其他语言(并且试图通过多线程)查找带有其他特色的路径。

我们也尝试过使用 UNION ALL 将全部的语句拼接起来,但是由于网络中数据量很大,这样做会导致在指定的特色数量多的情况下返回的时间很长。

可以考虑升级到最新的master版本,或者等年后 3.0的版本, 新的版本中 对match进行了优化,可以使用match语句
上面你的场景 可以使用
match (start)-[e1:edgein ]->(s1{prop:‘cheap’})-[e2:Travel]->(s2 {prop:‘cheap’})-[e3:Travel]->(end:{prop:‘cheap’}). where id(start) in [xxx, yyy, zzz …] return s1, s2, s3

2、 可以使用多线程 调用多个session,要确保一个线程中所有的query 都是通过一个session 进行操作的,不是一个query 一个session。
3、你理解错了,不是nebula 不允许多个线程同时操作同一片数据,读是不会有排队的

1 个赞

多个session 进行查询,和一个session 查询,时间上是一样吗, 可以观察一下 吞吐量和时延的指标

感谢回复,我们在测试中确实发现使用多个不同的session查询,和一个session查询的时间是一样的。
吞吐量和时延的指标应该如何去查看呢?

想问一下,官方有没有使用python并行查询nebula的代码示例可以参考?我们现在无法确定是数据库的配置问题还是代码的问题。

另外,我们尝试过官方在github上的例子,但是依旧没有成功并行。

你好,我们再次做了一些实验,发现复杂的语句在多线程的情况下会出现运行时间随语句复杂度上升的情况。

情景描述

我们的语句:

edge_left = "GO FROM 'head' OVER edgein YIELD edgein._dst as site1| " \
            "GO FROM $-.site1 OVER Travel" \
            "WHERE $$.Place.prop CONTAINS '{0}' " \
            "YIELD Travel._dst as site2, $-.site1 as site1 | " \
            "GO FROM $-.sie2 OVER Travel" \
            "WHERE $$.Place.prop CONTAINS '{0}' " \
            "YIELD Travel._dst as site3, $-.site2 as site2, $-.site1 as site1".format("cheap")

经过测试发现,如果不在每个管道连接符之前返回上一个语句的结果,那么多线程运行到 site1, site2 的总时间分别是 2s 和 20s;如果在管道连接符之前返回之前语句的结果,那么多线程运行到 site1, site2 的总时间分别是 2.4s 和 44s。

然而,如果同时在两个终端上进行单个线程内的计算,双方的运行速度都非常快。

我的问题

请问有没有可能是由于语句的复杂性和需要频繁返回之前的全部结果,导致语句在 nebula 中多线程运行的时候出现了阻塞?nebula 内部对这种读取和查询的语句有什么全局锁吗?如果用多进程是否能解决这种问题?

1、检测吞吐量和时延可以使用 nebula- dashboard。参考文档https://docs.nebula-graph.com.cn/2.5.0/nebula-dashboard/4.use-dashboard/
2、如果不在每个管道连接符之前返回上一个语句的结果 和 管道符 之前返回上一个语句的结果,两者的时间有差异, 这要看一下,你是返回哪些结果了,有没有包含目的点的属性,如果包含目的点的属性是可预期的

3、多线程情况和单线程情况相比没有提升,可以看一下,用dashboard监控一下,是否是内存,或者cpu 哪里有瓶颈,
多线程吞吐量是否有提升,延时应该会比单线程要增大一点

1 个赞

受限于 python 的全局解释锁,和 python 解码的速度比较慢,python 的多线程并不一定会很明显的提升效率。

  1. 看一下你们查询返回的数据,有多少条,是不是数据量比较大。
  2. 如果返回的数据比较大,客户端在解码时,其实是 cpu 密集,这个时候另一个线程的处理还是会等待的。可以简单看一下是不是一个核的 cpu 打满了,可以试一下多进程。
2 个赞