首页 > 解决方案 > Gremlin:ConcurrentModificationException 和多线程

问题描述

我的应用程序还没有上线,所以我正在测试 Gremlin 查询的性能,然后再投入生产。

为了测试,我使用了一个查询,该查询将边从一个顶点添加到 300 个其他顶点。它做了更多的事情,但这是简单的描述。我添加了这个提到的 300 的工作负载只是为了测试。

如果我一个接一个地运行查询 300 次,则需要将近 3 分钟才能完成并创建 90.000 条边(300 x 300)。

我很担心,因为如果我有 60.000 个用户同时使用我的应用程序,他们可能会在 2 分钟内使用此查询创建 90.000 个边,而同时 60.000 个用户在我的情况下并不多。如果我同时拥有 100 万用户,我将需要许多服务器满负荷运行,这超出了我的预算。

然后我注意到,当我的测试执行时,CPU 没有显示太多活动,我不知道为什么,我不知道数据库内部是如何工作的。所以我认为也许更真实的情况是同时调用我的所有查询,因为当我尝试测试时,真实用户会发生这种情况ConcurrentModificationException

据我了解,发生此错误是因为同时在 2 个查询中读取或写入边或顶点,这在我的应用程序中可能发生很多,因为所有用户顶点都在更改与相同 4 个顶点的连接一直以来,这种“碰撞”将一直在发生。

我正在本地使用 gremlin 服务器 3.4.8 进行测试,使用带有 Node.js 的套接字进行连接。我的计划是在 AWS Neptune 投入生产时使用它作为我的数据库。

我能做些什么来恢复希望?这个主题肯定有一些我不知道的非常重要的事情,因为我不知道图形数据库在内部是如何工作的。

编辑

我使用“指数退避”方法实现了一个逻辑来在收到错误时重试查询请求。它修复了 ConcurrentModificationException,但 Gremlin Server 在同时发送多个查询时存在很多问题,这表明 Gremlin Server 完全不支持多线程并且不稳定,我们应该尝试在其他 Gremlin 兼容数据库中使用多线程作为回应说。我遇到了查询返回的数据中的随机不一致以及 NegativeArraySize 和来自数据库的其他随机内容等错误,请注意这一点,不要浪费时间认为您的代码可能像发生在我身上一样被窃听。

标签: gremlintinkerpoptinkerpop3gremlin-serveramazon-neptune

解决方案


虽然 TinkerPop 和 Gremlin 试图提供与供应商无关的体验,但他们实际上只在其界面级别这样做。因此,虽然您可能能够在 JanusGraph、Neptune、CosmosDB 等中运行相同的查询,但您可能会发现性能存在差异,具体取决于查询的性质和相关图能够优化的程度那个查询。

对于您的情况,请在本地运行测试时考虑使用 TinkerGraph。TinkerGraph 是一个没有事务能力的内存图,并且没有被证明是线程安全的写入。如果您对其应用繁重的写入工作量,我可以设想ConcurrentModificationException很容易生成。现在考虑 JanusGraph。如果您已经用它测试了繁重的写入工作量,您可能会发现TemporaryLockingException如果您的模式需要唯一的属性键并且必须修改您的代码以使用指数退避进行事务重试,您会遇到大量错误。

这里的要点是,如果您的目标图是 Neptune,并且您已经测试了遍历的正确性并且现在担心性能,那么可能是时候在 Neptune 上进行负载测试以查看那里是否出现任何问题。

我很担心,因为如果我有 60.000 个用户同时使用我的应用程序,他们可能会在 2 分钟内使用此查询创建 90.000 个边,而同时 60.000 个用户在我的情况下并不多。如果我同时拥有 100 万用户,我将需要许多服务器满负荷运行,这超出了我的预算。

您将需要制定一个现实的测试计划。60,000 名用户是否都同时按下“提交”来触发这个查询,真的会发生什么吗?还是更有可能您有 100,000 名用户正在阅读,也许每半秒就有三个用户碰巧点击“提交”。

您的图形增长率似乎相当高,并且您在此处描述的预期使用情况将很快将您的图形置于数十亿边的类别中(更不用说您可能拥有的任何其他写入)。您是否在具有数十亿条边的图上测试了您的读取工作负载?你在海王星上明确测试过吗?您是否考虑过如何维护数十亿的边图(例如,在需要新功能时更改架构,确保其正确增长等)?

所有这些问题都是修辞性的,只是为了让你思考你的方向。祝你好运!


推荐阅读