我正在尝试插入具有大列值(1-25Mb)的数据,几秒钟后,我的一个节点死亡,无论是通过抛出OOM还是陷入无休止的GC循环。
它通常会尝试刷新CF,但之后它会说无法减少堆使用量,因为没有脏列系列。
由于日志建议我减少memtable / cache size,我试图弄清楚是什么耗尽了所有这些内存以调整我的设置,所以我运行了nodetool flush / invalidaterowcache / invalidatekeycache
然后通过jconsole触发了GC。
不幸的是,即使服务器处于空闲状态,我的内存使用率仍然很高(> 60%)。
所以,我的问题是为什么插入大值时服务器内存不足?而且,为什么服务器不给予回忆?
我做了一个堆转储并且堆满了byte [],主要由org.apache.cassandra.io.sstable.IndexSummary$KeyPosition
引用。
我不明白这是怎么可能的,因为一切都应该被刷新。
答案 0 :(得分:2)
在我看来,你遇到了infamous memory fragmentation问题。我不确定Cassandra是否会消除一些碎片问题,但一般来说,在.NET和可能的任何Windows程序中,都会遇到这种问题。
当您选择85000字节以上的任何内容时(是,奇数,但它就是这样),对象存储在大对象堆中。 LOH只在第2代获得GC,但更糟糕的是,它从未压缩。原因部分是由the way the OS is implemented造成的。
结果:当您存储2MB,5MB,3MB,2MB,3MB和2MB对象的对象时,您可能有4MB空闲。但是如果你然后尝试创建一个3MB的新对象,它就不能放在那里因为碎片(2个2MB的孔)并移动到堆的顶部。最终,这个用完了。所以:可以有足够的可用内存,但是由于这种碎片,无论如何都会得到一个OOM 。
此问题主要出现在64位(WOW64)和32位Windows上的32位x86应用程序上。 64位应用程序也存在碎片问题,但由于虚拟内存要大得多,因此在遇到实际的碎片问题之前,首先要对内存进行分页(变得非常慢)。
如果这确实是问题(您可以使用VMMap和WinDbg直观地检查碎片),您可以通过创建大型字节池并重用自己的池来解决它,从而防止碎片化
答案 1 :(得分:2)
我用MAT调查了堆转储,结果发现OutOfMemory发生了,因为Thrift使用了大量内存。
由于我必须为列值传输大块数据,因此我将这些设置更改为128,以“安全”:
但事实证明,Thrift每个接收线程分配一个byte[2 * thrift_max_message_length_in_mb]
,我有三个。所以我只使用768Mb接收缓冲区...
将设置更改为32修复了我的问题。