我正在使用Neo4j进行使用官方Neo4j驱动程序for .NET的项目:
https://www.nuget.org/packages/Neo4j.Driver
这个驱动程序适用于bolt协议,我的假设是专用二进制协议比HTTP API更有效。但是从项目开始以来,我注意到Neo4j的延迟相对较高,即使是非常简单的操作也是如此。例如,当UserID
是索引字段且数据库完全为空时,以下匹配为30-60ms:
match(n:User { UserID: 1 }) return n.UserID
在我的本地计算机(接近零网络开销)和我们的生产环境中都会发生此行为。我今天开始调查此问题并发现查询很快返回,但实际流式传输结果需要很长时间。例如,下面的查询在localhost上调用返回之前需要 0.2ms ,然后在ToArray()
上调用result
(缓冲记录,在这种情况下是一个整数field)将时间增加到 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客户端 160x 。
我还在我们的生产环境中运行基准测试,虽然差异不是很大,但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,虽然它提供了低级别的字符串模式,但它已被弃用且{{3} }。
答案 0 :(得分:4)
在进一步挖掘之后,我特意将问题追溯到Neo4j.Driver软件包,因为NodeJS的驱动程序没有遇到同样的问题。
克隆包的当前source,构建它并直接引用DLL而不是NuGet包完全消除了这个问题。为了正确看待:NuGet(1.0.2)上的当前版本需要 62秒来对localhost执行1000个简单匹配请求,而当前源在 0.3秒内执行此操作 strong>(甚至将NodeJS驱动程序击败10倍)。
我不太清楚为什么,但我很确定它与当前包的rda.SocketsForPCL
依赖关系有关,它似乎是一个胶合库,使套接字能够跨平台工作。但是,当前源会引用System.Net.Sockets
包。
总而言之,这个问题可以通过引用源的当前版本来解决,并且在发布新版本的软件包时将完全解决。