在卡桑德拉的大量插入内存不足

时间:2012-03-29 07:34:19

标签: c# cassandra

我正在尝试插入具有大列值(1-25Mb)的数据,几秒钟后,我的一个节点死亡,无论是通过抛出OOM还是陷入无休止的GC循环。

它通常会尝试刷新CF,但之后它会说无法减少堆使用量,因为没有脏列系列

由于日志建议我减少memtable / cache size,我试图弄清楚是什么耗尽了所有这些内存以调整我的设置,所以我运行了nodetool flush / invalidaterowcache / invalidatekeycache然后通过jconsole触发了GC。

不幸的是,即使服务器处于空闲状态,我的内存使用率仍然很高(> 60%)。

所以,我的问题是为什么插入大值时服务器内存不足?而且,为什么服务器不给予回忆?

修改

我做了一个堆转储并且堆满了byte [],主要由org.apache.cassandra.io.sstable.IndexSummary$KeyPosition引用。

我不明白这是怎么可能的,因为一切都应该被刷新。

2 个答案:

答案 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位应用程序也存在碎片问题,但由于虚拟内存要大得多,因此在遇到实际的碎片问题之前,首先要对内存进行分页(变得非常慢)。

如果这确实是问题(您可以使用VMMapWinDbg直观地检查碎片),您可以通过创建大型字节池并重用自己的池来解决它,从而防止碎片化

答案 1 :(得分:2)

我用MAT调查了堆转储,结果发现OutOfMemory发生了,因为Thrift使用了大量内存。

由于我必须为列值传输大块数据,因此我将这些设置更改为128,以“安全”:

  • thrift_framed_transport_size_in_mb
  • thrift_max_message_length_in_mb

但事实证明,Thrift每个接收线程分配一个byte[2 * thrift_max_message_length_in_mb],我有三个。所以我只使用768Mb接收缓冲区...

将设置更改为32修复了我的问题。