Storage engine
Cassandra使用一种类似于“日志结构合并树”(Log-Strcutured Merge Tree)的存储结构,不像传统关系型数据库那样使用”B-Tree”。Cassandra避免Read-before-write,特别是在大型分布式系统,Read-before-write会对读性能和其他方面造成巨大的潜在因素;为了避免Cassandra的大多数写操作使用了read-before-write,存储引擎在内存中聚合(groups)了inserts和updates,然后时不时以附加的模式将写数据到磁盘中,一旦写入磁盘,数据将不可变并且不可重写。读取数据需要结合这些不可变循序写入的数据以便发现正确的查询结果;在写入之前你可以使用LightWeight transactions来检查数据的状态。然而,这个功能被推荐有限使用;
如何写入数据
写操作发生时,Cassandra先将数据写进内存中的数据结构memtable,同时追加到磁盘中的commitlog中,memtable内容超出指定容量后会被放进将被刷入磁盘的队列(Memtable_flush_queue_size 配置队列长度),若将被刷入磁盘的数据超出了队列长度,Cassandra会锁定写,并将内存数据刷进磁盘中的SSTable,之后commitlog被清空;
如何维护数据
Compaction:compaction将数据的所有版本集中在一起,根据timestamp得到最新的数据,其他老数据标记tombstone以待删除。
Compaction strategies:(略)
如何更新数据
Cassandra视每一条新行为一个upsert,如果已经存在相同主键的行,则视为对已存在行的更新;(返回时间戳最新的数据行)
如何删除数据
Cassandra视delete为一个insert或者upsert,通过对数据添加一个tombstone,tombstone通过Cassandra的写操作写入一个或者更多的节点的SSTable。tombstone拥有一个内置的expiration date/time(终结时间),时间一到就会通过compaction进程进行删除。同样地,你也可以通过为Cassandra记录行列设置一个time-to-live值。
Deletion in a distributed system:在多节点集群中,Cassandra在超过两个节点存储数据的备份,这防止了数据的丢失,但也复杂化了删除进程。如果一个节点接收到一个delete数据的命令它会在本地存储起来,tombstone会指定特定的数据记录然后传递tombstone到其他包含这条记录的备份的节点。但如果一个备份节点在那个时候反应迟钝没办法马上接收到tombstone,那么它就依然会包含pe-delete version of the record.如果在哪个反应迟钝的节点恢复前这个tombstone record已经在其他集群中都删除了,那么Cassandra在那个节点中就会视这个记录为一条新纪录,并且传播给其他节点,这样的数据就叫做zombie(行尸走肉)。为了防止这种现象,Cassandra为每个tombstone提供了一个grace period,其目的是给反应迟钝的节点时间去恢复以致能正常的处理tombstone。如果一个客户端在grace period期间向tombstone record写了一句新的update,Cassandra会重写tombstone。如果有客户端在grace period期间对该记录发送读请求,Cassandra会忽视tombstone并且尽可能从其他备份检索record;当反应迟钝的节点恢复了,Cassandra会利用hinted handoff恢复节点down掉时节点丢失的数据库变化,Cassandra不能恢复在grace period期间tombstone的变化。但如果直到grace period结束后节点还没有恢复的话,Cassandra可能会跳过这个deletion。
索引是如何存储和更新的
索引会影响性能,在创建时需要结合业务考虑,更好的解决方案可以考虑:create a materialized view or additional table ;
如何读取数据
首先检查Bloom Filter,每个SSTable都有一个BloomFilter,用以在任何磁盘IO前检查请求PK(primary key)对应的数据在SSTable中是否存在;BF可能误判不会漏判:判断存在,但实际可能不存在,判断不存在,则一定不存在,则流程不会访问这个SSTable(红色);若数据很可能存在,则检查PartitionKey cache(索引的缓存),之后根据索引条目是否在cache中找到而执行不同的步骤:
- 在索引缓存中找到:1:从compression offset map中找到对应的数据的压缩块;2:从磁盘取出压缩的数据,返回结果集。
- 没有在索引缓存中:1:搜索Parttition summary (partition index的样本集)确定index条目在磁盘中的近似位置;2:从磁盘中SSTable内去除index条目;3:从compression offset map中查找拥有对应数据的压缩块;4:从磁盘取出压缩的数据,返回结果集。