Cassandra 写机制

1. Cassandra写流程

Cassandra的写入操作主要包含以下3个步骤:

(1)记录数据到commit log

(2)写数据到memtable(一般情况下一个column family有一个memtable)

(3)当commit log的size达到阀值或者memtable的size达到阀值时,将数据flush到SSTable中,flush完成后清空commit log和memtable

Cassandra 写机制_第1张图片
Cassandra写操作

(1)对于一个写操作,Cassandra首先将客户端提交的数据和操作记录到commit log中,此操作是为了提升可靠性(起到数据恢复的作用)。

(2)接着Cassandra将数据写入到内存表memtable中,memtable中组织的数据按照key排序。当memtable中的数据大小到达一定限制后,Cassandra才会将memtable中的数据批量刷新到一个SSTable中。这种机制,相当于缓存写回机制(Write-back Cache),优势在于将随机IO写变为顺序IO写, 大大降低了写操作对于存储系统的压力。

(3)SSTable一旦完成写入,就不可变更,只能读取。因此对于Cassandra来说,可以认为只有顺序写,没有随机写操作。

(4)由于SSTable的只读性,因此同一个Column Family的数据可能存储在多个SSTable中,如果一个Column Family中的数据量很大的时候,那么Cassandra需要合并读取多个SSTable和memtable,导致查询效率严重下降。为此Cassandra引入了BloomFilter,每个SSTable都拥有一个BloomFilter。BloomFilter是一个存储在内存中的数据结构,它能够快速判断某个给定的key是否位于某个SSTable中,因此,Cassandra能够快速定位某个key对应的SSTable。

(5)为了避免大量SSTable带来的性能影响,Cassandra通过一种称为压缩(Compaction)的机制来处理随着时间推移而不断膨胀的SSTables。Cassandra定期将多个SSTable合并成一个SSTable,由于每个SSTable中的数据均是有序的,因此只要做一次合并排序就可以完成该任务,这个代价是可以接受的。

(6)Cassandra的数据存储目录下,可以看到三种类型的文件,文件名的格式类似于:

         Column Family Name-序号-Data.db

         Column Family Name-序号-Filter.db

         Column Family Name-序号-index.db

其中Data.db文件是SSTable数据文件,SSTable是Sorted Strings Table的缩写,按照key排序后存储key/value键值字符串。index.db是索引文件,保存的是每个key在数据文件中的偏移位置,而Filter.db则是Bloom Filter算法生产的映射文件。

2. Cassandra Compaction Strategies

Cassandra主要支持三种数据压缩策略,Size Tiered Compaction Strategy(STCS)Leveled Compaction Strategy(LCS),Time Window Compaction Strategy(TWCS)。

2.1 Size Tiered Compaction Strategy(STCS)

当具有类似大小的SSTable的数目达到阀值(默认为4)时,STCS会将这些SSTables合并成一个新的SSTable,当这些新的SSTable数量增加到阀值,STCS会将他们合并成更大的SSTable。

优点:写占比高的情况下压缩效果好。

缺点:(1)将读操作变慢了,因为根据大小来进行合并的过程并不会对数据进行分组,这样使某个特定行的多个版本很有可能分散在多个SSTable中。

(2)浪费存储空间。由于SSTable是经过一段时间后合并的,一个被删除的记录,它的老版本可能一直存储在旧的SSTable中,直到新的合并出现才会将这些记录删除。因此对于一些经常进行删除操作的系统,其浪费的的空间是很大的。

(3)压缩时占用大量的空间。随着时间的推移,系统中会出现一些很大的SSTable。这时如果需要合并四个很大的SSTable,压缩占用的存储空间就是这四个SSTable大小的总和。

2.2 Leveled Compaction Strategy(LCS)

LCS将SSTable分层,每一层都拥有各自的SSTables。首先memtable flush数据到L0层,当L0层的SSTabel数量达到阀值(例如4)时,然后L0层4个的SSTabl会和和L1层的10个SSTable进行合并。从L1层开始,每一层的SSTable数量都是上一层的10倍,同时每个SSTable的默认大小为160MB。如果L1层合并后的数据量大于160MB*10,那么LCS会选择L1层的一个SSTable(合并后此SSTable会被删除),与L2层的SSTable进行合并。由于每个SSTable都是有序并且不相交的,因此从L2层也大约只需要选出10个SSTable来进行合并。

这样就解决了STCS出现的问题:

(1)由于每一层的各个SSTable中的数据都有序不相交,可以保证90%的读操作都在一个SSTable中完成,最坏情况是一个记录存在每一层,这样最坏情况下10TB数据也只需要读7层,也就是7个SSTable。

(2)最多只有10%的空间会被浪费。因为最坏的情况是该层的记录和完全存在在下一层中,而且每一层都是这种情况。也就是会所每一层都有10%(下一层数据是上一层的10倍)的数据时冗余的。

(3)在压缩合并操作的开销上,每次只会使用10倍于要压缩的sstable大小的空间。

适用条件:

对于一个更新操作和删除操作比较多的系统,或者读操作占比高的系统,使用分层压缩是比较合适的。因为这种系统会产生同一份数据的多个版本。但是由于这种压缩会在压缩中进行更多的IO操作,所以如果是一个主要是insert操作的系统,建议不要使用分层压缩方法。

2.3 Time Window Compaction Strategy(TWCS)

TWCS通过使用一系列的时间窗口将SSTables进行分组。在compaction阶段,TWCS在最新的时间窗口内使用STCS去压缩SSTables。在一个时间窗口的结束,TWCS将掉落在这个时间窗口的所有的SSTables压缩层一个单独的SSTable,在SSTable maximum timestamp基础上。一旦一个时间窗口的主要压缩完成了,这部分数据就不会再有进一步的压缩了。这个过程结束之后SSTable开始写入下一个时间窗口。

例如,从上午10点到上午11点,memtables flush到100MB的SSTables中。使用STCS策略将这些SSTables压缩到一个更大的SSTables中。在上午11点的时候,这些SSTables被合并到一个单独的SSTable,而且不会被TWCS再进行压缩了。在中午12点,上午11点到中午12点创建的新的SSTables被STCS进行压缩,在这个时间窗口结束的时候,TWCS压缩开始。注意在每个TWCS时间窗口包含不同大小的数据。

优势:用作时间序列数据,为表中所有数据使用默认的TTL。比DTCS配置更简单。

劣势:不适用于时间乱序的数据,因为SSTables不会继续做压缩,存储会没有边界的增长,所以也不适用于没有设置TTL(Time To Live)的数据。相比较DTCS,需要更少的调优配置。

参考:How is data written?

你可能感兴趣的:(Cassandra 写机制)