前一阵子一直在做 K8S 监控平台的东西,最近开始开发混沌工程平台并且着手组织相关的测试项目。 而正好我写书也写到了混沌工程这一章了, 所以我决定梳理一下一些知识点,免得自己忘记了。
其实不仅仅是要写 cap, 我写的书中还会详细介绍在 K8S 中常用的高可用设计方法。我一直以来主张的都是要先测试一个东西那就要先了解它。就像我们测试一个产品功能之前肯定要对这个产品的功能十分的熟悉才行。同理的如果我们接到了高可用测试的需求,那就一定要先熟悉系统的高可用设计,这样才能针对性的对齐测试目标和设计测试场景。
我十分不擅长对事物进行总结定义,就像我在写标题的时候纠结了好一会到底应该叫混沌工程还是叫高可用测试。当初互联网这些造新词的大佬们真的是给我出了难题。索性我就不把网络上针对 CAP 的定义 copy 过来了,我就按自己的理解随便说说吧。我理解 CAP 是一致性,可用性和分区容错性三个词的英文缩写,讲的是针对一个分布式系统在高可用设计上最重要的三种能力。并且这三种能力无法同时满足,在故障出现时必定要牺牲一项。
这里说的一致性是数据的一致性,一般分布式系统的数据都会备份在多台机器上。一致性是要保证用户在读取数据的时候,返回的应该是这个数据最新的结果。当然在分布式事务中未提交的数据不算是最新的数据。 那什么时候情况下会造成不一致的现象呢, 比如在 mysql 的 master/slave 架构下(异步复制方案),所有的写请求必须发送给 master 节点,而读请求可以发送给 master 和 slave 的任意一个节点。数据写入 master 节点后会有机制把数据同步到 slave 节点上。但是这个同步是有延迟的,所以就会有数据一致性的风险。 在平时这个延迟会非常小,可能是毫秒级别的。但是如果 master 到 slave 的网络出现了故障,那么这个不一致会越来越大。
在部分节点发生故障时,非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。翻译成大白话就是即便有部分节点 down 机,系统依然可以对外提供服务。这个比较容易理解,服务实例部署,当有部分实例故障时,流量可以切换到健康的服务上继续为用户提供服务。
这个应该是最难理解的,我个人理解网络分区指由于某些故障,造成系统中某些节点互相无法访问,从而在系统中分裂出了若干独立的组。比如还是拿 mysql 的 master/slave 架构来说(异步复制方案),由于某些故障导致 master 节点到 slave 节点的网络中断了,但是仅仅是 master 节点到 slave 节点的网络出现了问题,用户还是可以正常访问两个节点的。这就出现了网络分区,也就是说这些节点都是正常可以服务的,但是这些节点之间的通信出现了问题。 分区容错性的意思就是在系统中出现了网络分区时,要求系统仍然能够继续履行职责。
CAP 的理论是这三种能力无法同时满足,我们必须至少牺牲一项。但实际上我们只能牺牲 C 或者 A。在出现网络分区的情况下如果你想要保证 C 的话,那就只能禁止系统的写请求了,因为你的数据无法同步到其他节点上,一定会造成数据不一致的情况。 但如果你禁止写请求就违背了 A。 实际上我们只有 CP 和 AP 两个选择,CA 是做不到的。
在上面 mysql 这个案例中(异步复制方案)就属于 AP 的方案,一旦出现了网络分区问题,会造成数据的不一致,因为 master 节点的数据无法同步到 slave 节点上了,这导致两边的数据不是不一致的。 但是用户依然可以从 master 和 slave 上读取数据。所以是满足 AP 的。 这种方案一般在对数据的一致性不是很看重的场景中使用
CP 的方案其实也比较好理解,出现故障后为了保证 C,那就需要牺牲 A。 比如还是上面 mysql 的案例,当出现了网络分区后,用户发往 slave 节点的请求全部返回 error 就可以了。这样用户不会读取到未同步的数据。 或者还有一种设计是根据用户/订单的 ID 对数据进行分区, 比如 ID 是 0~1000 的数据存到 Node1 中, 1000~2000 的存到 Node2 中。 这样的设计简单粗暴,因为同一份数据没有在其他节点上留下备份,用户想要读取这份数据也必须在固定的节点读取,所以它是强一致性的。代价是彻底牺牲了可用性,当一个节点故障的时候,那么这部分的数据就是不可用了。 这也是为什么我们有时会看到一些新闻,说某某平台机房故障,导致部分用户出现异常。 这里不是全部的用户异常,而是部分用户。就是因为它采取了这种强一致性的设计。
之前在极客时间上学习课程的时候看到了 BASE 理论,这是对于 CAP 的补充,很多时候没有完美的系统所以提出了 BASE 理论来进行指导。BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency),核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。
我理解就是系统中的功能但是分三六九等的,有核心的业务也有边边角角的业务。所以在系统异常时可以只保证核心业务可用即可。 追求整个系统的可用太过于浪费成本。
我理解就是准许系统存在中间状态, 在中间状态下数据可能是不一致的,但不能影响可用性。 这一点我理解就是在 CAP 中说道的没有完美的 CP。 数据同步一定会有一定的延迟。
系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。尤其是对于选择了 AP 方案的系统,放弃了一致性不是说数据就永远不一致了, 系统需要有一定的机制保障数据最终会呈现一致的状态。可以使用自动化的方式也可以使用人工的方式,一定要让数据最终呈现一致的状态。比如 mysql 的主从和主备架构(异步复制方案),在发生网络分区时或者 master 节点 down 机后数据肯定是不一致的。 运维人员可以通过 binlog 从 master 中恢复数据并重新保持 master 和 slave 的数据一致。 这也是一种可接受的方案。
我理解 BASE 是对 CAP 的一个补充,尤其是对 AP 方案的补充。 因为 CAP 过于理想,想要实现完美的 CP 和 AP 方案太困难了。 所以很多系统最终都会变成 BASE 的状态。
测试人员了解 CAP 和 BASE 的目的是在测试的过程中起到指导作用。 帮助我们了解系统当前的设计,分析系统高可用的目标。业务是希望选择 CP 还是 CA?是要保证强一致性? 还是最终一致性?只有了解了这些才能设计测试用例。 比如这里我列举 2 个我最近遇到的典型的场景。
暂时就写这么多吧,感觉高可用这个方向还是很复杂的,我迄今为止感觉还是有蛮多东西没有搞懂的。