cassandra权威指南读书笔记--读写数据


cassandra除了轻量级事务,不支持别的事务。cassandra是追加写,写的速度非常快。cassandra还有hint日志,这个数据库总是可写的,而且单个列的写操作是原子的。
hint并不是一定写在协调节点,一般是写在下线节点的某个非副本的邻居节点。
写一致性
ANY:写hint也算成功
ONE:写hint和memtable才算成功。

协调节点会根据keyspace的副本数确定哪些是副本节点,如果副本节点不够满足一致性级别,直接报错。多DC时,客户端发请求到协调节点,协调节点同时会转发请求到所有DC的一个协调节点。如果涉及别的DC的一致性级别,对应节点会响应结果给原协调节点。

commitlog文件名格式:CommitLog-<version>-<timestamp>.log的模式命名。
version是commitlog格式的一个整数。cassandra 3.0的版本提交日志的格式是6。org.apache.db.commitlog.CommitLogDescriptor可以根据cassandra版本查到commitlog版本。

SSTable
每个keyspace有一个目录,每个目录下面有对应的表的目录,目录名由表名+UUID组成的,UUID是用来区别不同schema的表,因为表结构可能会变。表的目录下面是SSTable。
SSTable包含多个文件,这些文件采用通用的命名规则:
<version>-<generation>-<implementation>-<component>.db
version是一个两字符序列,表示SSTable格式的主\次版本。可以在org.apache.io.sstable.Descriptor
类中了解不同的SSTable格式版本。
generation 是一个索引数,每次为一个表创建一个新的SSTable时,索引数就会递增。
implementation 是实现org.apache.io.sstable.format.SSTableWriter接口的一个引用。比如cassandra 3.0,这个值是“big",会引用org.apache.cassandra.io.sstable.format.big.BigFormat类中的”Bigtable 格式“
component包含多种,3.0为例:
*-Data.db
存储实际的数据的文件,cassandra备份只保留这些文件。
*-CompressionInfo.db
提供Data.db文件压缩相关的元数据,包含有关未压缩的数据长度,块偏移量和其他压缩信息的信息
*-Digest.adler32
包含*-Data.db文件的一个校验和
*-Filter
包含这个SSTable的布隆过滤器
*-Index.db
提供相应的*-Data.db文件中的行和列的偏移位置
summary.db:索引的抽样,用来加速读取的
Statistics.db:存储有关SSTable的统计信息,nodetool tablehistograms命令将使用这些信息。
TOC.txt:该文件存储对应SSTable 所有组件的列表

轻量级事务 LWT lightweight transaction
限制:
1、必须在一个分区下。
2、每个事务由一个读写组成,读后写。也叫比较和设置,只有比较成功才会完成设置。类似CAS。
3、事务失败,会提示失败,会返回尝试更新的值,可以选择重试或者撤销。比如当你期望的值和读到的值不一样。
4、不支持using timestamp
insert要用if not exist
update要用if x=y
LWT的客户端时,可以使用wasApplied()来看语句是否成功。
LWT还另外支持串行一致性:serial和local_serial。
如果在查询的时候,读取的数据是一个未提交事务的一部分的时候,它会根据串行一致性级别提交事务。

批处理
支持多个分区,限制:
1、批处理只能包含修改语句(insert,update,delete)
2、批处理具有原子性。如果一个批处理被接受,最终一定会全部成功,batchlog。(3.0之前是unbatchlog,没有batchlog)
3、一个批处理中,分区所有更新会独立完成,可能会批处理完成之前读道不同分区的修改结果。
4、批处理带LWT,只能是在一个分区内。
5、计数器修改只能用于一种叫计算器批处理的方式。计算器批处理只能包含计数器修改。
批处理(batchlog方式)可能会降低性能,带来GC压力。
批处理底层实现:
协调器接受了批处理请求后,会将批处理请求的副本发给2个节点,副本存在system.batchlog。然后协调节点执行完批处理中所有的语句后,会删除其它节点的batchlog。
如果协调器执行失败,每分钟,每个节点会检查是否有应该完成的批处理。检查的时候会检查batchlog的时间戳和超时时间,只有才超时时间之后的才会reply,这样是防止重放正在执行的批处理。超时可以通过“cassandra.batchlog.replay_timeout_in_ms”来设置,如果没有设置,默认值write_request_timeout_in_ms的两倍。如果reply成功,会删掉对应的batchlog。
发给2个节点batchlog,存储batchlog的节点的选择其实只是找若干个尽可能不在同一个机架上的节点,主要是为了可靠性。
总结:
如果batch log写入失败,那么批处理全部失败。
如果batch log写入成功,即使某个写没有成功,cassandra也会(在gc_grace_seconds之前)一直回放batch log,保证最终全部成功。
注意:
表的gc_grace_seconds配置会影响batch的回放。在回放batch时,会检查涉及的所有表的gc_grace_seconds,如果当前时间已经超出了其中某个表的gc_grace_seconds,则整个batch都不会回放直接删除。另外,如果表的gc_grace_seconds为0,会收到警告提示。
失败:默认50k,batch_size_fail_threshold_in_kb
告警:默认5k,batch_size_warn_threshold_in_kb
counter因为不是幂等操作,不支持原子性的batch
正常写和批处理写会有并发问题。
LWT 超时后,后台batchlog 和正常写得看下代码,应该是会导致直到gc_grace_seconds后不在重试。

如果读到的数据不一致,会返回时间戳最新的那一条数据。然后cassandra会在后台完成读修复。如果本节点过滤墓碑,墓碑时间超过gc_grace_seconds,那么返回给协调节点的时候,是不带墓碑数据,如果不一致,可能会出现僵尸数据。
一致性级别没有ANY。如果一致性级别是ONE,而且多副本数据不一致,会先返回第一个查询到的节点数据,再在后台触发读修复。

读请求和写类似,也是协调节点接受请求,然后再转发到别的DC,不过只有一个DC只会选一个最快的节点完全读,其他读摘要。如果摘要和完全读计算的摘要的结果一致,就直接返回完全读的结果。如果不一致,就会完成一个读修复。
单节点完全读查询:
1、行缓存
如果行缓存没有则
2、检查键缓存查找索引
3、检查memtable。***一个给定的表只有一个memtable***
4、检查SSTable。有很多特性优化SSTable的搜索:键缓存,布隆过滤器,SSTable索引和摘要索引。
a.用布隆过滤器确定请求的分区在不在给定的SSTable中,如果不在就不必搜索这个SSTable。
b.如果通过布隆过滤器检验,就检查键缓存。键缓存是个Map,key=SSTable的文件描述符和分区键的组合,value=SSTable文件中的偏移位置。
c.如果没在键缓存命中,使用磁盘上存储的二级索引找到这个偏移位置。第一级是分区摘要,用来得到第二级索引的偏移位置,然后在第二级索引(分区索引)中搜索分区键,从而得到分区键在SSTable中的偏移位置。
d.找到分区键的偏移位置,就开始读数据,一旦从所有的SSTable读完数据,取各个列的最新时间戳的值,然后合并SSTable和memtable的数据。所有的墓碑都会被过滤掉,只剩下去除掉墓碑后的数据。
c.如果开启行缓存,会把数据写到行缓存中。
e.返回结果给协调节点。
摘要读取和上面一样,只是增加一步计算摘要的结果,返回给协调节点的也是摘要。

布隆过滤器优化:可以为每个表设置bloom_filter_fp_chance属性来控制布隆过滤器报告的误报率,不过会增加额外的内存消耗。

读修复
实现:协调节点向所有的副本节点发出一个完全读请求。协调节点需要为每一列选个值合并,它会比较副本返回值,返回有最新时间戳的值。(每个副本返回值如果有墓碑,而且墓碑时间超过gc_grace_seconds,副本返回数据会过滤掉墓碑,没超过就会连墓碑一起返回。)如果时间戳也一样,会按照字典排序,选择最大的值。合并后的数据,就是返回给客户端的值。
读修复会根据一致性级别决定在返回客户端之前或者之后完成读修复,比如Quorum或者all,就会在返回给客户端之前完成。如果是one,大概率在返回客户端之后修复。对于给定的表,读操作是否会导致后台读修复的几率由read_repair_chance和dc_local_read_repair_chance确定(当然还是先保证一致性级别,做修复,然后再由这两个参数确定)

函数和聚集
user-defined functions,UDF,用户自定义函数 (3.0起,UDF会在单独的沙箱运行)
user-defined aggregates,UDA,用户自定义聚集
user-defined types,UDT,用户自定义类型
原生函数和聚集:count,min,max,sum,avg
分页:limit,paging(2.0引入,自动分页,客户端可以请求一个查询返回的数据的一个子集)
预测重试:SpeculativeExecutionPolicy

删除
删除使用的是墓碑机制,是因为Cassandra自身的持久,最终一致和分布式设计。如果像RDBMS去设计直接删除,如果某个节点挂了,那么后来节点恢复了,这个节点就错过了删除,还保留了数据,可能会把已经删除的数据修复回来。
gc_grace_seconds主要是让有足够的时间去把挂掉的节点恢复。默认是10天,然后就会运行一个合并,将墓碑回收,从而释放空间。
由于SSTable是不可变的,并不是从SSTable删除数据。而是合并时,统计墓碑,对合并数据排序,在排序后的数据上创建新索引,将已合并,已排序的,并有索引的数据写到一个新文件。然后删除老文件。

 

posted @ 2020-07-28 00:09  DevinDC  阅读(466)  评论(0编辑  收藏  举报