0

我正在编写一个应用程序,它通过 Spring Data 将大量对象存储到 MongoDB 中MongoTemplate。为了避免同步,我MongoTemplate为每个线程创建了一个单独的线程。事实上,每个线程都拥有它自己的所有东西,以避免同步。

应用程序处理用户与网页交互时生成的事件。因此,来自特定用户的事件需要按顺序处理,而跨多个用户的事件可以并行处理。该应用程序当前由 N 个管道和一个负载均衡器组成,该负载均衡器根据 userId 的哈希/mod 将事件分发到管道。在管道结束时,使用 Spring Data MongoDB 模板将数据写入 MongoDB。

这个单一进程每秒能够处理 2500 个事件。但是,我观察到线程之间存在显着的争用(以每秒 2500 个事件的速率,任何阻塞都变得相当严重)。所有在访问同步缓存的 ClassTypeInformation 领域。

不幸的是,MongoTemplate使用ClassTypeInformation将缓存存储在同步地图中。因此,无论我如何尝试,将数据写入 MongoDB 总是会在我的工作线程之间发生这种争用。

我认为ClassTypeInformation应该将其转换为 bean,以便可以在用户需要时提供。考虑到这一点,将消除多个线程之间的争用。

有谁知道为什么这被实现为静态而不是普通的 Spring bean?是否有任何计划进行此更改?

4

1 回答 1

0

不,没有计划。出于多种原因:ClassTypeInformation是一个值对象,而不是可注入的。必须非常频繁地动态创建实例。用 Spring 配置它的实例根本没有意义,因为通常必须在遇到某种情况时创建实例Class,需要检查它并维护和解析泛型信息。使用静态工厂确保我们可以对对象创建进行改进,而无需修改所有客户端。

我们已经应用了大量的基准测试和调整来消除最新版本中的一些性能瓶颈,ClassTypeInformation甚至从未接近出现在探查器分析中。

一般来说,我会在深入研究低级内部之前开始:

  • 您认为首先需要开始并行化插入的原因是什么。MongoTemplate.insertAll(…)如果您想利用我们的对象到文档映射工具,这基本上是您可以将对象插入 MongoDB 的最快方式。引入并行性实际上可以减慢速度,因为首先需要同步。
  • 为什么你认为创建单独MongoTemplate的实例可以改善事情?MongoTemplate是线程安全的,因此可以在线程之间共享。
  • 您是否考虑过插入将对象手动转换为 的自定义转换器DBObject?默认情况下,我们必须使用反射将前者转换为后者,这当然是有代价的。
  • 你真的需要首先从对象开始吗?有时从输入源读取的数据可以直接映射到DBObjects 中,这允许您完全绕过对象到文档的映射。

一般来说,使用数据访问 API 的所有便利通常与获得大部分性能的目标背道而驰。与其坚持便利性并尝试将所有内容并行化,不如摆脱一些便利性以避免昂贵的代码路径通常更容易。

如果您确实发现默认设置有任何问题,我们很乐意提交一份错误报告,其中包含您发现的一些证据(可执行测试用例等),以了解我们可以改进的地方。但我认为从简单开始而不是一开始就太聪明是有帮助的。

于 2015-05-22T14:14:16.607 回答