快速发现和定位问题的能力是快速恢复系统的基石。只有快速发现和定位问题,才能谈及如何解决问题,最大限度减少用户损失。那么如何在复杂的大规模场景中真正做到先于用户发现和定位问题呢?分享一下我们在管理大型Kubernetes集群过程中快速发现和定位问题的一些经验和实践——我们如何通过自研的通用链路检测+定向检测工具KubeProbe来应对我们遇到的大型集群稳定性挑战。链路检测:模拟广义的用户行为,检测链路和系统是否异常。方向检测:检查集群异常指标,发现已经存在或未来可能存在的风险点。系统增强:发现问题提速提速。配置检测与自愈,Chat-Ops01业务背景与挑战云原生阿里云云原生应用平台容器服务团队拥有ACK、ASI等产品,管理大规模Kubernetes集群。它不仅为外部公有云用户提供Kubernetes服务,还承担了阿里巴巴集团的云迁移和阿里巴巴应用的全面容器化工作。目前阿里巴巴全业务运行在Kubernetes集群上,实现了云原生和容器化,如:天猫/淘宝/高德/考拉/饿了么等。容器服务是阿里云的管控基础,各种云服务也运行在这些集群上,如视频云/Dataworks/MSE微服务引擎/MQ消息队列等,我们需要对这些基础设施的稳定性负责.现在,云原生架构越来越流行,越来越多的产品和应用开始选择云原生架构。这是一张粗略显示现代云原生应用程序架构的图片。应用在云上诞生,在云上成长。在各个层面提供分层服务。这种分层服务让业务和应用程序专注于业务层,屏蔽了平台和基础设施层的复杂概念。从稳定性来看,应用架构是分层的,上层应用的稳定性将开始依赖底层基础设施的支持;它不仅提供了场景,而且对基础设施团队维护大规模集群的稳定性提出了很大的挑战。这里有两张图可以展示云原生应用架构下业务应用和平台层基础设施的关系。Kubernetes集群非常复杂,单个集群中有几十个甚至上百个链路组件。这么多,何况是大规模的多集群管理?但是跑在上层的业务同学是不会感知到复杂性的,因为我们已经把复杂性封装起来了,留给用户的是一个简单的统一接口。像淘宝这样的应用,其实是很复杂的,但在用户眼里,只是一个简单的订单提交,按钮后面的内容极其复杂。你为什么这么做?因为我们将复杂性留给自己,将简单性留给用户。在许多情况下,优秀的应用程序开发人员不一定是基础架构专家。云原生让业务专注于业务,让基础设施专注于基础设施。同时,大部分业务只能关心业务本身的稳定性。很多时候,业务无力关心,或者不想投入大量人力去关心基础设施和平台层的稳定性。所以,在平台层和基础设施的稳定性问题上,我们要把复杂留给自己,把简单留给用户,为用户提供稳定的平台层服务。同时,我们更关心全局稳定性和全局可用性,而不是单点可用性。容器服务是阿里巴巴集团业务和阿里云管控/云服务的基础。各种业务在其上运行,如电商业务/中间件/二方业务/搜索/阿里云云服务等。此外,还有上百个自研开源组件,数十万个组件变更/每年上千个集群/数十万个节点,即使是大集群也有单个集群超过10000个节点。业务结构更加复杂,包括单租户集群、多租户集群、vc集群、联邦集群等,还有各种线下混合分发、统一调度、促销活动。运行时也有多种形式,如runC、runD等。因此,组件的复杂性、频繁的变更、不同的用户场景、大规模的集群、复杂的业务架构都给业务带来了挑战:挑战一:如何降低系统风险。场景复杂,业务形态各异。任何细节的遗漏或链接的粗心处理都可能导致损害的放大。挑战二:如何对用户集群的稳定性负责。如何在用户之前发现和定位问题,成为容器服务生产稳定性建设的重中之重,也是全球高可用体系的基石。系统如此复杂,任何一个细节的遗漏或处理不慎都可能导致意想不到的损坏,如何降低系统的风险?此外,我们如何负责运行时具有不同形状的用户集群的全局稳定性?如何在用户之前发现和定位这些集群中存在或即将出现的问题,是保证集群稳定的重中之重,也是Kubernetes全局高可用系统的基石。02思考和解决方案基于这些挑战,CloudNative做了一些思考和预设。下图是一个极其简化的用户发布扩展链接。虽然已经极度简化了,但是我们还是可以看出链接还是比较复杂的。为了保证用户的扩展/发布环节顺畅,我们首先带来几个预设:预设1:环节中有很多复杂的组件,每个组件都是单独升级迭代的,数据监控不可能无死角地覆盖所有场景;预设2:即使链路中各组件/节点的监控数据正常,也不能保证集群整体链路100%可用。只有通过实际业务全链路检测才能确定实际可用性的结论;假设三:反证的方法用来证明集群不可用肯定比证明的方法好。即使100%的监控数据正常,只要发布失败,就证明链路不可达。另外,除了单集群,我们还需要注意多集群的管理。下面举例说明多集群管控中的不稳定因素。可见,在多集群场景下,稳定性控制的复杂度会被放大。我们继续带来几个假设:假设四:在大规模集群场景下,数据一致性问题会更加明显,并可能导致严重故障,成为显着的不稳定因素;假设五:集群内监控告警链路存在自依赖风险。如果集群出现故障,监控告警也可能同时失效。以下是我们基于上述假设的一些解决方案。探索与解决方案1.链接检测链接检测广义上就是模拟用户行为,检测链接是否通畅,过程是否正常。要想先于用户发现系统问题,就必须先成为系统用户,做使用最多、了解最深、时刻使用和感知系统状态的用户。所谓链路检测,就是广义上模拟用户行为,检测集群组件链路中各种等待检测的对象。这里需要特别说明的是,这里的用户并不是指狭义上使用系统的同学,而是广义上的用户,或者可以理解延伸为依赖下游。另外,在实现全链路检测的同时,拆解电路实现整个电路的短路检测也是非常有必要的,这也是对全链路检测的一种补充。2.定向检查定向检查是指对大规模集群的异常指标进行检查分析,发现现有或未来可能存在的风险点,就像管道检修一样。比如有几个cluster,分成很多clustergroup。不同集群组之间的etcd冷/热备份配置是否完整,风控限流配置是否正常,webhook版本是否正常,混合部分参数是否一致,包括其证书的有效期是否即将到期等等。不同的集群组之间可能会有差异,但是同类型的集群之间是有平衡的,所以我们可以做一些有针对性的检查。接下来是关于链接检测的一些常见场景:就像一个游戏策划者,如果他连自己做的游戏都不玩,他可能会发现游戏机制有问题。他能让比赛变得更好吗?要想比用户先发现系统问题,首先要成为系统的用户,必须是使用最多、了解最深、无时无刻不在使用和感知系统状态的用户。另外,所谓链路检测,就是让自己成为自己系统的用户,模拟广义上“用户”的行为,检测集群/组件/链路中各种等待检测的对象。需要注意的是,这里的“用户”并不是指狭义上使用系统的同学,而是广义上的用户,或者可以理解为依赖下游。比如商科学生要发布一个业务,他必须要经过git系统,然后到发布系统,再到我们的底层基础设施平台,也就是我们的ASI。这是一个全链路检测过程。这里商科生就是用户,检测对象可以是全链路。但是如果我们把etcd当做一个系统服务,那么APIServer广义上就是它的使用者,我们模拟检测APIServer请求etcd的链接是有意义的。另外,像MSE运营zookeeper,外部用户通过阿里云控制台创建ACK集群,PaaS平台运营联邦集群,甚至视频云业务方发起转码任务,都是一样的。另外需要注意的是,虽然全链路检测看起来很漂亮,但是在很多情况下,全链路检测同时进行的时间还是很长,失败的时候问题可能已经很严重了。因此,在实现全链路检测的同时,还需要对链路进行拆解,实现全链路中的短链路检测,这也是对全链路检测的一种补充。上图是定向检查的场景。与链路检测侧重链路可用性相比,定向检测的核心还是在大规模集群场景下。数据一致性是一个非常棘手的问题。数据不一致会导致一些隐患,将来可能会导致一些非确定性故障。所谓定向检查,就是针对已知原因对整个集群或链路的各种数据和指标进行检查,找出不一致或数据偏差的点,判断是否可能引发风险,做到防患于未然治好他们的病。例如,我们有相同类型的集群组。集群A发现自己的证书有效期不到三年,而其他集群的证书有效期为三年;B集群的webhook版本可能是v2,而其他集群的webhook版本是v3;集群C的windcontrol限流配置没有配置限流驱逐pod,而其他集群配置了限流驱逐pod,这肯定不符合预期;/双机未配置或工作不正常,我们也可以先检查一下。03系统实现CloudNative基于上面的众多后台预设和解决方案,我们设计并实现了一套检查/检测平台,我们命名为KubeProbe(未开源,目前社区中也有类似名称的项目,可联系).我们早期也考虑过使用社区项目Kuberhealthy,并为Kuberhealthy做了一些代码贡献,修复了一些严重的代码错误。最后因为功能不适合我们的场景,所以我们选择了自己开发搭建。上图是一套中央架构,我们就会有一套中央控制系统。用户的用例会通过统一仓库的镜像进行访问,使用我们常用的sdk库自定义检查检测逻辑。我们会在中控系统上配置集群和用例的关系配置,比如某个用例应该在哪些集群组上执行,做各种运行时配置。我们支持周期触发/手动触发/事件触发(如发布)的用例触发方式。用例被触发后,集群中会创建一个执行检查/检测逻辑的Pod。用户自定义的各种业务检查/检测逻辑都会在这个Pod中执行,成功或失败后直接回调/消息队列。通知中心。该中心将负责告警和用例资源清理。让我举一个例子。比如Kubelet,在我们的组件运维平台上是批量发布的。每个批次都会触发相关集群的链路检测用例作为事后检查。一旦我们发现发布后检查失败,我们将封锁用户的当前发布,以防止损害蔓延。同时,我们会第一时间提醒相关同事,调查新版本组件是否不符合预期。同时我们也支持第三方事件回调,可以更快的集成到第三方系统中。此外,对于一些需要7*24小时不间断使用的高频短周期检测用例,我们还实现了另一套常驻分布式架构。此架构在集群中使用ProbeOperator来监控ProbeConfigCRD更改。检测逻辑在检测盒中重复执行。该架构完美复用了KubeProbe中心端提供的告警/根因分析/发布拦截等附加功能。同时采用标准Operator的云原生架构设计,常驻系统带来检测频率的大幅提升。(因为去掉了创建检查pod和清洗数据的开销)基本上可以实现集群7*24小时的无缝覆盖,方便外部集成。另外,还有一个很重要的一点必须要提到,那就是平台只提供了一个平台级的能力支持。真正让这个东西发挥作用,还是要看这个平台上搭建的用例是否丰富,能否方便使用。更多的人进来写了各种检查和检测用例。就像测试平台很重要,但是测试用例比测试平台更重要。一些通用的工作负载检测和组件检测,固然可以发现很多控制环节的问题,但是更多的问题,甚至是业务层问题的暴露,其实还是要靠基础设施和业务层同学的共同努力。从我们的实践来看,测试同学和业务同学贡献了很多相关的检测用例,比如测试同学贡献的ACK&ASK的创建和删除,全链路检测检测,金丝雀业务全链路扩展用例,比如本地生活同学等PaaS平台应用检验,也获得了不少稳定的成果和收益。目前我们维护了几十个检查/检测用例,明年可能会超过100个,检查/检测的数量将近3000万,明年可能会超过1亿。目前99%以上的集群管控问题和隐患都可以提前发现,效果非常好。04发现问题后:根因分析与事件处理CloudNative接下来说说发现问题后的事情。这是一个类似于咨询对话的例子。病人发现“哦,我不舒服!”这是发现的问题。医生参考各种化验单,同时进行信息汇总分析推断,并告诉患者,“你已经24小时没有睡觉了,睡不着是因为你焦虑,你焦虑的根源是因为后天就要期末考试了。”这就是定位问题的根源,然后根据根源解决问题。他对病人说:“你别着急,我刚接到消息,小学生不用期末考试了。”这个过程一定要快!检测环节的告警内容往往比较杂乱,不同于数据监控告警。上面说到链路检测告警的告警很可能是患者的一句话,我不舒服,你需要作为医生来判断,他为什么不舒服?根本原因是什么。而数据监控往往代表了原因本身,比如EtcdOOM,使用现有的oncall体验可能得不到最好的效果。另外,快速问题定位和根因分析是一个树状查找,一个经验处理和判断的过程,即如何从一个混乱的表象推导出根因,核心是逻辑。这与健康检查不同。健康检查列出检查项目1、2、3、4、5……然后告诉你一堆值。很多时候,即使有体检中心,我们还是需要医院的专业医生来解读判断你的病情,不是吗?同时,根因分析/问题自愈的关键在于专家经验的下沉,即将专家经验下沉到系统中。专家经验下沉带来的最大好处就是复用性和产出性。大家可以想一想,如果我们把一个最专业的医生的能力放到系统里,是不是更方便他给大家分析病情呢?这是KubeProbe发现问题后的全过程。我们首先会通过一个自建的集中根因分析系统,我们会汇总分析所有与这次故障相关的信息,包括事件/日志/变更/告警/组件升级等,我们汇总分析这些信息,并关联事件,最后通过树形分析系统定位到某个检测失败的原因,比如APIServer超时或者etcd断开连接等。另外补充一点,文本关联也是一个很好的rootcause分析方式.我们可以使用机器学习来训练文本识别,以关联与此失败案例最相关的根本原因。我们只是稍微参与了这种AIOps工作。涉及到,还在不断的探索中,我们的数据量非常大,我觉得这一定是未来的方向之一。KubeProbe根因分析及后处理全过程。上图左下方是失败的告警。经过根因分析系统,发现最核心也最相关,最大的原因可能是API服务器的连接断开了,目前已经恢复了,所以可能只是偶尔的网络抖动,我们暂时不需要特别注意,但是此时我们可以看到置信度为90%。还有其他可能的原因可以联系起来。比如对于某个组件,这个检测是基于某个组件的发布,它的发布者是XXX。我们可以观察到这个release会对APIserver造成一些影响,multiplelistwatch是否没有达到预期,然后把APIserverlistwatch有问题,置信度50%。当我们得到初步原因后,我们会进入二次确认系统进行二次确认。比如我们判断原因可能是APIServer超时/etcd断开/节点超时等,我们会自动再次拉取APIServer接口,看此时是否还超时,是否恢复。如果恢复了,我们会进行一般报警,告诉用户现在已经可以了,但是你要注意。如果没有恢复,那就很严重了,属于重中之重,直接报警。这就是思维方式。如果出现系统无法定位并持续定位失败的问题,我们也会触发高层告警,并添加相关根因分析识别树逻辑。太多的警报等于没有警报,我最讨厌警报的海洋。从经验来看,当我们建立了这样一个根因分析+二次确认+事后检查的体系后,我们的oncall成本下降了90%以上,而且还能继续下降。最后的状态可以说是无人驾驶。在值班的时候,也可以尝试类似的工作,可以说是投入小,效果大。自从建立这些系统以来,我们可以自豪地说,我们已经用很少的努力Oncall了每一个报警入口(是的,每一个报警,几千个集群,每一个千万级检测检查的报警),不会有任何遗漏.最后,为Oncall员工Chat-ops准备了一些甜点。基于NLP语义识别的Chat-ops系统我们使用钉钉提供的NLP机器人搭建了一个比较完善的Chat-ops系统,让我们的oncall人员可以很方便的通过ChatKubeProbe相关功能在报警群中进行操作,比如:重新-运行故障检测,查询集群状态,拉取诊断信息,查询检测日志,集群告警静音。上图是我们操作Chat-ops系统的过程。这个过程非常方便。比如我晚上已经在床上了,这个时候给我报警,比如之前某个集群出现故障,现在已经恢复了,需要注意。既然关注了,想再跑一次某个普通的case(可能周期比较长,比如一个小时)。由于短链接的用例可能随时运行,所以我会告诉机器人再次运行,机器人会识别我的语义并再次运行集群。运行之后,我会通过查询状态来查看集群当前的状态。这很方便。有时你晚上去上班,或者在路上,或者在床上,你会觉得很舒服Goon-call系统。05Demo实例CloudNative1、release2、检测列表3、检测Pod开始运行4、检测结果5、rootcauseanalysis&alarm6、Chat-ops
