分布式系统测试那些事儿——信心的毁灭与重建

本话题系列文章整理自 PingCAP NewSQL Meetup 第 26 期刘奇分享的《深度探索分布式系统测试》议题现场实录。文章较长,为方便你们阅读,会分为上中下三篇,本文为下篇。html

接中篇:
ScyllaDB 有一个开源的东西,是专门用来给文件系统作 Failure Injection 的, 名字叫作 CharybdeFS。若是你想测试你的系统,就是文件系统在哪不断出问题,好比说写磁盘失败了,驱动程序分配内存失败了,文件已经存在等等,它均可以测模拟出来。java

CharybdeFS: A new fault-injecting file system for software testingsql

Simulate the following errors:数据库

  • disk IO error (EIO)网络

  • driver out of memory error (ENOMEM)并发

  • file already exists (EEXIST)app

  • disk quota exceeded (EDQUOT)框架

再来看看 Cloudera,下图是整个 Cloudera 的一个 Failure Injection 的结构。dom

7.png

一边是 Tools,一边是它的整个的 Level 划分。好比说整个 Cluster, Cluster 上面有不少 Host,Host 上面又跑了各类 Service,整个系统主要用于测试 HDFS, HDFS 也是很努力的在作有效的测试。而后每一个机器上部署一个 AgenTEST,就用来注射那些可能出现的错误。tcp

看一下它们做用有多强大。

Cloudera: Simulate the following errors:

  • Packets loss/corrupt/reorder/duplicate/delay

  • Bandwidth limit: Limit the network bandwidth for the specified address and port.

  • DNSFail: Apply an injection to let the DNS fail.

  • FLOOD: Starts a DoS attack on the specified port.

  • BLOCK: Blocks all the packets directed to 10.0.0.0/8 (used internally by EC2).

  • SIGSTOP: Pause a given process in its current state.

  • BurnCPU/BurnIO/FillDISK/RONLY/FIllMEM/CorruptHDFS

  • HANG: Hang a host running a fork bomb.

  • PANIC: Force a kernel panic.

  • Suicide: Shut down the machine.

数据包是能够丢的,能够坏的,能够 reorder 的,好比说你发一个 A,再发一个 B,它能够给你 reorder,变成先发了 B 再发了 A,而后看你应用程序有没有正确的处理这种行为。接着发完一次后面再给你重发,而后能够延迟,这个就比较简单。目前这个里面的大部分,TiKV 都有实现,还有带宽的限制,就好比说把你带宽压缩成 1M。之前咱们遇到一个问题颇有意思,发现有人把文件存到 Redis 里面,但 Redis 是带多个用户共享的,一个用户就能把整个 Redis 带宽给打满了,这样其余人的带宽就很卡,那这种很卡的时候 Redis 可能出现的行为是什么呢?咱们并不须要一个用户真的去把它打满,只要用这种工具,瞬间就能出现我把你的带宽限制到原来的 1%,假设别人在跟你抢带宽,你的程序行为是什么?立刻就能出来,也不须要配很复杂的环境。这极大的提升了测试效率,同时能测试到不少 corner case。

而后 DNS fail。那 DNS fail 会有什么样的结果?有测过吗?可能都没有想过这个问题,可是在一个真正的分布式系统里面,每一点都是有可能出错的。还有 FLOOD,假设你如今被攻击了,整个系统的行为是什么样的?而后一不当心被这个 IP table 给 block 了,该怎么办。这种状况咱们确实出现过。咱们一上来并发,两万个链接一打出去,而后发现大部分都连不上,后来一看 IP table 自动启用了一个机制,而后把大家都 block。固然咱们后面查了半个小时左右,才把问题查出来。但这种实际上应该是在最开始设计的时候就应该考虑的东西。

若是你的进程被暂停了,好比说你们在云上跑在 VM 里面,整个 VM 为了升级,先把你整个暂停了,升级完以后再把你恢复的时候会怎么样?那简单来说,就是若是假设你程序是有 GC 的,GC 如今把咱们的程序卡了五秒,程序行为是正常的吗?五十秒呢?这个颇有意思的就是,BurnCPU,就是再写一个程序,把 CPU 全占了,而后让你这个如今的程序只能使用一小部分的 CPU 的时候,你程序的行为是否是正常的。正常来说,你可能说我 CPU 不是瓶颈啊,我瓶颈在 IO,当别人跟你抢 CPU,把你这个 CPU 压的很低的时候,到 CPU 是瓶颈的时候,正常你的程序的这个行为是否是正常的?还有 IO,跟你抢读的资源,跟你抢写的资源,而后 filedisk 把磁盘写满,写的空间不多。好比说对数据库而言,你建立你的 redo log 的时候,都已经满了会怎么样?而后我忽然把磁盘设为只读,就你忽然一个写入会出错,可是你接下来正常的读写行为是否是对的?很典型的一个例子,若是一个数据库你如今写入,磁盘满了,那外面读请求是否就能正常响应。 Fill memory,就是瞬间把这个 memory 给压缩下来,让你下次 malloc 的时候可能分布不到内存。这个就和业务比较相关了,就是破坏 HDFS 的文件。其它的就是 Hang、Panic,而后还有自杀,直接关掉机器,整个系统的行为是什么样的?

如今比较痛苦的一点是你们各自为政,每一家都作一套,可是没有办法作成一个通用的东西给全部的人去用。包括咱们本身也作了一套,可是确实没有办法和其余的语言之间去 share,最先提到的那个 libfu 库其实是在 C 语言写的,那全部 C 相关的均可以去 call 那个库。

Distributed testing

  • Namazu

    • ZooKeeper:

      • Found ZOOKEEPER-2212, ZOOKEEPER-2080 (race): (blog article)

    • Etcd:

      • Found etcdctl bug #3517 (timing specification), fixed in #3530. The fix also resulted a hint of #3611, Reproduced flaky tests {#4006, #4039}

    • YARN: Found YARN-4301 (fault tolerance), Reproduced flaky tests{1978, 4168, 4543, 4548, 4556}

而后 Namazu。你们确定以为 ZooKeeper 很稳定呀, Facebook 在用、阿里在用、京东在用。你们都以为这个东西也是很稳定的,直到这个工具出现了,而后轻轻松松就找到 bug 了,全部的你们认为的这种特别稳定的系统,其实 bug 都还挺多的,这是一个毁三观的事情,就是你以为东西都很稳定,都很 stable,其实不是的。从上面,咱们能看到 Namazu 找到的 Etcd 的几个 bug,而后 YARN 的几个 bug,其实还有一些别的。

How TiKV use namazu

  • Use nmz container / non-container mode to disturb cluster.

    • Run container mode in CI for each commit. (1 hour)

    • Run non-container mode for a stable version. (1 week+)

  • Use extreme policy for process inspector

    • Pick up some processes and execute them with SCHED_RR scheduler. others are executed with SCHED_BATCH scheduler

  • Use [0, 30s] delay for filesystem inspector

接下来讲一下 TiKV 用 Namazu 的一些经验。由于咱们曾经在系统上、在云上面出现过一次写入磁盘花了五十几秒才完成的状况,因此咱们须要专门的工具模拟这个磁盘的抖动。有时候一次写入可能确实耗时比较久,那这种时候是否是 OK 的。你们若是能把这种东西通通用上,我以为还能为不少开源系统找出一堆 bug。

稍微介绍一下咱们如今运行的基本策略,好比说咱们会用 0 到 30 秒的这个 delay (就是每一次你往文件系统的交互,好比说读或者写,那么咱们会给你产生随机的 0 到 30 秒的 delay ),但咱们正常应该仍是须要去测三十秒到几分钟的延迟的状况,是否会让整个系统崩掉了。

How TiKV simulate network transport

  • Drop/Delay messages randomly

  • Isolate Node

  • Partition [1, 2, 3, 4, 5] -> [1, 2, 3] + [4, 5]

  • Out of order messages

  • Filter messages

  • Duplicate and send redundant messages

怎么模拟网络呢?假设你有网络,里面有五台机器,那我如今想作一个脑裂怎么作?不能靠拔网线对吧?好比在 TiKV 的测试框架中,咱们就能够直接经过 API 把 5 个节点脑裂成两部分,让 1, 2, 3 号节点互相联通,4, 5 号节点也能联通,这两个分区彼此是隔离的,很是的方便。其实原理很简单,这种状况是用程序本身去模拟,假如是你发的包,自动给你丢掉,或者直接告诉你 unreachable,那这个时候你就知道这个网络就脑裂了,而后你怎么作?就是只容许特定类型的消息进来,把其余的都丢掉,这样一来你能够保证有些 bug 是必然重现的。这个框架给了咱们极大的信心用来模拟并重现各类 corner case,确保这些 corner case 在单元测试中每次都能被覆盖到。

How to test Rocksdb

  • Treat storage as a black box.

  • Three steps(7*24):

    • Fill data, Random kill -9

    • Restart

    • Consistent check.

  • Results:

    • Found 2 bugs. Both fixed

而后说说咱们怎么测 RocksDB。 RocksDB 在你们印象中是很稳定的,但咱们最近发现了两个 bug。测的方法是这样的:咱们往 RocksDB 里面填数据,而后随机的一段时间去把它 kill 掉,kill 掉以后咱们重启,从新启动以后去检测咱们刚才 fail 的 data 是否是一致的,而后咱们发现两个可能形成数据丢失的 bug,可是官方的响应速度很是快,几天就都 fix 了。但是你们广泛运行的是这么 stable 的系统,为何还会这么容易找到 bug?就说这个测试,若是是一直有这个测试的 cover,那么这两个 bug 可能很快就可以被发现。

这是咱们一个基本的,也就是当成一个纯黑盒的测。你们在测数据库的时候,基本也是当黑盒测。好比说 MySQL 写入数据,kill 掉,好比说我 commit 一个事务,数据库告诉咱们 commit 成功,我把数据库 kill 掉,我再去查我刚才提交的数据同样能查到。这是一个正常的行为,若是查不到,说明整个系统有问题。

More tools

  • american fuzzy lop

8.png

其实还有一些更加先进的工具,你们平时以为特别稳定的东西,都被摧残的不行。Nginx 、NGPD、tcpdump 、LibreOffice ,若是有用 Linux 的同窗可能知道,还有 Flash、sqlite。这个东西一出来,当时你们很兴奋,说怎么一会儿找了这么多 bug,为何之前那么稳定的系统这么不堪一击,会以为这个东西它还挺智能的。就好比说你程序里面有个 if 分支,它是这样的,假如你程序有一百条指令,它先从前面一直走,走到某条分支指令的时候,它是一直持续探索,一个分支走不下去,它会一直在这儿持续探索,再给你随机的输入,直到我探索进去了,我记下来了下次我知道我用这个输入能够进去特定的分支。那我能够再往下走,好比说你 if 分支进去以后里面还有 if ,那你传统手段可能探测不进去了但它能够,它记录一下,我这个能够进去,而后我重来,反正我继续输入这个,我再往里面走,一旦我探测到一个新的分支,我再记住,我再往里面走。因此它一出来的时候你们都说这个真厉害,一下发现这么多 bug。但最激动的不是这些人,最激动的是黑客,为何?由于忽然有不少栈溢出、堆溢出漏洞被发现了,而后就能够写一堆工具去攻击线上的这么多系统。因此不少的技术的推动在早期的时候是黑客作出来,可是他们的目的固然不必定是为了测试 bug,而是为了怎么黑一个系统进去,这是他们当时作的,因此这个工具也是很是强大、很是有意思的,你们能够拿去研究一下本身的系统。

你们印象里面各类文件系统是很稳定的,但是当用 American fuzzy lop 来测试的时候,被惊呆了。 Btrfs 连 5 秒都没有坚持到就跪了,你们用的最多的 Ext4 是最坚挺的,也才抗了两个小时!!!

9.png

再来讲说 Google,Google 怎么作测试对外讲的很少,最近 Chrome team 开源了他们的 Fuzz 测试工具 OSS-Fuzz,这个工具强大的地方在于自动化作的极好:

  • 发现 bug 后自动建立 issue

  • bug 解决后自动 verify

更惊人的是 OSS-Fuzz 集群一周能够跑 ~4 trillion test cases 更多细节你们能够看这篇文章:Announcing OSS-Fuzz: Continuous Fuzzing for Open Source Software

另外有些工具能让分布式系统开发人员的生活变得更美好一点。

Tracing tools may help you

  • Google Dapper

  • Zipkin

  • OpenTracing

还有 Tracing,好比说我一个 query 过来,而后通过这么多层,通过这么多机器,而后在不一样的地方,不一样环节耗时多久,实际上这个在分布式系统里面,有个专门的东西作 Tracing ,就是 distribute tracing tools。它能够用一条线来表达你的请求在各个阶段耗时多长,若是有几段,那么分到几个机器,分别并行的时候好了多长时间。大致的结构是这样的:

10.png

这里是一个具体的例子:

11.png

很清晰,一看就知道了,不用去看 log,这事其实一点也不新鲜,Google 十几年前就作了一个分布式追踪的工具。而后开源社区要作一个实现叫作 Zipkin,好像是 java 仍是什么写的,又出了新的叫 OpenTracing,是 Go 写的。咱们如今正准备上这个系统,用来追踪 TiDB 的请求在各个阶段的响应时间。

最后想说一下,你们研究系统发现 bug 多了以后,不要对系统就丧失了信心,毕竟bug 一直在那里,只是从前没有发现,如今发现得多了,整体上新的测试方法让系统的质量比之前好了不少。好像有点超时了,先聊到这里吧,还有好多细节无法展开,下次再聊。(本系列完结)

相关文章
相关标签/搜索