在Cassandra 2.x 版本及更早版本的时候,我经常建议用户单节点规模数据不要超过1T,到Cassandra 3.x 之后我又建议用户单节点规模不要超过4T。为什么会有这些变化,其实是跟基础设施的发展有关系的。一方面是随着SSD硬盘的越来越廉价,大部分用户使用SSD替换了机械硬盘提升了磁盘随机读写能力。但更重要的时,内存也变得廉价了,很多用户从之前单节点的32G内存升级到了128G,使得用户的JVM可以配置更大的堆。更大的堆意味着着可以存放更多的元数据,意味着可以存放更大的数据。
现在我们来分析下Cassandra 堆里面存放了什么信息。为了执行读取,Cassandra数据库在堆内存中维护以下组件:
1.Bloom filters
2.Partition summary
3.Partition key cache
4.Compression offsets
5.SSTable index summary
5.SSTable meta info
此元数据驻留在内存中,也可以认为存放在堆内永久代,并与总数据成比例。一些组件与总内存的大小成比例地增长。除此之外,平时读写和压缩任务也会产生对象消耗堆内存。另外还有memtable(可配置中堆内或者堆外,4.x版本默认放在堆外) 和 Cache类(Key Cache,Row Cachhe)。
至此,我们基本分析出来,Cassandra的内存压力随着数据量的增大而增大。所以就有了上面的结论,32G的内存建议不超过1T,128G的内存建议不超过4T。那么问题来了,如果我有1T的内存是不是单节点容量可以达到32T呢?理论上是可以,但实际上会怎么样?实际上跟垃圾回收算法有关系,Cassandra 2.x的时候默认是CMS垃圾回收算法,一般建议堆最大不超过14G,因为超过14G,每次垃圾回收的时候性能下降,标记大量的对象导致GC暂停陡增。同样Cassandra 3.x 之后默认垃圾回收算法是G1,它一般建议最大堆不超过64G,如果超过这个值,GC暂停也是飙升到秒级以上,会严重影响业务。所以这个时候就算你有更大的内存,也会因为GC 暂停问题,不能配置足够大的堆来支撑更大的数据。
所以,我们建议用户根据内存及堆大小来评估单节点的最大容量。换算每TB数据需要消耗32G的内存。不过也有特例,如果使用时TWCS(时间窗压缩策略),因为每个sstable的生命周期只被Compact一次,后续不会参与Compact,通过又关闭读修复,所以会大大减少Compact时产生的对象,所以我建议用户在此类场景下,单节点数据量可以提高1倍。
尽管如此,不少用户还是希望单节点可以容纳更大的数据,由此降低硬件存储成本,实现纵向扩容的能力。特别是IOT领域的用户,半导体/电力/能源/物流/新能源汽车等,产生的数据量是特别巨大的,往往都是数十PB级别。于是这类客户往往选择商业的Azul Prime JDK来满足此类需求,Azul Prime的C4垃圾回收器不受堆大小敏感,在堆配置成TB级别,依然可以使垃圾回收暂停控制在毫秒级别。所以,如果使用Azul的JDK,可以不受64G堆大小的限制,从而配置成1T以上的堆(最大号称可以配置成8T),也就是单节点支撑32T(TWCS 64T)的数据,由此可以节省75%的节点数。当然我们也不建议用户配置更大的节点,因为数据量再上去扩容的时间会变得比较久。当然同样的原理试用于Hadoop namenode/es/solr等。
最后放个表格对比:
回收器 | 特点 |
Azul C4 | 适应各种场景,配置简单,高吞吐低延迟,GC停顿毫秒级,支持最大堆内存8TB。通过了Cassandra和DataTax认证,并进行了优化,以提高Cassandra的性能。单节点容量理论上不受限制,不过最好不超过32T。 |
G1 | 适应高吞吐优先,满足简单负载,配置简单。适合14G-32GB的堆大小。G1比CMS对更大的堆执行得更好,因为它首先扫描堆中包含最多垃圾对象的区域,并在运行时压缩堆,而CMS在执行垃圾收集时停止应用程序。单节点容量理论上不超过4T。 |
CMS | 适应14G以下小的堆,优化参数非常多,得有时间和专业知识手动调整和测试。单节点容量理论上不超过1T。 |
ZGC | JDK17支持,JDK11上面目前实验性质,Cassandra还不适配 |
谢谢阅读!
如需Cassandra / Azul JDK 支持,加V:milk670661 备注:51CTO Cassandra