“持续”和“混沌工程”嫁接的火花

DevOps 系列

Posted by 薛以致用 on November 22, 2020

11月21日在成都参与中国 DevOps 社区精心准备的思想碰撞,现场吸引了 300多位 DevOps 爱好者们,有限的25分钟日程中,我快速表达了对于 DevOps 和混沌工程结合及发展趋势,意犹未尽,周末花了点时间整理成文字,一来坚持文字表达要比 PPT 更全面,也便于更多混沌工程爱好者分享和参与探讨,其次,把其中的一些故事和实践更具体呈现给社区,期待有中国的混沌工程即服务的产品出现。

长跑前的热身

DevOps 的“莫比乌斯环”状的标志性迭代循环,不知道是否意味着 DevOps 是一段没有终点的旅程,而其中不断奔跑的人和团队,演绎出一段段精彩的传奇故事;云计算的发展,是分布式系统大放异彩的时代,而追求高性能、高可用性、高扩展性、高安全性、高性价比是客户永不满足的追求;传统企业应用的灾难恢复,定义出了 RTO 和 RPO 来衡量我们对于系统可用和数据完整的量化要求,当系统变得越来越复杂,一个系统输入的因子,带来的结果变得不是那么好预测和控制;那什么是复杂的系统呢?

以亚马逊电商为例,从单体架构改造成微服务架构之后,想象下微服务的数量达到 2万的量级,2019年每秒有 6次部署的频率在更新迭代,团队的测试努力能覆盖所有关键业务功能路径就已经非常不错了,有没有因素会导致系统整体崩溃呢?影响用户体验的事件到底有哪些?很难回答。

再以 AWS 云服务为例,目前最新的官方数据有 175种功能全面的服务类别,24个区域,77个可用区,服务全球数百万活跃客户和数万个合作伙伴,这些数字的组合,满足各行业应用场景所带来的复杂性,是难以想象的;

如果大家真要了解什么是复杂,学习什么是机械体,什么是生物体,为什么整体大于部分之和,熵增和熵减,有序和无序,进化论和还原论,推荐大家看 Melanie Mitchell 的《复杂》这本书;

那混沌工程可以给我们带来什么样的价值呢?

我们首先看一个 Twilio 的案例,Twilio 和刚刚上市的声网业务类似,专注于通讯接口服务,面向开发者,提供封装好的简单易用的通讯 API 接口(云通讯服务),目前市值已经450亿美金;该团队 2017年一篇博文里面分享了一个有趣的实验,在他们的 Service Mesh 平台中,团队准备从 HTTP/1 升级到 Envoy HTTP/2,引入了一个失败注入实验,利用 tc 命令给他们的服务注入 0~25ms网络延迟以及 1%或3%的网络丢包,观察服务在不同协议下的表现,实验结果有一个新的发现,在 25ms 延迟和 3% 的丢包场景下,p99 的延迟数据显示,HTTP/2 的表现比 HTTP/1 糟糕太多!!!更详细内容大家请参考文末原文。

我想大家对于混沌工程已经有点热身了,我们来看看社区的一个定义:

混沌工程是在分布式系统上进行实验的学科, 目的是建立对系统抵御生产环境失控条件的能力以及信心!

我也比较喜欢 Adrian Cockcoft 的一个更简化的定义:

进行实验来弱化分布式系统故障(失败)所带来的影响 Experiment to ensure that the impact of failure is mitigated!

混沌工程自循环

ChaosEngineer Cycle

混沌工程自身是一个自洽的一个循环实践,从上图可知,简单而言,先定义系统稳态,到围绕系统稳态定义假说,设计包含恰当故障注入的实验,收集实验结果,验证假说是否成立或是否有新发现,总结和持续改进;

系统的稳态定义,建议从核心业务指标入手,再对应细化的具体的技术指标,比如对于一个电商而言,每秒订单数是核心业务指标,对于一个在线流媒体服务商而言,比如奈飞,每秒点击播放次数是核心业务指标;类似还可能有用户注册数,点赞转发数等等;

ChaosIQ 的在线工具,提供了一整套的混沌工程向导,可以生成可重用的 JSON 定义,并提供相应的命令行工具以及结果的收集,可视化展示。

Sample

首先定义一个团队目标,比如 “Rails home response well under different backend incidents”, 在这个目标下,可以定义多个验证,每个验证,包含一个稳态定义,采集指标以及实验条件:

比如,这个例子,我们可以定义一个稳态假说是,Rails 首页响应时间始终小于 3ms,指标采集每 5秒中采集一次 HTTP 请求延迟,并持续 24小时;注入什么样的故障实验呢?这里我们随机在容器环境中杀掉 50%的 Rails 首页容器服务实例;

执行就很简单,

chaos verify ~/environment/chaos/rails-full.json

执行完就可以在对应的 ChaosIQ控制台看到对应的报表和数据进行分析和理解了;

从零到一:如何注入故障?

估计很多人已经听不下去了,每天加班搬砖,无论开发还是运维都是为了避免故障发生,你到好,故意注入故障,找抽吧。哈哈,回到混沌工程的初心,首先,大家都要认识到,分布式复杂系统,故障总是意料之外情理之中发生,其次,根据墨菲定律,怕什么来什么,为了晚上能安稳的睡觉,我们何不正视这些故障场景?

就像人类学会种痘来获得天花免疫能力一样,注入故障实验,能进化我们的系统使之变得更有韧性,奈飞团队更是发展到在白天工作时间,在生产环境进行混沌工程,实验和发现系统对于可控的故障注入的反应,并不断提供数据反馈给整个团队;

Experiment Toolkit on AWS

目前 AWS 的客户,可以参考上图里面列出的社区和 AWS 官方的一些参考实现,有托管服务原生支持的故障注入,比如 Amazon Aurora服务,也有利用 System Manager 的代理执行定义好的脚本,也有开源 Chaos Toolkit 对于 AWS 的扩展库;我们以亚马逊 PrimeVideo 团队的一个混沌实验代码(kotlin)为例,模拟一个依赖的第三方服务调用在网络丢包情况下的反应,这里通过 AWS SDK 调用 SSM 服务接口,在相应的服务运行环境中模拟网络丢包场景:

// https://github.com/amzn/awsssmchaosrunner

/**
 * This attack drops packets to an AWS service using the CIDR ranges returned from
 * https://ip-ranges.amazonaws.com/ip-ranges.json. This is useful for services like S3
 * and DynamoDB which have a wide range of IP addresses. Otherwise it behaves similar
 * to the DependencyPacketLossAttack.
 */
class AWSServicePacketLossAttack constructor(
    override val ssm: AWSSimpleSystemsManagement,
    override val configuration: SSMAttack.Companion.AttackConfiguration
) : AbstractAWSServiceAttack(ssm, configuration) {
    override val chaosContent: String
        get() {
            return "    - \"sudo tc qdisc add dev eth0 root handle 1: prio priomap 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2\"\n" +
                "    - \"sudo tc qdisc add dev eth0 parent 1:1 handle 10: netem loss ${configuration.otherParameters["packetLossPercentage"]}%\"\n" +
                "    - \"for k in $($serviceCidrRangeQuery);" +
                " do echo \$k && sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst \$k match ip dport " +
                "${configuration.otherParameters["dependencyPort"]} 0xffff flowid 1:1; done\"\n" +
                "    - \"sudo tc qdisc show\"\n"
        }
}

从零到一:混沌实验的前提和准备工作

看完故障注入实验,大伙肯定很兴奋,忍不住要动手试试了,先别急,混沌实验通常都是在生产环境实施,但起步阶段,建议开发人员可以先针对自身服务以及开发测试环境进行尝试,这样的实验称为 “个人实验”,再提升一个成熟度,可以在集成环境或预生产环境进行,更接近生产环境的状况,最好可以借助生产环境流量镜像,也可以通过 Gatling,Locust或JMeter模拟压力环境,最后再把积累下来的实验脚本,在生产环境进行验证;

是不是所有的系统都适合上混沌工程呢?大家看前面的定义就感受到,混沌工程是针对复杂的分布式系统,目标是缓解故障带来的整体业务影响;因此在实施混沌工程之前,首先要夯实的系统本身的架构和代码质量;

故障的发生通常可以分为四层,最底层的基础设施层,到操作系统中间件层,再到应用本身,最后到运维;AWS 提供了业界首个基于云服务的分布式系统的优良架构框架,从安全,可靠(包含混沌工程),性能,成本和卓越运营五个方面,提供了一系列自查的问题列表,相信通过这些工具,团队可以对整体的系统的成熟度有个清晰的认识;

代码质量,跟代码规范,整洁架构,自动化测试密切相关,核心是提升开发人员的能力,才能提升团队效能构建 DevOps 持续迭代优化环,实现软件价值交付飞轮效应;

Application_Readiness

从零到一:Gameday 游戏日

还有一种混沌实验组织方式,称为 “Gameday 游戏日“,DevOps 的核心是团队协同,类似,游戏日的作用也是,类似一次消防演习,准备好环境,统一混沌实验的目标和步骤,制定应对措施等等,创造一个安全的实验环境,在一个合适的时间段把团队(所有系统涉及到的成员,不仅仅是开发或运维)集中在一起按步骤进行演习锻炼;

Gameday

关于游戏日的参考步骤和流程,可以参考: https://www.slideshare.net/BilalAybar/chaos-engineering-gameday-on-aws

关于如何利用 Gremlin 结合 AWS 优良架构验证可靠性混沌测试可以参考:

https://aws.amazon.com/blogs/apn/how-gremlins-chaos-engineering-platform-validates-aws-operational-excellence-and-reliability/

从1到100:Continuous Chaos

DevOps 所有实践中都包含“持续”这个关键词,持续的迭代(敏捷),持续的集成,持续的测试,那再加上持续的混沌工程呢?所谓持续混沌工程,就是引入混沌工程师,将混沌实践固化到自动化流水线中,实现定期的混沌自循环。

Continuous Chaos

从奈飞团队的经验来看,持续混沌工程也是一个随着业务发展不断发展的旅程,从小处着手,逐渐建立信心;比如猴子军团,一开始关注的只是随机关停虚拟机,进行故障实验发现和优化系统行为,直到实现业务对于这类故障可以无感为目标;继续发展出一批捣乱的“猴子”,比如验证机器配置是否符合奈飞最佳实践规则,虚拟机是否处于健康状态,增加服务延迟,模拟 AWS 可用区故障甚至是 Region 级别的故障等等;

Continuous Chaos+Toolkit

整个混沌工程已经处于成熟阶段,不仅仅有蓬勃发展的社区实践,比如 Chaos Toolkit,Chaos Blade,CNCF 的 Litmus,Chaos Mesh,更有商业化产品 Gremlin 和 ChaosIQ,这些成熟的工具链,从技术和实践层面降低了客户采用门槛,因此借助类似 Chaos Toolkit 或 Gremlin 这样的混沌工程框架,我们可以无缝赋能 DevOps 团队,将混沌工程适配到各种云原生平台,比如 K8S 平台,AWS 等云服务厂商,最终提升我们复杂系统应用的价值。

总结

故障或失败总是那么令人沮丧,但混沌工程的出现,让大家对于故障的认知更趋于客观,混沌实践更是提供了一套理论和方法,让团队把故障和失败通过实验,游戏日,演变成数据,从数据中,团队可以有很多发现和持续改进的线索,期待更多的国内开发者和客户关注和实践混沌工程。

参考资料

申明

本站点所有文章,仅代表个人想法,不代表任何公司立场,所有数据都来自公开资料,如有不妥的图片或内容请公众号“联系作者”

转载请注明出处


公众号二维码

诞生于 2019,遇见 2020。

感谢关注,欢迎动动手指标星和置顶;

这样就不会错过少但精彩的技术探讨、团队建设、案例分享!

每周至少一更,转发是对我的最大鼓励!

学习之路漫漫,走走停停,
偶有所感,随心所记,
言由心声,问心无愧!

从客户中来,到客户中去!