我们正在使用 spring-data-redis
与 spring-cache
抽象和 lettuce
作为我们的redis客户。另外,我们在一些方法上使用多线程和异步执行。
示例工作流如下所示:
主方法a(主线程)-->调用方法b( @Async
)它是一个代理方法,可以在另一个线程中异步运行逻辑。-->方法b调用方法c,即 @Cacheable
. 这个 @Cacheable
注解处理对redis缓存的读/写。
有什么问题吗? Lettuce
是 Netty
-它依靠 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.org/buildpacks/java/ 然后计算 MaxDirectMemorySize
使用https://github.com/cloudfoundry/java-buildpack-memory-calculator.
哪一个利兹 MaxDirectMemorySize=10M
. 具有4gb的实际可用内存 MaxDirectMemorySize
可能是保守的方式。这可能是问题的一部分。
问题的潜在解决方案
增加 MaxDirectMemorySize
但我们不确定这是否足够
配置 Netty
不使用 DirectMemory
( noPreferDirect=true
) --> Netty
然后将使用堆,但是如果这会使我们的应用程序速度过慢,那么我们是不安全的 Netty
对记忆来说太饥渴了
不知道这是否是一个选项,甚至使问题更糟:配置 Lettuce
至 shareNativeConnection=false
-->这将导致多个连接到redis
我们的问题是:我们如何以正确的方式解决这个问题?
我很乐意提供更多关于如何设置应用程序配置(application.yml、lettuceconnection等)的信息,如果其中任何一个有助于解决问题的话。
1条答案
按热度按时间svujldwt1#
感谢大家:https://gitter.im/lettuce-io/lobby 我们找到了一些解决这些问题的线索。
正如怀疑的那样
MaxDirectMemorySize
考虑到总的可用内存太保守了。建议增加这个值。因为我们不知道有多少记忆
Netty
要想表现得更稳定,我们考虑了以下步骤。第一:我们将禁用
Netty
的首选项MaxDirectMemory
通过设置noPreferDirect=true
.Netty
然后将使用堆缓冲区。第二:我们将监视堆内存的大小
Netty
在操作过程中消耗。这样,我们就可以推断出Netty
.第三:我们将取平均内存消耗值并将其设置为“new”
MaxDirectMemorySize
通过在jvm选项中设置它-XX:MaxDirectMemorySize
. 那我们就启用了Netty
使用DirectMemory
通过设置noPreferDirect=false
.第四:监视日志条目和异常,看看我们是否仍然有问题,或者这是否起到了作用。
[更新]我们从上述步骤开始,但意识到
noPreferDirect=true
不会完全阻止netty使用directmemory。对于某些用例(nio过程)Netty
仍然使用directmemory。所以我们必须增加
MaxDirectMemorySize
.现在,我们设置以下java\u选项
-Dio.netty.noPreferDirect=true -XX:MaxDirectMemorySize=100M
. 这可能会解决我们的问题。