在多线程上下文中使用Spring-Data-Redis与Lettuce发生OutOfDirectMemoryError。

问题描述 投票:0回答:1

我们使用的是 spring-data-redis 随着 spring-cache 抽象和 lettuce 作为我们的redis-client.此外,我们在一些方法上使用多线程和异步执行。

一个工作流的例子是这样的。

主方法A (main-thread) --> 调用方法B (@Async),这是一个代理方法,能够在另一个线程中异步运行逻辑。--> 方法B调用方法C,而方法C则是 @Cacheable. 该 @Cacheable Annotation处理对我们redis缓存的读写。

有什么问题?

LettuceNetty-基于的,它的工作原理是依靠 DirectMemory. 由于 @Async 程序的性质,我们有多个线程,使用了 LettuceConnection (因此 Netty)同时进行。

根据设计,所有线程将使用相同的(? Netty 它共享 DirectMemory. 由于显然太小 MaxDirectMemorySize 我们得到 OutOfDirectMemoryError当有太多线程在访问 Netty.

例子: io.lettuce.core.RedisException: io.netty.handler.codec.EncoderException: io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 8388352 byte(s) of direct memory (used: 4746467, max: 10485760)

到目前为止,我们发现了什么?

我们用 https:/docs.cloudfoundry.orgbuildpacksjava 并计算出 MaxDirectMemorySize 使用 https:/github.comcloudfoundryjava-buildpack-memory-calculator。.

这就导致了 MaxDirectMemorySize=10M. 实际可用内存为4GB,则计算出的内存容量为4GB。MaxDirectMemorySize 可能是太保守了。这可能是问题的一部分。

解决这个问题的可能办法

  • 增加 MaxDirectMemorySize 但我们不确定这是否足够。
  • 配置 Netty 不使用 DirectMemory (noPreferDirect=true) --> Netty 就会使用堆,但是我们不安全,如果这样会使我们的应用速度太慢,如果 Netty 贪多嚼不烂
  • 不知道这是否是一个选项,甚至使问题变得更糟:配置 LettuceshareNativeConnection=false --> 这将导致与redis的多个连接。

我们的问题是:我们如何用正确的方法解决这个问题?

我很乐意提供更多关于我们如何设置应用程序的配置(application.yml,LettuceConnection等)的信息,如果这些信息有助于解决这个问题。

multithreading asynchronous redis spring-data-redis lettuce
1个回答
0
投票

感谢大家的支持。https:/gitter.imlettuce-ioLobby。 我们得到了一些关于如何处理这些问题的线索。

正如怀疑的那样,10M MaxDirectMemorySize 考虑到总的可用内存,这个值过于保守。

建议增加这个值。由于我们实际上并不知道有多少内存 Netty 会需要更稳定的表现,我们想到了以下步骤。

首先,我们将禁用 我们将禁用 Netty的偏好。MaxDirectMemory 通过设置 noPreferDirect=true. Netty 就会使用堆缓冲区。

其次,我们将监控堆内存的使用量。 我们将监控有多少堆内存。Netty 在运行过程中会消耗多少内存。这样,我们就可以推断出一个平均的内存消耗量。Netty.

第三,我们将取平均内存消耗值,并将其设为 "新"。 我们将采取平均内存消耗值 并将其设置为 "新" MaxDirectMemorySize 通过在JVM选项中设置 -XX:MaxDirectMemorySize. 然后我们将重新启用 Netty 来使用 DirectMemory 通过设置 noPreferDirect=false.

第四,监控日志和异常情况。 监视日志和异常情况,看看我们是否还有问题 或者说这是否成功了。

© www.soinside.com 2019 - 2024. All rights reserved.