在MappingMongoConverter中使用ClassTypeInformation.from(..)引入了很多线程争用

时间:2015-05-22 04:59:58

标签: spring-data spring-data-mongodb spring-mongodb

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

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

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

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

我认为应该将ClassTypeInformation转换为bean,以便在用户满足时可以提供。允许这样做,将消除多个线程之间的争用。

有谁知道为什么这个实现为静态而不是普通的Spring bean?有没有计划进行这项改变?

1 个答案:

答案 0 :(得分:0)

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

我们已经应用了大量的基准测试和调整来删除最新版本中的一些性能瓶颈,ClassTypeInformation甚至从未在概要分析器中显示出来。

一般来说,在开始进入低层内部之前我会先行开始:

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

一般来说,使用数据访问API的所有便利性通常会反对获得大部分性能的目标。它不是坚持方便并试图并行化所有内容,而是通常更容易摆脱一些方便,以避免代价高昂的代码路径。

如果您确实发现默认设置存在任何问题,我们很乐意为您提供一些错误报告,其中包含您的调查结果(可执行测试案例等),以了解我们可以改进的内容。但我认为从一开始就简单而不是试图过于聪明是有帮助的。