从 TiDB 学习分布式数据库测试

前言

最近在研究数据库正确性测试相关的内容,恰好看到TiDB数据库在这方面的工作,很受启发,故写此文章。

推荐下一些TiDB官方好文章:

  • 《分布式系统测试那些事儿 – 理念》https://cn.pingcap.com/blog/distributed-system-test-1/
  • 《分布式系统测试那些事儿 – 错误注入》https://cn.pingcap.com/blog/distributed-system-test-2/
  • 《分布式系统测试那些事儿 – 信心的毁灭与重建》https://cn.pingcap.com/blog/distributed-system-test-3/
  • 《TiDB 混沌工程实践:如何打造健壮的分布式系统?》https://cn.pingcap.com/blog/tidb-chaos-engineering/
  • 《基于 Chaos Mesh 和 Argo 打造分布式测试平台》https://cn.pingcap.com/blog/building-a-distributed-test-platform-based-on-chaos-mesh-and-argo/

从一个BUG开始

理论上说,任何一款支持事务的数据库都应该支持ACID四个特性。实际上呢,可能因为未知的软件Bug、机器故障(比特反转)等,导致数据库在实际运行中未能完全满足,这就有可能对上层业务带来严重的影响。

比如Percona(MySQL源码的一个分支)修复了一个MySQL可能丢失数据的bug:https://docs.percona.com/percona-server/8.0/release-notes/8.0.39-30.html#bug-fixes

关于Bug的更详细解读见:https://www.modb.pro/db/1869263663966728192

对应的修复代码:https://github.com/percona/percona-server/pull/5385/files

上面列举的是一个软件层面BUG导致数据丢失的case,所以从PR中可以看到添加了对应的测试case以确保同一个问题不会再犯。那么其他workload会不会还有类似问题?机器故障时又会有什么表现呢?

数据库测试的手段

下面列举了一些数据库测试需要做的一些事情,内容主要来自上面推荐的几篇文章。

1、事务正确性测试

首先需要证明数据库实现的事务模型是没有问题的,尤其是在并发读写时,类似的工作已经有人在做了:

事务隔离级别测试:

Elle: 用来验证数据库事务隔离级别的检查工具。Elle 是一个纯黑盒的测试工具,巧妙的构造了一个测试场景,通过客户端生成的历史构造出依赖关系图,通过判断依赖图中是否有环以及分析环来确定事务的出现的异常类型,来确定事务的隔离级别。[5] https://github.com/jepsen-io/elle

事务一致性测试:

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

2、构造丰富的测试case

怎么在你睡觉的时候发现 Bug ?

“我们现在很有意思的一个事情是,迄今为止 PingCAP 没有一个测试人员,这是在所有的公司看来可能都是觉得不可思议的事情,那为什么我们要这么干?因为我们现在的测试已经不可能由人去测了。究竟复杂到什么程度呢?我说几个基本数字大家感受一下:我们现在有六百多万个 Test,这是完全自动化去跑的。然后我们还有大量从社区收集到的各种 ORM Test,一会我会提到这一点。就是这么多 Test 已经不可能是由人写出来的了,以前的概念里面是 Test 是由人写的,但实际上 Test 不一定是人写的,Test 也是可以由机器生成的。举个例子,如果给你一个合法的语法树,你按照这个语法树去做一个输出,比如说你可以更换变量名,可以更换它的表达式等等,你可以生成很多的这种 SQL 出来。[2]”

“但是这地方又蹦出另外一个问题,就是你生成了合法的 SQL 语句,但是你不知道它语句执行的结构,那你怎么去判断它是不是对的?当然业界有很聪明的人。我把它扔给几个数据库同时跑一下,然后取几个大家一致的结果,那我就认为这个结果基本上是对的。如果一个语句过来,然后在我这边执行的结果和另外几个都不一样,那说明我这边肯定错了。就算你是对的,可能也是错的,因为别人执行下来都是这个结果,你不一样,那大家都会认为你是错的。”[2]

3、错误注入

一个软件运行在操作系统之上,使用了硬件上的磁盘、CPU、内存、网卡、时钟等资源,在软件上还有文件系统、网络协议栈等。如何证明或者验证在这些依赖的资源出现错误时,数据库系统不会出现不符合ACID的问题?

如果你说把磁盘弄坏、网线拔掉、主机烧毁来模拟这类故障,这的确是个办法,但不是明智的的办法。

如果直接损坏硬件成本比较大,不妨加个中间层,这次添加的是故障模拟。“磁盘是模拟的,网络是模拟的,那我们可以监控它,你可以在任何时间、任何的场景下去注入各种错误,你可以注入任何你想要的错误。[3]”

在这方面有很多项目已经做过了,如:

  • libfiu:Fault injection in userspace https://blitiri.com.ar/p/libfiu/
  • Netflix:《 Failure Injection Testing 》 https://netflixtechblog.com/fit-failure-injection-testing-35d8e2a9bb2
  • OpenStack fault-injection library: https://pypi.org/project/os-faults/
  • Jepsen: A framework for distributed systems verification, with fault injection https://github.com/jepsen-io/jepsen
  • FoundationDB:Simulation and Testing https://apple.github.io/foundationdb/testing.html
  • CharybdeFS: ScyllaDB fault injection filesystem https://github.com/scylladb/charybdefs
  • Namazu:Programmable fuzzy scheduler for testing distributed systems https://github.com/osrg/namazu
  • american fuzzy lop: a security-oriented fuzzer https://github.com/google/AFL
  • OSS-Fuzz:Continuous Fuzzing for Open Source Software https://github.com/google/oss-fuzz

4、做好观测

错误可以注入到数据库中了,那么怎么观测数据库服务再哪个环节出现了问题呢?这就得请出 Metrics、Log 和 Tracing 三剑客了。 这些想必大家都很熟悉了:

  • Metrics: 丰富的内核指标、秒级数据采集、智能的异常判断&报警
  • Log: 存放了详细的错误信息,可以使用 FluentBit 或 Promtail,将这些数据导入 ES 或 LOKI 进行相关分析。对于分布式系统,一个事务会请求到做个组件,那么可以使用transaction ID打印到日志中将其关联起来。[4]
  • Tracing: 在调用链概念出现之前,日志是用来帮助我们理解应用程序中发生情况的唯一途径。大多数的应用程序在他们运行的服务器上创建日志。然而,对于分布式系统来说,光靠日志是不够的,因为光靠日志定位问题的具体位置是一项巨大的挑战。但是调用链则可以非常方便的处理这种场景,因为其可以完整的追踪一个请求的开始到结束所经过的所有节点。[1]

5、小结

  • TiDB 在 SQL 测试上借助了社区现有 ORM Test,以此保证兼容性
  • 同时,利用语法树随机生成SQL并在多款数据库上运行,验证在 TiDB 的SQL执行结果跟其他数据库一致
  • 对于分布式系统,利用错误注入方式模拟故障,验证数据库稳定性、可靠性
  • 另外还有本文未提及的其他大量测试手段 https://github.com/PingCAP-QE

PingCAP/TiDB 的测试

上面提及的“事务正确性测试”、“构造丰富的测试case”,PingCAP 开发了一个 tipocket 框架,对其做了集成;在“错误注入”方面,PingCAP 开发了一个对应的 chaos-mesh 混沌工程平台;“做好观测”方面,tidb在设计之初就做了考量,在内核中做了Metrics、Log、Tracing工作,并且可以存储到k8s提供的相关服务中。最后tidb利用argo-workflow来做自动化运行。

  • chaos-mesh: 混沌工程平台,提供丰富的故障模拟类型,具有强大的故障场景编排能力,方便用户在开发测试中以及生产环境中模拟现实世界中可能出现的各类异常[6] https://github.com/chaos-mesh/chaos-mesh
  • TiDB operator: Kubernetes 上的 TiDB 集群自动运维系统,提供包括部署、升级、扩缩容、备份恢复、配置变更的 TiDB 全生命周期管理。借助 TiDB Operator,TiDB 可以无缝运行在公有云或自托管的 Kubernetes 集群上。[7] https://github.com/pingcap/tidb-operator
  • tipocket:一个专门用于测试 TiDB 的测试工具包,它封装了一些同样适合测试其他数据库的测试工具。设计灵感来源于分布式系统领域著名的库jepsen-io/jepsen。https://github.com/pingcap/tipocket
  • argo:一个基于k8s的工作流平台。比如在运行测试case前,创建namespace、新建secert,然后运行测试case,在测试完成后删除ns等。https://github.com/argoproj/argo-workflows

最终的运行关系如图所示:

  • 测试人员提交一个测试任务(argo workflow),依次执行step 1、2、3。
  • 在执行 step 3 时,运行的镜像是由 tipocket 框架编写而来的测试case。这个case会创建一个tidb集群(节点副本数可以在配置),然后运行测试workload(模拟银行转账、模拟财务报表分析、或者随机生成SQL等,需要根据不同的workload编写对应的数据校验逻辑),workload运行期间还会随机生成各种错误并注入到集群中。
  • 直到 workload 运行结束,执行 step 4、5,结束测试。

比如一个简单银行转账测试case包括:

  • 初始化N个账户,每个账户M元
  • 启动X个线程,模拟并发转账。随机选择出发起人、收款人,转账金额。开启事务修改两个账户余额,并记录转账流水。
  • 定时sum所有账户的总额,预期值为 N*M 元,如果总金额不对,立刻退出
  • 否则等到测试时间结束

此外还可以设计更复杂的case,比如

  • 这期间定时执行 alter table 语句,对于分布式数据库可能还有其他特殊DDL,都可以加入
  • 支持转账给多人
  • 也可以将转账数据同时写入MySQL等其他数据库,验证不同数据库的结果
  • 还可以将转账记录按照对应格式记录到磁盘上,然后利用Elle、Porcupine验证数据前后关系是否符合一致性

参考

  • [1] https://developers.weixin.qq.com/community/develop/article/doc/00040a73f2440837740fab41b5b413
  • [2] https://cn.pingcap.com/blog/distributed-system-test-1/
  • [3] https://cn.pingcap.com/blog/distributed-system-test-2/
  • [4] https://cn.pingcap.com/blog/distributed-system-test-3/
  • [5] https://cn.pingcap.com/blog/building-a-distributed-test-platform-based-on-chaos-mesh-and-argo/
  • [6] https://chaos-mesh.org/docs/
  • [7] https://docs.pingcap.com/zh/tidb-in-kubernetes/dev/tidb-operator-overview
  • [8] https://chaos-mesh.org/zh/blog/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/66544.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尚硅谷Vue3入门到实战 —— 04 OptionsAPI 与 CompositionAPI

我们看一下上一节的代码&#xff0c;如下&#xff1a; <template><div class"person"><h2>姓名&#xff1a; {{ name }}</h2><h2>年龄&#xff1a; {{ age }}</h2><button click"changeName">修改名字</but…

【物联网原理与运用】知识点总结(上)

目录 名词解释汇总 第一章 物联网概述 1.1物联网的基本概念及演进 1.2 物联网的内涵 1.3 物联网的特性——泛在性 1.4 物联网的基本特征与属性&#xff08;五大功能域&#xff09; 1.5 物联网的体系结构 1.6 物联网的关键技术 1.7 物联网的应用领域 第二章 感知与识别技术 2.1 …

JVM生产环境常用参数配置及调优建议

一、生产常用参数配置 JAVA_OPTS"-server -Xms3000m -Xmx3000m -Xmn1500m -XX:UseG1GC -XX:ConcGCThreads8 -XX:PrintGCDetails -XX:PrintGCTimeStamps -Xloggc:./g1-gc.log -XX:MaxMetaspaceSize256m -XX:-UseGCOverheadLimit -XX:UseCompressedOops -XX:HeapDumpOnOu…

Nginx:会话保持

会话保持 是指在负载均衡环境中,确保来自同一用户的多个请求都发送到同一个后端服务器。这通常用于那些需要记住用户状态或上下文的应用程序,例如购物车、登录状态等。 会话保持的重要性 用户体验:保证用户在整个会话期间的一致性体验,避免因不同服务器间的数据不同步导致…

SEO内容优化:如何通过用户需求赢得搜索引擎青睐?

在谷歌SEO优化中&#xff0c;内容一直是最重要的因素之一。但要想让内容真正发挥作用&#xff0c;关键在于满足用户需求&#xff0c;而不是简单地堆砌关键词。谷歌的算法越来越智能化&#xff0c;更注重用户体验和内容的实用性。 了解目标用户的需求。通过工具如Google Trends…

【VUE+ElementUI】通过接口下载blob流文件设置全局Loading加载进度

下载Blob流文件&#xff0c;并以服务形式显示文件下载进度 1、下载接口 增加 config参数&#xff0c;并用...config将该属性加入到请求中&#xff1b; xxapi.js文件中设置downloadFile下载接口 // 下载文件 export function downloadFile(data, config) {return request({ur…

Clisoft SOS与CAD系统集成

Clisoft SOS与CAD系统集成 以下内容大部分来自官方文档&#xff0c;目前只用到与Cadence Virtuoso集成&#xff0c;其他还未用到&#xff0c;如有问题或相关建议&#xff0c;可以留言。 与Keysight ADS集成 更新SOS客户端配置文件sos.cfg&#xff0c;以包含支持ADS的模板&am…

Unity-Mirror网络框架从入门到精通之Attributes属性介绍

前言 在现代游戏开发中&#xff0c;网络功能日益成为提升游戏体验的关键组成部分。Mirror是一个用于Unity的开源网络框架&#xff0c;专为多人游戏开发设计。它使得开发者能够轻松实现网络连接、数据同步和游戏状态管理。本文将深入介绍Mirror的基本概念、如何与其他网络框架进…

Fastapi + vue3 自动化测试平台(2)--日志中间件

FastAPI Vue3 自动化测试平台&#xff08;2&#xff09;-- 日志中间件 前言 在开发和运行自动化测试平台时&#xff0c;日志功能是至关重要的一部分。日志不仅能帮助我们快速定位和解决问题&#xff0c;还能作为平台运行的记录依据&#xff0c;为后续分析和优化提供参考。 …

【计算机视觉】单目深度估计模型-Depth Anything-V2

概述 本篇将简单介绍Depth Anything V2单目深度估计模型&#xff0c;该模型旨在解决现有的深度估计模型在处理复杂场景、透明或反射物体时的性能限制。与前一代模型相比&#xff0c;V2版本通过采用合成图像训练、增加教师模型容量&#xff0c;并利用大规模伪标签现实数据进行学…

css预处理器sass

在前端开发的世界中&#xff0c;CSS 是构建网页样式的基础。然而&#xff0c;随着项目规模的增大&#xff0c;纯 CSS 的编写和维护往往会变得复杂而繁琐。为了解决这些痛点&#xff0c;Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;应运而生。Sass 是一种 C…

uni-app图文列表到详情页面切换

需求&#xff1a;参考若依框架后&#xff0c;想实现首页浏览文章列表&#xff0c;没有合适的样式参考&#xff0c;所以需要有效果做到“图文列表到详情页面切换”&#xff0c;查阅了一下案例 发现有相应的案例&#xff0c;在导航栏“模板”中找到了 DCloud 插件市场 PC电脑端访…

日志服务 SQL 引擎全新升级

作者&#xff1a;戴志勇、顾汉杰&#xff08;执少&#xff09; SQL 作为 SLS 基础功能&#xff0c;每天承载了用户大量日志数据的分析请求&#xff0c;既有小数据量的快速查询&#xff08;如告警、即席查询等&#xff09;&#xff1b;也有上万亿数据规模的报表级分析。SLS 作为…

【微服务】5、服务保护 Sentinel

Sentinel学习内容概述 Sentinel简介与结构 Sentinel是Spring Cloud Alibaba的组件&#xff0c;由阿里巴巴开源&#xff0c;用于服务流量控制和保护。其内部核心库&#xff08;客户端&#xff09;包含限流、熔断等功能&#xff0c;微服务引入该库后只需配置规则。规则配置方式有…

matlab编写Newton插值多项式

定义&#xff1a; 即&#xff1a; clear x [1, 2, 3, 4]; % x坐标 y [2, 1, 4, 3]; % y坐标 % 定义目标插值点 xi 2.5;% x: 已知数据点的x坐标% y: 已知数据点的y坐标% xi: 插值点&#xff0c;可以是一个数或一个向量n length(x);% 初始化差商矩阵F zeros(n, n);F(:,1…

unity学习14:unity里的C#脚本的几个基本生命周期方法, 脚本次序order等

目录 1 初始的C# 脚本 1.1 初始的C# 脚本 1.2 创建时2个默认的方法 2 常用的几个生命周期方法 2.1 脚本的生命周期 2.1.1 其中FixedUpdate 方法 的时间间隔&#xff0c;是在这设置的 2.2 c#的基本语法别搞混 2.2.1 基本的语法 2.2.2 内置的方法名&#xff0c;要求更严…

东土科技参股广汽集团飞行汽车初创公司,为低空经济构建新型产业生态

近日&#xff0c;广汽集团旗下专注于飞行汽车领域的初创公司广东高域科技有限公司于2024年12月31日正式成立&#xff0c;在穿透后的股东信息中&#xff0c;东土科技通过广州瓴云科技投资合伙企业&#xff08;有限合伙&#xff09;赫然在列。 此前12月18日&#xff0c;广汽集团…

xml-dota-yolo数据集格式转换

1、yolo转xml from xml.dom.minidom import Document import os import cv2 # def makexml(txtPath, xmlPath, picPath): # txt所在文件夹路径&#xff0c;xml文件保存路径&#xff0c;图片所在文件夹路径 def makexml(picPath, txtPath, xmlPath): # txt所在文件夹路径&…

【Nginx】设置https和http同时使用同一个端口访问

以下是一个同时使用 HTTP 和 HTTPS 并通过 8070 端口的配置示例&#xff1a; server {listen 8070;server_name your_domain.com;location / {root /var/www/html;index index.html;} }server {listen 8070 ssl;server_name your_domain.com;# SSL 证书和私钥的路径ssl_certif…

基于Elasticsearch8的向量检索实现相似图形搜索

Elasticsearch8版本增加了KNN向量检索&#xff0c;可以基于此功能实现以图搜图功能。 1、首先创建索引&#xff0c;es提供了类型为dense_vector的字段&#xff0c;用于存储向量&#xff0c;其中dims是向量维度&#xff0c;可以不配置&#xff0c;es会根据第一条插入的向量维度…