基于 Chaos Mesh® 和 Argo 打造分布式测试平台

2020-06-30 00:00:00 集群 测试 故障 注入 混沌

作者:叶奔 殷成文

不久前我们开源了基于 Kubernetes 的混沌测试工具 Chaos Mesh®,Chaos Mesh 提供了模拟系统异常状况的能力,但这只是混沌工程中的一环,完整混沌工程核心原则包含了系统稳定状态的定义、提出假设、运行实验以及验证和改进。

本篇文章主要介绍我们是如何在 Chaos Mesh 和 Argo 的基础上打造自己的自动化测试平台 TiPocket,实现完全自动化的混沌测试,构成混沌测试完整闭环。

为什么需要 TiPocket?

为了确保用户的数据安全,我们需要确保给用户提供的每一个 TiDB 版本都已经经过了严格的测试,所以我们为 TiDB 设计了各种异常场景,并实现了数十个测试 Case,所以在我们的 Kubernetes 集群中,可能同时运行着十几个甚至几十个混沌实验,即使我们拥有了 Chaos Mesh 来帮助我们管理错误注入,但这还远不够,我们还需要去管理 TiDB 集群,需要去收集指标,需要去分析结果,同时进行如此多的混沌实验,另一方面,我们还需要对 TiDB 生态中的其他工具进行混沌测试,这是无法想象的,因此,我们开发了 TiPocket 来解放自己。

TiPocket 是一个基于 Kubernetes 和 Chaos Mesh 的完全自动化测试框架,目前我们主要使用它用来测试 TiDB 集群,不过由于它 All-in-K8s 的特性以及可扩展的接口,它目前也支持测试 TiDB 生态中的其他组件,只要简单的添加应用在 Kubernetes 中 Create/Delete 的逻辑,就可以很轻松的添加对各种应用的支持。

Chaos Mesh 提供故障模拟的能力

故障注入可以说是混沌测试中重要的一环,并且在分布式数据库领域,可能遇到的故障又非常的多,不仅仅是节点故障、各种网络故障、文件系统故障,更甚至可能遇到内核故障。如果 TiDB 不能正确的处理这些异常,那么后果是无法想象的,这也是开始我们开发 Chaos Mesh 的主要原因之一。而 TiPocket 中很好的结合了 Chaos Mesh,将 Chaos Mesh 作为基本的依赖之一,以达到混沌测试中故障注入的目的。

目前我们已经在 TiPocket 提供了多种类型的故障注入:

  • Network:基于 Chaos Mesh 的 NetworkChaos,提供模拟的网络分区,或者链路随机的丢包、乱序、重复、时延等。
  • Time Skew:基于 TimeChaos,模拟待测试容器发生时间偏移。TimeChaos 的实现也是非常有趣,感兴趣的话可以参考我们以前的 文章。
  • Kill:通过 PodChaos 来 kill 对应的 pod。细分下来我们也实现了多种 kill 类型,简单的就是随机删除集群内的任意pod;如果针对各个组件,也有专门的 Chaos 随机 kill 一个或两个 TiKV 节点,或者是专门 kill PD 的 leader 节点。
  • IO:基于 IOChaos,我们用的比较多的是给 TiKV 注入 IO Delay,再去看写入的情况。

解决了故障注入的问题,那么接下来我们就需要判断我们的系统在 TiDB 注入了故障后,是否符合预期呢?

如何判断 TiDB 是否正常?

为了高效的达成这目标,TiPocket 中实现了数十个测试 Case 并结合不同的检查工具来验证 TiDB 是正常。下面会用几个测试 Case 为例,简要介绍 TiPocket 是如何验证 TiDB 的。

Fuzz 测试:SQLsmith

SQLsmith 是一个生成随机 SQL 的工具,TiPocket 分别创建一个 TiDB 集群和一个 MySQL 实例,使用 go-sqlsmith 生成的随机 SQL 分别在 TiDB 和 MySQL 上执行,并对 TiDB 集群注入各种故障,后对比执行的结果,如果出现结果不一致的情况,那么我们可以判断我们的系统存在问题。

事务一致性测试:Bank/Porcupine

1. Bank

银行测试是模拟一个银行系统中的转账流程。在这个测试中,我们创建一系列模拟银行账户,并随时选择两个账户使用事务进行相互转账,一个账户减去一定的金额,另一个账户增加对应的金额,这样的交易不断的并发执行着。在快照隔离下,所有的转账都必须保证每一个时刻所有的账户的总金额是相同的。TiDB 即使在注入各种故障的情况下,依然需要保证这样的约束是成立的,一旦约束被破坏,那么就可以判断此时的系统是不符合预期的。

2. Porcupine

Porcupine 一个用 Go 实现的线性一致性验证工具。是基于 P-compositionality 算法,P-compositionality 算法利用了线性一致性的 Locality 原理,即如果一个调用历史的所有子历史都满足线性一致性,那么这个历史本身也满足线性一致性。因此,可以将一些不相关的历史划分开来,形成多个规模更小的子历史,转而验证这些子历史的线性一致性。在 TiPocket 有许多 Case 中使用了 Pocupine 检查器 去检查生成的历史,从而判断 TiDB 是否满足线性一致性的约束。

事务隔离级别测试:Elle

Elle 是用来验证数据库事务隔离级别的检查工具。Elle 是一个纯黑盒的测试工具,巧妙的构造了一个测试场景,通过客户端生成的历史构造出依赖关系图,通过判断依赖图中是否有环以及分析环来确定事务的出现的异常类型,来确定事务的隔离级别。在 TiPocket 中,我们参考 Elle 项目,实现了 Go 版本的 Elle 检查工具 go-elle,并结合 go-elle 工具来验证 TiDB 的隔离级别。

这些只是 TiPocket 中用来验证 TiDB 正确性的一小部分,如果读者有兴趣可以自行阅读相关 源码,查看更多的验证方法。现在我们有了故障注入,有了待测的 TiDB 集群,有了检验 TiDB 的方式,那么我们该如让这些混沌实验自动化的运行起来呢?如何大化的利用资源呢?在下一小节我们会介绍 TiPocket 中是如何解决这个问题的。

Argo 让流程自动化起来

和大多数的工程师一样,我们个想法是自己开发,造轮子,让 TiPocket 具备调度的功能和管理的功能,但是考虑到我们目前的人力和时间,并且我们知道目前已经有很多开源的工具可以提供类似的功能,所以后我们选择让 TiPocket 更加纯粹,将调度和管理交给更加合适的工具去负责。在考虑到我们 All-in-K8s 的特性,Argo 就成为我们不二的选择。

Argo 是一个为 Kubernetes 而设计的工作流引擎,很早就在社区中开源,并且马上得到了广泛的关注和应用。像在知名的 kubeflow 项目中,就大量使用了 Argo。下面我们首先来介绍下 Argo 的基本概念,再来讲讲如何结合 TiPocket 和 Argo。

Argo 为工作流抽象出了几种 CRD。主要的包括了 Workflow Template、Workflow 以及 Cron Workflow。

  • Workflow Template 可以理解成工作流的模版,我们可以为每个不同的测试任务预先定义好模版,实际运行测试时传入不同的参数。
  • Workflow 将多个工作流模版进行编排,以不同的顺序组合起来进行执行,即实际运行的任务。基于 Argo 本身提供的能力,我们还可以在 pipeline 中实现条件判断、循环、DAG 等多种复杂的能力。
  • Cron Workflow 顾名思义,以 cron 的方式运行 Workflow,非常适合我们想要长期运行某些测试任务的情况。

下面我们看一个简单示例:

spec:
  entrypoint: call-tipocket-bank
  arguments:
    parameters:
      - name: ns
        value: tipocket-bank
            - name: nemesis
        value: random_kill,kill_pd_leader_5min,partition_one,subcritical_skews,big_skews,shuffle-leader-scheduler,shuffle-region-scheduler,random-merge-scheduler
  templates:
    - name: call-tipocket-bank
      steps:
        - - name: call-wait-cluster
            templateRef:
              name: wait-cluster
              template: wait-cluster
        - - name: call-tipocket-bank
            templateRef:
              name: tipocket-bank
              template: tipocket-bank

相关文章