首页 > 数据库 >etcd 和 MongoDB 的混沌(故障注入)测试方法

etcd 和 MongoDB 的混沌(故障注入)测试方法

时间:2024-05-20 11:19:51浏览次数:17  
标签:etcd 二进制 MongoDB gofail 故障 故障注入 测试

/i/l/?n=24&i=other/1432456/202405/1432456-20240520111533088-944222207.png

最近在对一些自建的数据库 driver/client 基础库的健壮性做混沌(故障)测试, 去验证了解业务的故障处理机制和恢复时长. 主要涉及到了 MongoDB 和 etcd 这两个基础组件. 本文会介绍下相关的测试方法.

MongoDB 中的故障测试

MongoDB 是比较世界上热门的文档型数据库, 支持 ACID 事务、分布式等特性.

社区上大部分对 MongoDB 进行混沌(故障)测试的文章大多都是外围通过对 monogd 或 mongos 进行做处理进行模拟的. 比如如果想要让 MongoDB 自己触发副本集切换, 可以通过一下这样一段 shell 脚本:

# 将副本集主节点进程挂死
kill -s STOP <mongodb-primary-pid>

# 挂死之后, 业务受损, MongoDB 在几秒到十几秒应该会进程主备切换
# 切换完成后, 业务能自动将连接切换到新的工作正常的主节点, 无需人工干预, 业务恢复正常
# 这里一般验证的是 Mongo Client Driver 的可靠性

上面提到的手段一般是系统层级的, 如果我们只是想要模拟某个 MongoDB command 命令遇到网络问题了, 怎么做?进一步想要进行更细粒度的测试. 其实 MongoDB 在 4.x 以上版本内部已经实现了一套可控的故障点模拟机制 -> failCommand.

在测试环境部署 MongoDB 副本集的时候, 一般可以通过以下方式启动这个特性:

mongod --setParameter enableTestCommands=1

然后我们可以通过 mongo shell 针对特定的 command 开启故障点, 例如针对一次 find 操作让其返回错误码 2:

db.adminCommand({
    configureFailPoint: "failCommand",
    mode: {
      "times": 1,
    },
    data: {errorCode: 2, failCommands: ["find"]}
});

这些故障点模拟是可控的, 成本相对于必直接在机器上搞破坏比较低, 也很适合融入持续集成自动化流程. MongoDB 内置的故障点机制还支持了很多的特性, 比如让某个故障概率发生、返回任意 MongoDB 支持的错误码类型等等, 通过该机制, 我们可以很方便的在单元测试和集成测试中验证我们自己实现的 MongoDB Client Driver 的可靠性.

如果想具体知道 MongoDB 支持哪些故障点, 可以详细查看 MongoDB 提供的 specification, 里面有提到针对 MongoDB 每一个特性, driver 可以使用哪些故障点进行测试.

MongoDB 官方提供的 go 实现的 dirver 代码仓库中也有不少的例子可以参考 https://github.com/mongodb/mongo-go-driver/blob/345ea9574e28732ca4f9d7d3bb9c103c897a65b8/mongo/with_transactions_test.go#L122.

etcd 中的故障测试

etcd 是一个开源的、高可用的分布式键值存储系统, 它主要用于共享配置和服务发现.

之前我们提到了 MongoDB 内置了可控的故障点注入机制方便我们做故障点测试, 那么 etcd 是否也提供了呢?

没错, etcd 官方也提供了内置的可控故障注入手段方便我们围绕 etcd 做故障模拟测试, 不过官方提供的可供部署的二进制分发默认是没有使用故障注入特性的, 区别于 MongoDB 提供了开关, etcd 需要我们手动从源码编译出包含故障注入特性的二进制出来去部署.

etcd 官方实现了一个 Go 包 gofail 去做 "可控" 的故障点测试, 可以控制特定故障发生的概率和次数. gofail 可以用于任意 Go 实现的程序中.

原理上通过注释在源代码中通过注释 (// gofail:) 去对可能发生问题的地方埋藏一些故障注入点, 偏于进行测试验证, 例如:

	if t.backend.hooks != nil {
		// gofail: var commitBeforePreCommitHook struct{}
		t.backend.hooks.OnPreCommitUnsafe(t)
		// gofail: var commitAfterPreCommitHook struct{}
	}

在使用 go build 构建出二进制之前, 使用 gofail 提供的命令行工具 gofail enable 可以取消这些故障注入相关代码的注释, 并生成故障点相关的代码,这样编译出的二进制可以用于故障场景的细粒度测试. 使用 gofail disable 去注释去除掉生成的故障点相关代码, 再使用 go build 编译出的二进制就可以在生产环境使用.

在执行二进制的时候, 可以通过环境变量 GOFAIL_FAILPOINTS 去唤醒故障点, 如果你的二进制程序是个永不停机的服务, 那么可以通过 GOFAIL_HTTP 环境变量在程序启动的同时, 启动一个 HTTP endpoint 去给外部测试工具唤醒埋藏的故障点.

具体的原理实现可以查看下 gofail 的设计文档 -> design.

值的一提的是 pingcap 重新基于 gofail 重新造了个轮子, 做了不少优化:
failpoint 相关代码不应该有任何额外开销;
不能影响正常功能逻辑,不能对功能代码有任何侵入;
failpoint 代码必须是易读、易写并且能引入编译器检测;
最终生成的代码必须具有可读性;
生成代码中,功能逻辑代码的行号不能发生变化(便于调试);
如果想要了解它的实现原理, 可以查看这篇官方文章: Golang Failpoint 的设计与实现
这篇深度剖析的博客也值得一读: 在 Go 中使用 Failpoint 注入故障

接下来我们看看如何在 etcd 中启用这些故障埋点。

编译出可供进行故障测试的 etcd

etcd 官方仓库的 Makefile 已经内置了对应的指令帮我们快速编译出包含故障点二进制 etcd server. 编译步骤大致如下:

git clone [email protected]:etcd-io/etcd.git
cd etcd

# 激活故障点注释
make gofail-enable
make build
# 还原代码
make gofail-disable

经过如上步骤之后, 编译好的二进制文件直接可以在 bin 目录下可以看到, 让我们启动 etcd 看一下:

# 开启通过 HTTP 激活故障点的方式
GOFAIL_HTTP="127.0.0.1:22381" ./bin/etcd

使用 curl 看下有哪些故障点可以使用:

curl http://127.0.0.1:22381

afterCommit=
afterStartDBTxn=
afterWritebackBuf=
applyBeforeOpenSnapshot=
beforeApplyOneConfChange=
beforeApplyOneEntryNormal=
beforeCommit=
beforeLookupWhenForwardLeaseTimeToLive=
beforeLookupWhenLeaseTimeToLive=
beforeSendWatchResponse=
beforeStartDBTxn=
beforeWritebackBuf=
commitAfterPreCommitHook=
commitBeforePreCommitHook=
compactAfterCommitBatch=
compactAfterCommitScheduledCompact=
compactAfterSetFinishedCompact=
compactBeforeCommitBatch=
compactBeforeCommitScheduledCompact=
compactBeforeSetFinishedCompact=
defragBeforeCopy=
defragBeforeRename=
raftAfterApplySnap=
raftAfterSave=
raftAfterSaveSnap=
raftAfterWALRelease=
raftBeforeAdvance=
raftBeforeApplySnap=
raftBeforeFollowerSend=
raftBeforeLeaderSend=
raftBeforeSave=
raftBeforeSaveSnap=
walAfterSync=
walBeforeSync=

知道了故障点, 就可以针对指定故障设置故障类型, 如下:

# beforeLookupWhenForwardLeaseTimeToLive 故障点处 sleep 1 秒
curl http://127.0.0.1:22381/beforeLookupWhenForwardLeaseTimeToLive -XPUT -d'sleep(10000)'
# 查看故障点状态
curl http://127.0.0.1:22381/beforeLookupWhenForwardLeaseTimeToLive
sleep(1000)

故障点的描述语法见: https://github.com/etcd-io/gofail/blob/master/doc/design.md#syntax

至此, 已经可以利用 etcd 内置的故障点做一些故障模拟测试了, 具体怎么使用这些故障点可以参考下 etcd 官方的集成测试实现 -> etcd Robustness Testing. 通过故障点名称搜索相关代码即可.

除了上述这些 etcd 内置的故障点, etcd 的官方仓库也提供了一份系统级的集成测试例子 -> etcd local-tester, 它模拟了 etcd 集群模式下的节点宕机测试.

好了, 本文的分享, 到此暂时结束啦 ღ( ´・ᴗ・` )~

小广告插播: 最近维护了可以维护多个 etcd server、etcdctl、etcductl 版本的工具 vfox-etcd, 你也可以用它来在机器上安装多个包含 failpoint 的 etcd 版本进行混沌 (故障模拟) 测试哦~

本文由博客一文多发平台 OpenWrite 发布!

标签:etcd,二进制,MongoDB,gofail,故障,故障注入,测试
From: https://www.cnblogs.com/sikongji-yeshan/p/18201474

相关文章

  • mongo replicaset=rs0 com.mongodb.MongoSocketException: centosc
    1、描述虚拟机搭建mongo副本集虚拟机的设定的hostname为: centosc。虚拟机IP为192.168.25.129搭建三个副本集端口分别为,28017、28018、28019,运行mongo副本集报错,报错信息如下:2024-05-2010:22:39:235[main]INFOorg.apache.coyote.http11.Http11NioProtocol-StartingProtocol......
  • MongoDB基础知识梳理笔记
    1、mongodb是什么?MongoDB是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB旨在给WEB应用提供可扩展的高性能数据存储解决方案。MongoDB将数据存储给一个文档,数据结构由键值(key=>value)对组成......
  • 记一次k8s etcd报错Unhealthy
    使用命令某个节点ectd不健康#kubectlgetcsNAMESTATUSMESSAGEERRORcontroller-managerHealthy......
  • mongodb数据库:手动释放磁盘空间
    平台:阿里云mongoDB云数据库版本:Mongodb4.2数据库集群方案:一主二从三分片需求:手动释放过剩磁盘空间从文档解析可知:delete数据或者做分片数据迁移,并不会释放磁盘空间,而是将这些空间标记为reuse可重用状态,后续新写入的数据会重用这部分空间。需求是手动释放这些空间,使用compact......
  • Etcd开启grpc请求耗时监控
    针对各种类型grpc请求耗时统计场景,etcd提供监控数据。#etcd容器增加环境变量env:-name:ETCD_METRICSvalue:extensivecurl-shttp://127.0.0.1:2381/metrics|grepgrpc_server_handling_seconds_bucketgrpc_method包含了Alarm/AuthDisable/AuthEnable/Authenticate/......
  • Etcd开启trace
    针对处理耗时超过100ms的grpc请求,etcd打印包含耗时长的阶段的trace日志。#etcd容器增加环境变量env:-name:ETCD_LOGGERvalue:zaptrace日志举例{"level":"info","ts":"2024-05-13T14:16:45.478Z","caller":"traceutil/trace.......
  • etcd集群搭建
    主机环境和分配规划:主机ip  主机名  操作系统环境  操作系统版本172.17.0.2etcd01centos7.9172.17.0.3etcd02centos7.9172.17.0.4etcd03centos7.9etcd官网下载,我这边下载的是v3.4.32版本https://objects.githubusercontent.com/github-product......
  • mongodb keysExamined ,mongodb nreturned
    keysExamined是MongoDB查询执行阶段的一个指标,用于表示在索引扫描过程中检查的界内和界外键的总数。这个值可以帮助我们了解查询是否有效地利用了索引。如果keysExamined的值大于0,这意味着查询正在使用索引。如果keysExamined的值非常高,但返回的文档数量(nreturned)却很低,这可能表明......
  • mongodb 收集统计信息
    在MongoDB中,收集统计信息主要可以通过以下几种方法实现:使用db.collection.stats()命令:这个命令可以返回指定集合的详细统计信息,包括文档数量、索引数量和大小等。此外,还可以通过设置indexDetails:true参数来获取与每个索引相关的详细信息。使用index_stats()函数:这个函数专......
  • mongodb单实例开启oplog
    需求DTS传输同步数据的需求,需要将mongodb里的数据更新、数据增加操作同步给FC函数MongoDB中的Oplog(操作日志)是一个特殊的集合,用于记录数据库的所有操作。Oplog是MongoDB复制集中的一个重要组成部分,它允许从节点通过读取Oplog来实现与主节点的数据同步。所以要把单实例调整成复......