https://docs.datastax.com/en/cassandra-oss/3.0/cassandra/dml/dmlAboutReads.html
https://blog.csdn.net/FS1360472174/article/details/55005335
读需要从active memtable和多个SSTables中联合查询结果。
读流程如下所示:
1.Check the memtable
2.Check row cache, if enabled
3.Checks Bloom filter
4.Checks partition key cache, if enabled
4.1如果找到了:直接找 compression offset map
4.2如果没找到:checks the partition summary - access partition index - compression offset map
5.Locates the data on disk using the compression offset map
6.Fetches the data from the SSTable on disk
读请求流程图 行缓存和键缓存请求流程图
MemTable
如果memtable有目标partition的数据,这个数据会从memtable中读出来,并且和从SSTables中读出来的数据进行merge。SSTable数据的访问方式接下来会介绍。
Row Cache
一般来说,当需要读取的大部分数据都存放在内存中时,速度是非常快的。操作系统的page cache能显著提升读性能的,row cache 对于读占比高(如读操作占95%)的应用有一定性能提升,但对于写占比高的系统,Row Cache是禁用的。因为如果开启了row cache,就会将一部分写入到磁盘SSTables的数据又存储一份在内存中(不是指memtable)。在Cassandra2.2+,row cache 存储在堆外内存(off-heap memory是JVM中的概念),该内存使用了全新的实现方式来避免垃圾回收对JVM造成的压力。存放在row cache占用的内存大小可配置。当cache满的时候,row cache使用LRU(least-recently-userd)进行内存回收。
row cache的大小是可以配置的,可以配置该cache最多能存放多少rows。这个功能很有用,比如当查询最近的十条数据( "Last 10 Items")会很快。如果开了row cache。就会先从row cache中读取目标数据,节省了两次从磁盘seek查找数据。存储在row cache中的数据是SSTables中频繁被访问的数据。当数据存储到row cache中后,就可以被后续的查询访问到了。row cache不是write-through。当对某一行进行写入操作时,这行的cache就会失效,但不会把这次的写入缓存到cache中,直到这行被读取时,才将该行放到cache。类似的,如果一个partition更新了,整个partition的cache都会被移除。
若目标的数据在row cache中找不到,就会去检查Bloom filter。
Bloom Filter
首先,Cassandra检查每个SSTable的Bloom filter,去确定哪个SSTables中有可能有请求的分区数据。Bloom filter是存储在堆外内存(off-heap memory)。每个SSTable都有一个关联的Bloom filter。通过SSTable的Bloom filter可以确定的得出:该SSTable没有包含的特定的分区数据。同样也可以得出该分区数据存在在SSTable中的概率。通过缩小key的范围,它可以加速partition key的查找过程。然而,因为Bloom filter是一个概率函数,所以可能会得到错误的结果,也就是说,如果Bloom filter识别出该STTable可能有此数据,也不一定真的有。
如果Bloom filter不能够排除此SSTable(也就是说BF得等到的结果是可能有此数据),就会检查partition key cache.
Bloom filter 每10亿partitions数据大约占用1~2GB 内存。在极端情况下,如果一个partition一行,这样的话单机就有数十亿的entries。Bloom filter可以占用的总内存大小是可调节的,如果想用内存来换取性能。
Partition Key Cache
如果开启了partition key cache,会将partition的索引(index)存储在堆外内存中(也就是把接下来讲的Partition Index的一部分放在内存中的意思)。key cache使用的内存空间较小,该大小可配置。在读的过程中,若命中了cache,就节省了一次磁盘的seek(因为如果没命中需要找partition summary,然后到partition index文件seek)。如果在key cache中找到了该partition key,就直接到compression offset map中查找磁盘上对应的compressed block。partition key cache在冷启动后,性能不佳,因为key cache中是空的,但热了之后,性能就会有很大提升了。如果一个节点上的内存有限,可以限制保存在key cache中的partition key数目。如果在key cache中没有找到对应的partition key。就会去partition summary中去找。
partition key cache 大小是可以配置的,即存储在key cache中的partition keys数目。
Partition Summary
partition summary 是存储在堆外内存的结构,存储一些partition index(接下来讲的那个)的采样值(我理解就是partition index文件的索引)。partition index包含了所有的partition keys。但partition summary从每X个keys中取样,然后将每X个key map到index 文件的offset中。如partition summary设置了20keys进行取样。它就会存储第一个key以及对应的partition index 文件的offset,第20th 个key以及对应partition index 文件的offset,以此类推。(当需要找某一个partition key时,就可以根据这个映射关系找到前一个offset,比如要找第45个key,那就可以确定范围:[第40个key对应的partition index的offset, 第60个key对应的partition index的offset],然后就去partition index文件的这个范围开始找)。尽管并不知道该partition key(在partition index文件中)的具体位置,但partition summary可以缩短找到该partition 数据位置的时间(因为如果没有这个summary的话,就需要从头遍历一遍partition index文件来找对应的key的index)。当找到了该partition key值可能的范围后,就会去找partition index。
通过配置取样频率,可以在内存和性能之间权衡,当partition summary包含的数据越多,使用的内存越多。可以通过表定义的index interval属性来改变样本频率。固定大小的内存可以通过index_summary_capacity_in_mb属性来设置,默认是堆大小的5%。
Partition Index
partition index文件存放在磁盘中,其中存储了所有partition keys到(Compression offset map中的)offset的映射。如果partition summary 已经得到了需要查找的partition keys范围,现在就是根据这个范围值来查找目标partition key(的offset)。需要进行单次seek和顺序读(seek到范围的开始offset,然后顺序读)。根据找到的offset信息,就直接到compression offset map中查找磁盘上对应的compressed block。如果走到了查询partition index这步,那么则需要seek两次磁盘才能找到目标数据。(一次是seek partition index文件,一次是seek SSTable;但如果在Partition Key Cache中就找到了该key,就不需要访问partition index文件了,则只需要一次磁盘seek。)
Compression offset map
compression offset map存储了许多指针,指向磁盘的位置。存储在堆外内存,可以被partition key cache或者partition index访问。当通过compression offset map定位到磁盘中的数据位置,就可以从正确的SStable(s)中取出 compressed partition data。就能返回查询结果。
注: 在一个partition里,所有的row查询的代价是不同的。在一个partition的前面的行的查询代价更小,应为没有必要执行partition-level的index。
数据每增长1TB,compression offset map 就增长1~3GB。因为数据越多,压缩块的数量也就越多,compression offset map 就会越大。Compression 默认是开启的,即使通过compression offset map会消耗CPU资源。开启compression使得页缓存更加的高效,通常来说是值得的。
读是如何影响写的
使用哪种compaction 策略是可配置的,compaction 策略会影响读的性能。如果行被频繁更新那么使用SizeTieredCompactionStrategy或者DateTieredCompactionStrategy可能会产生数据碎片;但LeveledCompactionStrategy(LCS)可以防止数据碎片化。
网友评论