Neo4j over bolt 协议具有非常高的延迟
Posted
技术标签:
【中文标题】Neo4j over bolt 协议具有非常高的延迟【英文标题】:Neo4j over bolt protocol has very high latency 【发布时间】:2016-10-14 19:30:55 【问题描述】:我正在将 Neo4j 用于一个项目,该项目使用此处找到的适用于 .NET 的官方 Neo4j 驱动程序:
https://www.nuget.org/packages/Neo4j.Driver
这个驱动程序在螺栓协议上工作,我的假设是一个专门的二进制协议会比 HTTP API 更有效。但自从项目开始以来,我注意到 Neo4j 的延迟相对较高,即使是非常简单的操作也是如此。例如,当UserID
是索引字段并且数据库完全为空时,如下所示的匹配需要 30-60 毫秒:
match(n:User UserID: 1 ) return n.UserID
此行为发生在我的本地计算机(几乎为零的网络开销)和我们的生产环境中。我今天开始对此进行调查,发现查询返回很快,但实际输入结果需要很长时间。例如,以下查询在调用返回 localhost 之前需要 0.2ms,但随后在 result
上调用 ToArray()
(缓冲记录,在本例中是单个整数字段)会增加60ms 的时间。
using (var driver = GraphDatabase.Driver($"bolt://localhost:7687", AuthTokens.Basic("neo4j", "1")))
using (var session = driver.Session())
// 0.2ms to return from this call
var result = session.Run("match(n:User ID: 1) return n.ID");
// Uncommenting this makes the whole thing take 60ms
// result.ToArray();
然后我尝试了社区赞助的 Neo4jClient 包,它通过 HTTP 工作:
https://github.com/Readify/Neo4jClient
使用相同的查询,总时间减少到仅 0.5 毫秒:
var client = new GraphClient(new Uri("http://localhost:7474/db/data"), "neo4j", "1");
client.Connect();
client.Cypher.Match("(n:User ID: 1)").Return<int>("n.ID").Results.ToArray();
运行更官方的基准测试给出了以下结果,螺栓驱动的官方驱动程序和基于 HTTP 的 Neo4jClient 之间存在巨大差异。
Host Process Environment Information:
BenchmarkDotNet.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-4770 CPU 3.40GHz, ProcessorCount=8
Frequency=3312642 ticks, Resolution=301.8739 ns, Timer=TSC
CLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1586.0
Type=Neo4jBenchmarks Mode=Throughput Platform=X64
Jit=RyuJit
Method | Median | StdDev | Scaled | Scaled-SD |
------------- |--------------- |------------ |------- |---------- |
Neo4jClient | 382.5675 us | 3.3771 us | 1.00 | 0.00 |
Neo4jSession | 61,299.9382 us | 690.1626 us | 160.02 | 2.24 |
因此,当网络开销可以忽略不计时,HTTP 客户端的速度快了 160 倍。
我还在我们的生产环境中运行了基准测试,虽然差异没有那么大,但 HTTP 方法的速度仍然快了 6 倍(而且我与生产环境的网络连接速度非常慢)。
完整的基准代码:
public class Neo4jBenchmarks
private readonly IDriver _driver;
private readonly GraphClient _client;
public Neo4jBenchmarks()
_driver = GraphDatabase.Driver("bolt://localhost:7687", AuthTokens.Basic("neo4j", "1"));
_client = new GraphClient(new Uri("http://localhost:7474/db/data"), "neo4j", "1");
_client.Connect();
[Benchmark(Baseline = true)]
public void Neo4jClient()
_client.Cypher.Match("(n:User ID: 1)").Return<int>("n.ID").Results.ToArray();
[Benchmark]
public void Neo4jSession()
using (var session = _driver.Session())
session.Run("match(n:User ID: 1) return n.ID").ToArray();
我的机器和生产都运行 Neo4j CE 3.0.4(目前是社区版),尽管我在 Windows 10 上运行它并且生产是 Linux 机器。据我所知,我们没有调整任何设置,但我怀疑这可以解释 160 倍的性能差异。
我还尝试重用会话对象(我认为这是一个非常糟糕的主意,因为它不是线程安全的),因为创建会话涉及创建事务,以查看是否有所作为,但事实并非如此显。
我希望我可以使用 Neo4jClient,但我们确实需要执行任意字符串查询的能力,而 Neo4jClient 严重依赖流畅的 API,虽然它提供了低级字符串模式,但它已被弃用,actively discouraged in the documentation。
【问题讨论】:
我完全愿意使用字符串进行查询,无论是使用您想要的语法进行拉取还是引发错误,我们都可以看到我们能做什么! @ChrisSkardon - 那太好了!如果我能破解一些东西,我会看看。我基本上正在寻找的是 Neo4j 的 Dapper:低级别,输入是字符串和参数,我只是获得将结果映射到对象的帮助。跨度> 【参考方案1】:进一步挖掘后,我将问题追溯到 Neo4j.Driver 包,因为 NodeJS 的驱动程序没有遇到同样的问题。
克隆包的当前source,构建它并直接引用DLL而不是NuGet包完全消除了这个问题。客观地说:NuGet (1.0.2) 上的当前版本需要 62 秒 对 localhost 执行 1000 个简单匹配请求,而当前源在 0.3 秒内完成此操作 strong>(甚至比 NodeJS 驱动程序高出 10 倍)。
我不太清楚为什么,但我很确定它与当前包的 rda.SocketsForPCL
依赖关系有关,它似乎是一个胶水库,可以使套接字跨平台工作。但是,当前来源为此引用了 System.Net.Sockets
包。
因此,总而言之,这个问题可以通过引用源的当前版本来解决,并且会在发布新版本的软件包时完全解决。
【讨论】:
以上是关于Neo4j over bolt 协议具有非常高的延迟的主要内容,如果未能解决你的问题,请参考以下文章