multithreading - 在多线程上下文中使用带有生菜的 Spring-Data-Redis 的 OutOfDirectMemoryError
问题描述
我们使用spring-data-redis
抽象spring-cache
并lettuce
作为我们的 redis 客户端。此外,我们在某些方法上使用多线程和异步执行。
示例工作流程如下所示:
Main-Method A (main-thread) --> 调用 Method B ( @Async
),这是一个代理方法,能够在另一个线程中异步运行逻辑。--> 方法 B 调用方法 C,即@Cacheable
. Annotation 处理对我们的 redis-cache的@Cacheable
读/写。
有什么问题?
Lettuce
is Netty
-based 依赖于DirectMemory
. 由于@Async
我们程序的性质,我们有多个线程同时使用LettuceConnection
(因此Netty
)。
按照设计,所有线程都将使用相同的 (?)Netty
共享DirectMemory
. 由于 a 显然太小了,当有太多线程访问时,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
. 计算出的实际可用内存为 4GBMaxDirectMemorySize
可能是保守的方式。这可能是问题的一部分。
问题的潜在解决方案
- 增加
MaxDirectMemorySize
JVM --> 但我们不确定这是否足够 - 配置
Netty
不使用DirectMemory
(noPreferDirect=true
) -->Netty
然后将使用堆,但是如果这会使我们的应用程序太慢,如果Netty
内存太少,我们是不安全的 - 不知道这是否是一个选项,甚至会使问题变得更糟:配置
Lettuce
为shareNativeConnection=false
--> 这将导致与 redis 的多个连接
我们的问题是:我们如何以正确的方式解决这个问题?
我很乐意提供更多关于我们如何设置应用程序配置的信息(application.yml、LettuceConnection 等),如果其中任何一个有助于解决问题的话。
解决方案
感谢那些在:https ://gitter.im/lettuce-io/Lobby我们得到了一些关于如何解决这些问题的线索。
MaxDirectMemorySize
正如怀疑的那样,考虑到总可用内存,10M过于保守。
建议是增加这个值。由于我们实际上并不知道需要多少内存Netty
才能更稳定地执行,因此我们考虑了以下步骤。
首先:我们将通过设置禁用Netty
的首选项。然后将使用堆缓冲区。MaxDirectMemory
noPreferDirect=true
Netty
第二:Netty
然后我们将监控在操作期间将消耗多少堆内存。这样做,我们将能够推断出Netty
.
第三:我们将取平均内存消耗值并将其设置为“新” ,方法MaxDirectMemorySize
是在 JVM 选项中设置它-XX:MaxDirectMemorySize
。然后我们将通过设置重新启用Netty
使用。DirectMemory
noPreferDirect=false
第四:监控日志条目和异常,看看我们是否仍然有问题,或者这样做是否有效。
[更新]
我们从上述步骤开始,但意识到该设置noPreferDirect=true
并不能完全阻止 netty 使用 DirectMemory。对于某些用例(nio-Processes)Netty
仍然使用 DirectMemory。
所以我们不得不增加MaxDirectMemorySize
.
现在我们设置以下 JAVA_OPTS -Dio.netty.noPreferDirect=true -XX:MaxDirectMemorySize=100M
。这可能会解决我们的问题。
推荐阅读
- django - 使用字符串字段 (CharField) 通过外键关联模型
- angular - 如何编写保护以防止用户在 Angular 6 中丢失表单数据?
- ios - 故事板转场目的地不是预期课程
- git - 如何让新的樱桃采摘分支被推上审查?
- c - 如何修复“未分配重新分配的指针”错误
- javascript - 如何使 Ember 计算属性依赖于变量的所有后代属性?
- css - 如何在响应式类中正确格式化 href?
- reactjs - 在安装了 react-redux 和 redux 模块的连接的反应路由器中无法解析模块“react-redux”
- python-sphinx - sphinx autodoc 在 readthedocs 上创建空白页面,但在本地正确包含模块文档字符串
- python - 搜索字符串中两个分隔符之间的字符