etcd 和 MongoDB 的混沌(故障注入)测试方法
最近在对一些自建的数据库 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 git@github.com: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 的混沌(故障注入)测试方法的更多相关文章
- 统一集中管理系统cronsun简介,替代crontab
一.背景 crontab 是 Linux 系统里面最简单易用的定时任务管理工具,相信绝大多数开发和运维都用到过.在咱们公司,很多业务系统的定时任务都是通过 crontab 来定义的,时间长了后会发现存 ...
- 替代crontab,任务计划统一集中管理系统cronsun简介
一.背景 crontab 是 Linux 系统里面最简单易用的定时任务管理工具,相信绝大多数开发和运维都用到过.在咱们公司,很多业务系统的定时任务都是通过 crontab 来定义的,时间长了后会发现存 ...
- Dapr是如何简化微服务的开发和部署
基于微服务设计模式的现代应用程序面临着一系列挑战.微服务需要有一个强大的服务发现机制来实现动态连接.它们需要松散耦合,实现自主性和独立缩放.微服务需要支持多种语言,其中每个服务都是以最合适的语言.框架 ...
- 在 Ali Kubernetes 系统中,我们这样实践混沌工程
在传统的软件测试中,我们通常通过一个给定的条件来判断系统的反馈,通过断言来判断是否符合预期,测试条件和结果通常比较明确和固定.而混沌工程,是通过注入一些“不确定”因素,象放进了一群淘气的猴子,在系统资 ...
- 万级K8s集群背后etcd稳定性及性能优化实践
背景与挑战 随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云容器服务TKE服务数量和核数大幅增长, 另一方面我们提供的容器服务类型(TKE托管及独立集群.EKS弹性集群.edge边缘计算集群.m ...
- 万级K8s集群背后 etcd 稳定性及性能优化实践
1背景与挑战随着腾讯自研上云及公有云用户的迅速增长,一方面,腾讯云容器服务TKE服务数量和核数大幅增长, 另一方面我们提供的容器服务类型(TKE托管及独立集群.EKS弹性集群.edge边缘计算集群.m ...
- Mongodb的安装使用
1.下载 最好不要去.com的那个网站下载: 各个版本的下载地址: http://dl.mongodb.org/dl/win32/x86_64 2.压缩包版本: 下载压缩包版本,目录结构如图: ...
- MongoDB的真正性能-实战百万用户一-一亿的道具
使用情景 开始之前,我们先设定这样一个情景: 1.一百万注册用户的页游或者手游,这是不温不火的一个状态,刚好是数据量不上不下的一个情况.也刚好是传统MySql数据库性能开始吃紧的时候. 2.数据库就用 ...
- [CoreOS 转载] CoreOS实践指南(五):分布式数据存储Etcd(上)
转载:http://www.csdn.net/article/2015-01-22/2823659 摘要:在“漫步云端:CoreOS实践指南”系列的前几篇,分别介绍了如何架设CoreOS集群,系统服务 ...
- [转载]MongoDB的真正性能
最近开始研究MySQL和MongoDB,发现这方面资料不多.尤其是真正的说到点子上的文章,太少了. 有一些对比测试的文章基本上都是瞎测,测试方法都测到了马腿上,得出的结论基本上都是NoSQL毫无价值 ...
随机推荐
- 移动端H5页面在不同Android和iOS设备上的兼容适配
@charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...
- SpringBoot2 可以使用 SolonMCP 开发 MCP(江湖救急)
MCP 官方的 java-sdk 目前要求 java17+(直接使用 sdk 也比较复杂).Spring-AI(有 MCP 内容)也是要求 java17+. SpringBoot2 怎么办? 使用 S ...
- 为Feign客户端自定义ErrorDecoder
摘要:重写Feign的错误解码器ErrorDecoder,以自定义业务逻辑. ErrorDecoder,顾名思义,它是发生错误或者异常情况时使用的一种解码器,允许我们对异常进行特殊处理. 在配 ...
- Linux命令之Telnet的使用方法
无论是linux还是windows,在命令行下,telnet命令都可以用于查看某个远端主机端口或者服务域名是否可以访问,语法糖如下: telnet IP 端口 telnet 域名 端口(即:telne ...
- MySQL Explain查看执行计划详解
目录 前言 EXPLAIN 中的列 id 和select_type table type possible_keys key 和 key_len ref 和 rows Extra 小结 Referen ...
- Spread Ribbon 工具栏控件:在WinForms中高效编辑Spread工作簿
引言 在数据密集型应用中,电子表格功能是提升用户体验的关键要素.GrapeCity Spread.NET V17 推出的独立 Ribbon工具栏控件,为WinForms开发者提供了与Excel高度一致 ...
- Elastic学习之旅 (6) Query DSL
大家好,我是Edison.首先说声抱歉,这个ES学习系列很久没更新了,现在继续吧. 上一篇:ES的倒排索引和Analyzer 什么是Query DSL DSL是Domain Specific Lang ...
- C++ deque容器操作 总结
------------------------------------ deque容器 双口容器 -----基本操作: 插入 push_back() push_front() insert() fr ...
- DotNetCore 提示 系统不支持“big5”编码。System does not support 'big5' encoding.
C# .NET Core 以 Big 5 (大五碼)編碼格式讀取檔案 (ruyut.com) C# .NET Core 以 Big 5 (大五碼)編碼格式讀取檔案 日期: 4月 27, 2022 之前 ...
- 一款开源免费、通用的 WPF 主题控件包
前言 今天大姚给大家分享一款开源免费(MIT License).通用的 WPF 主题控件包:Rubyer WPF. WPF介绍 WPF是一个强大的桌面应用程序框架,用于构建具有丰富用户界面的 Wind ...