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

打印 上一主题 下一主题

主题 653|帖子 653|积分 1959


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

MongoDB 是比较世界上热门的文档型数据库, 支持 ACID 事务、分布式等特性.
社区上大部分对 MongoDB 举行混沌(故障)测试的文章大多都是外围通过对 monogd 或 mongos 举行做处理举行模拟的. 好比如果想要让 MongoDB 自己触发副本集切换, 可以通过一下如许一段 shell 脚本:
  1. # 将副本集主节点进程挂死
  2. kill -s STOP <mongodb-primary-pid>
  3. # 挂死之后, 业务受损, MongoDB 在几秒到十几秒应该会进程主备切换
  4. # 切换完成后, 业务能自动将连接切换到新的工作正常的主节点, 无需人工干预, 业务恢复正常
  5. # 这里一般验证的是 Mongo Client Driver 的可靠性
复制代码
上面提到的手段一般是系统层级的, 如果我们只是想要模拟某个 MongoDB command 命令遇到网络题目了, 怎么做?进一步想要举行更细粒度的测试. 其实 MongoDB 在 4.x 以上版本内部已经实现了一套可控的故障点模拟机制 -> failCommand.
在测试环境部署 MongoDB 副本集的时候, 一般可以通过以下方式启动这个特性:
  1. mongod --setParameter enableTestCommands=1
复制代码
然后我们可以通过 mongo shell 针对特定的 command 开启故障点, 例如针对一次 find 操作让其返回错误码 2:
  1. db.adminCommand({
  2.     configureFailPoint: "failCommand",
  3.     mode: {
  4.       "times": 1,
  5.     },
  6.     data: {errorCode: 2, failCommands: ["find"]}
  7. });
复制代码
这些故障点模拟是可控的, 成本相对于必直接在机器上搞破坏比较低, 也很适合融入连续集成自动化流程. 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 去对可能发生题目的地方埋藏一些故障注入点, 偏于举行测试验证, 例如:
  1.         if t.backend.hooks != nil {
  2.                 // gofail: var commitBeforePreCommitHook struct{}
  3.                 t.backend.hooks.OnPreCommitUnsafe(t)
  4.                 // gofail: var commitAfterPreCommitHook struct{}
  5.         }
复制代码
在使用 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. 编译步骤大抵如下:
  1. git clone git@github.com:etcd-io/etcd.git
  2. cd etcd
  3. # 激活故障点注释
  4. make gofail-enable
  5. make build
  6. # 还原代码
  7. make gofail-disable
复制代码
经过如上步骤之后, 编译好的二进制文件直接可以在 bin 目录下可以看到, 让我们启动 etcd 看一下:
  1. # 开启通过 HTTP 激活故障点的方式
  2. GOFAIL_HTTP="127.0.0.1:22381" ./bin/etcd
复制代码
使用 curl 看下有哪些故障点可以使用:
  1. curl http://127.0.0.1:22381
  2. afterCommit=
  3. afterStartDBTxn=
  4. afterWritebackBuf=
  5. applyBeforeOpenSnapshot=
  6. beforeApplyOneConfChange=
  7. beforeApplyOneEntryNormal=
  8. beforeCommit=
  9. beforeLookupWhenForwardLeaseTimeToLive=
  10. beforeLookupWhenLeaseTimeToLive=
  11. beforeSendWatchResponse=
  12. beforeStartDBTxn=
  13. beforeWritebackBuf=
  14. commitAfterPreCommitHook=
  15. commitBeforePreCommitHook=
  16. compactAfterCommitBatch=
  17. compactAfterCommitScheduledCompact=
  18. compactAfterSetFinishedCompact=
  19. compactBeforeCommitBatch=
  20. compactBeforeCommitScheduledCompact=
  21. compactBeforeSetFinishedCompact=
  22. defragBeforeCopy=
  23. defragBeforeRename=
  24. raftAfterApplySnap=
  25. raftAfterSave=
  26. raftAfterSaveSnap=
  27. raftAfterWALRelease=
  28. raftBeforeAdvance=
  29. raftBeforeApplySnap=
  30. raftBeforeFollowerSend=
  31. raftBeforeLeaderSend=
  32. raftBeforeSave=
  33. raftBeforeSaveSnap=
  34. walAfterSync=
  35. walBeforeSync=
复制代码
知道了故障点, 就可以针对指定故障设置故障范例, 如下:
  1. # beforeLookupWhenForwardLeaseTimeToLive 故障点处 sleep 1 秒
  2. curl http://127.0.0.1:22381/beforeLookupWhenForwardLeaseTimeToLive -XPUT -d'sleep(10000)'
  3. # 查看故障点状态
  4. curl http://127.0.0.1:22381/beforeLookupWhenForwardLeaseTimeToLive
  5. 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 发布!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表