Cassandra一致性详解

本文详细介绍了Cassandra的一致性实现

展开查看详情

1.⼀一致性详解 郭泽晖(索⽉月) 2019.09 CASSANDRA

2.OVERVIEW 1.CAP定理理与Cassandra 1.1 Cassandra优势 2.Cassandra ⼀一致性实现 2.1 CAS 2.2 Quorum读写 2.3 不不⼀一致产⽣生原因 2.4 Hinted handoff 2.5 Read repair 2.6 Manual repair 3.Cassandra应⽤用场景 4.总结

3.1. CAP定理理与CASSANDRA 摘⾃自: https://en.wikipedia.org/wiki/CAP_theorem

4.1. CAP定理理与CASSANDRA 理理念上的误区: Cassandra属于AP系统,完全没有强⼀一致性 正确理理解: CAP并不不是绝对的0和1的取舍,⽐比如可⽤用性可以从0%-100%, 是⼀一个连续的过程。实际⼯工程实践中,都会朝这3个⽅方向努⼒力力。 Cassandra⼤大部分读写是能保证强⼀一致的,只有极端情况不不符合, 这类情况是优先保证可⽤用性,这也是归类到AP的原因。 更更多参考: CAP Twelve Years Later: How the "Rules" Have Changed Brewer's 2012 article on CRDTs (conflict free replicated data types).

5.1.1 CASSANDRA优势 海海量量数据存储 灵活的⽔水平扩展 简洁易易上⼿手的类SQL语法 总是保持在线 多语⾔言客户端⽀支持 可调节读写⼀一致性级别 垂直架构性能强劲 部署⾮非常简单

6.1.1 CASSANDRA优势 去中⼼心化架构,并发读写,节点故障⽆无任何影响 success CQL INSERT/SELECT Coordinator ack ack Kill -9 ⽆无影响 NODE NODE NODE

7.2. CASSANDRA⼀一致性实现 Cassandra允许⽤用户⾃自定义副本数量量和读写⼀一致性级别 CREATE KEYSPACE aliyun WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3} 常⽤用读写⼀一致性级别 ONE 读或写要求返回成功⾄至少1个副本 TWO 读或写要求返回成功⾄至少2个副本 QUORUM 读或写要求返回成功超过半数副本 SERIAL CAS原⼦子更更新(强⼀一致)

8.2.1 CAS 写⼊入和更更新语法可以使⽤用IF⼦子句句做到“Compare and Set” 原⼦子更更新效果,操作失败会返回false。 cqlsh> INSERT INTO cycling.cyclist_name (id, lastname, firstname) VALUES (4647f6d3-7bd2-4085-8d6c-1229351b5498, 'KNETEMANN', 'Roxxane') IF NOT EXISTS; cqlsh> UPDATE cycling.cyclist_name SET firstname = ‘Roxane’ WHERE id = 4647f6d3-7bd2-4085-8d6c-1229351b5498 IF firstname = ‘Roxxane’;

9.2.2 QUORUM读写 QUORUM级别读写能⾮非常好的满⾜足⾼高可⽤用,同时也保证强⼀一致(有临界情况,下⽂文会说明) 读要超过半数(2副本) 3副本写⼊入,有2副本成功即可,容忍挂掉⼀一个节点 所以总能读到最新数据(鸽巢原理理) CQL INSERT V1 success&return V1 CQL SELECT success Coordinator Coordinator timeout return V1 return V0 ack ack NODE NODE NODE NODE NODE NODE V1 V1 V0 V1 V1 V0

10.2.2 QUORUM读写 QUORUM级别读写临界情况 读2副本可能正好读到V1也可能V0 3副本写⼊入,只有1副本成功,整个写⼊入失败 并且V1从⽤用户看来是没写⼊入成功的 CQL INSERT V1 success&return V1 CQL SELECT failed Coordinator Coordinator failed return V1 return V0 ack failed NODE NODE NODE NODE NODE NODE V1 V0 V0 V1 V0 V0 PS:解决⽅方法可以是,业务重试到写⼊入成功为⽌止

11.2.3 不不⼀一致产⽣生原因 ‣ 1.并发写⼊入时有节点没有成功完成写⼊入(可能是BUG或者当时挂了了之类的情况)。假设是 ONE级别查询,查询落到这个节点的时候就会读出旧数据 ‣ 2.磁盘损坏导致某节点丢失部分最新副本(云环境⽤用云盘这个问题可以忽略略) 不不⼀一致是⽐比较极端情况下才会出现,出现后Cassandra有很多⼿手段修复它。

12.2.4 HINTED HANDOFF 考虑以下场景: 如果3副本Quorum写⼊入3个节点,其中⼀一个节点挂了了,只有2个节点写⼊入成功,此时出现不不⼀一致怎么办? CQL INSERT success Coordinator ack ack NODE NODE NODE

13. 2.4 HINTED HANDOFF 出现上述情况,此时就需要通过Hinted handoff功能⾃自动恢复⼀一致性,在故障节点恢复后。 CQL INSERT 2.记录写⼊入内容到本地磁盘(称为Hint) 4.侦测到故障节点恢复并读取Hint Coordinator DISK Coordinator 1.检测到写⼊入失败 5.重新写⼊入副本 NODE NODE NODE NODE NODE NODE

14.2.4 HINTED HANDOFF Hint失效问题 max_hint_window_in_ms: 10800000 # 3 hours hints_flush_period_in_ms: 10000 # 10 seconds ‣ 1.默认节点挂掉超过3个⼩小时就不不会再为此节点记录Hint。 ‣ 2.Hint先写⼊入buffer,然后flush到磁盘。这⾥里里有个flush周 期,如果Coordinator在flush前挂掉,会导致丢失Hint。 ‣ 3.Coordinator磁盘满了了写不不了了Hint,导致Hint丢失。 ‣ 4.磁盘损坏导致Hint丢失。 ‣ …… Hint失效后如何修复⼀一致性呢?

15. 2.5 READ REPAIR 在Hint失效后,需要有其他功能来继续修复⼀一致性,Read repair就是其中之⼀一。下⾯面以3副本QUORUM 级别的读操作来阐述整个读过程。这种情况需要读到2个副本,才算成功。 并发读取第1个⽬目标副本数据 Replica Target Data 选取2⽬目标副本和1备副本 SELECT * FROM user.table 和第2个⽬目标副本的Digest WHERE id = 0 Coordinator Replica Target Digest Replica Standby Standby 1.超过⼀一定时间阈值⽆无法满⾜足副本数量量会读备副本 2.第2个副本不不会返回数据,只返回digest,节约带宽。因为如果如果2个副本的digest⼀一致的话,只需要返回第⼀一个副本数据即可。

16.2.5 READ REPAIR Data Data& 计算第1个副本digest Digest ⽐比较Digest 不不⼀一致:DigestMismatchException Digest Digest 不不⼀一致后数 据没法返回, 需要全部重 读 Standby Standby ⼀一条路路做repair Data 结束 合并数据 Data Data ⼀一条路路响应⽤用户 读请求

17.2.5 READ REPAIR Read repair问题: 1.影响读延迟,有⼀一个重读的过程。 2.没读到的数据不不会被修复。如果放任不不管,后续这份数据可能因磁盘损 坏继续丢失副本,最后数据全没了了。 3.ONE级别⼀一致性读不不会修复 有没有更更全⾯面的修复⼿手段?

18.2.6 MANUAL REPAIR bin/nodetool help 'repair' 这个是Cassandra⽤用来修复⼀一致性的⽇日常⼿手段,需要定期运⾏行行修复潜在的不不⼀一致⻛风险。 下⾯面会详细说明下这个⼯工具的原理理和运⾏行行过程。

19. 2.6 MANUAL REPAIR repair需要在某个节点上运⾏行行或者远程指定某个节点,整个repair过程会在 nodetool客户端,当前节点, 远端副本节点 三者之间交互。 1.根据mykeyspace配置的分区策略略获取当前节点上所有 管辖的Range(也就是分区)信息 Range1 Range4 bin/nodetool repair mykeyspace mytable Range2 Range3 3.按分组提交RepairSession, 并发运⾏行行,并⾏行行度取决于参数 2.之后对所有Range分组,找出每个Range Node Node Range1 Range2 —job-threads Node 关联的副本节点。按副本节点集合为key分组。 下⻚页RepairSession处理理 Node Node Range3 Range4 Node

20.2.6 MANUAL REPAIR 向所有副本节点发送ValidationRequest ValidationRequest会做ValidationCompaction(read only)⽣生成多棵 RepairSession MerkleTree,即叶⼦子结点表示某个⼦子Range所有数据hash值的⼀一种 特定⼆二叉树。 Range (1, 100] (1, 50] (50, 100] Hash Hash Hash Hash 返回所有MerkleTree并在执⾏行行repair的节点上⽐比较, 如果Hash值不不同会通过内部Stream互相修复。 PS:可以看出这个过程要读盘有⼀一定开销,建树也有内存开销。后续引⼊入了了incremental repair解决这个问题。也就是下⼀一⻚页接下来要说的。

21.2.6 MANUAL REPAIR Incremental repair 改进:AntiCompaction RepairSession成功结束后,会向所有节点发起AntiCompaction,把SSTable拆成2个。 SSTable 包含执⾏行行过repair的数据 SSTable SSTable 包含未执⾏行行过的数据 这样下次做ValidationCompaction的时候,可以跳过⼀一部分数据,减少读盘的开销。

22.2.6 MANUAL REPAIR Incremental repair 问题: 1.可能会产⽣生很多SSTable⽂文件,影响性能。 2.如果是第⼀一次做Incremental rapair开销⾮非常⼤大,很容易易搞挂。 3.社区版本⾄至今任然有⼀一些未解决bug(4.0中才fix),会导致SSTable没 有被正常标记为“已经执⾏行行过repair” 导致下次仍然会继续读。

23.2.6 MANUAL REPAIR 推荐的解决⽅方案: 做repair时候带上 —start-token 和 —end-token 做 subrange repair。 这样会跳开AntiCompaction过程,⾃自⼰己也能通过subrange控制repair粒 度,避免产⽣生过⼤大流量量。缺点就是略略微麻烦,效率低。 PS:阿⾥里里云Cassandra通过⾃自研的⽇日常repair⼿手段最⼤大限度的避免了了上述问题

24.3 CASSANDRA应⽤用场景 除了了极少数交易易类场景,基本都能⽤用,需要⽤用户根据业务需求调整⼀一致性级别。 常⽤用不不同级别适⽤用场景 ONE 对⼀一致性要求不不严格的场景,能获得超⾼高性能和可⽤用性(分析,推荐等场景) QUORUM 能获得强⼀一致(容忍特殊失败情况)的同时保证⾼高可⽤用(⼤大部分场景都适⽤用) SERIAL 适⽤用CAS原⼦子更更新强⼀一致场景 更更多参考资料料可参⻅见Cassandra商业公司阿⾥里里云或Datastax相关⽂文档: https://help.aliyun.com/document_detail/126637.html?spm=5176.cncds.0.0.68201f2cLcsNyI&aly_as=_fl7YvKf https://www.datastax.com/resources?type=case_study

25.4 总结 ‣ 1.Cassandra设计上总是保持在线 ‣ 2.Cassandra可以根据业务需要在强⼀一致 和⾼高可⽤用中权衡 ‣ 3.Cassandra⼤大多数时候是很好的选择

26.欢迎技术交流 技术社区微信公众号 技术社区钉钉群 阿⾥里里云Cassandra免费⽕火爆公测中 欢迎试⽤用:https://www.aliyun.com/product/cds