开发者学堂课程【阿里云可观测峰会:行业实践】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1060/detail/16102
行业实践
内容介绍:
一、行业 saas 的微服务稳定性保障实践
二、万节点规模云服务的SRE能力建设
三、友邦人寿和观测体系的设计与落地
四、阿里云ACK容器服务生产级可观测体系建设实践
五、微服务异常诊断与根因分析算法实践
六、阿里云serverless可观测实践
本节内容我们主要学习行业SaaS的微服务稳定性保障实战
一、行业 saas 的微服务稳定性保障实践
我是安福路汽车科技有限公司的祁晓波,今天和大家分享观测和稳定性的一些探索。今天我带来的主题是行业SaaS的微服务稳定性保障实战。首先简单做一下自我介绍,我是一六年加入南京爱福路汽车科技有限公司,也即F6,负责F6后端的架构设计,实施了微服务相关的拆分,主导了K8S在F6的落地和实践。全程参与F6内部DevOps的设计建设和演进,目前主要负责F6基础设施和稳定性的一些工作。目前我主要专注于的领域包含Java,包括微服务的架构,云原生领域DevOps的一些实践,以及CICD这些流程,以及最终还有SRE的领域。
这幅漫画体现的是研发的日常:
研发同学每天都碰到一些日常的问题需要处理,最让研发头疼的两个问题竟然是不可以运行的,为什么?竟然是可以运行的,为什么?我们期望可观测能够给大家提供一些解决问题的思路。
首先我们一起来了解一下可观测性最近持续火热的来龙去脉。2017年TWitter工程师在2017发表了一篇文章,叫《Monitoring and Observability》 。首次将Observability一词代入开发者的视野。它通过开玩笑的方式调侃了关于可观测性和监控的区别。它是这么解释的,可观测性是因为研发不喜欢做监控,所以我们需要把监控重新包装成一个新的名词,让它可以流行。真的是这样吗?参考上一幅的那个漫画,监控能够告知我们服务究竟是否能够正常的运行,但是可观测性可以告诉我们,为什么服务没有在正常的运行。从谷歌的趋势图当中可以看到,可观测性逐年呈现整体上升的一个态势。
可观测性也会被视为系统的一个属性,功能性、安全性等,逐步会成为系统在做开发设计过程当中需要具备的一个特性。
2020年之后的观测的这个搜索趋势出现了井喷,它的相关词包括SRE,这和疫情应该与密切相关。包括合规,一些合规政策的缩紧,越来越多的基础服务面临的这个稳定性的挑战。而破解稳定性的很重要的一个手段是在于服务需要提供可观测性,那很大的它的原因也是因为谷歌类一本偏大一站点可靠性工程的逐步普及,国内的大厂纷纷设立相关岗位和对应的招聘指标。可观测性在国内也得到了较多的关注,这张图是整体的一个可观测性在全球的搜索趋势,明显看来是在中国这边的搜索是热度较高的。
那我们再回到可观测性这个词的来源,从维基百科当中可以得到可观测性最早是匈牙利的工程师提出来的,它是一个数学上的概念。可观测性是指系统可以由外部输出推断其内部状态的一个程度。换句话,可观测性应当可以回答刚刚漫画中问的那个问题,为什么我的服务没有正常的运行?那可能是因为连接数不够等。
这张图是维基百科提供的一个关于可观测性的数据,也即你应当是可以从它的数据的产出分析出来它究竟内部是如何运转的。
回到正题,今天我分享的主题主要分为三个部分,第一部分难点与挑战,第二部分可观测的演进,第三部分,关于未来的畅想。
业务蓬勃的发展对于稳定性的诉求是激增的。首先来介绍一下F6汽车科技,我们是一家专注于汽车后市场信息化建设的互联网平台公司,目前是在这个行业市场占有率是top的行业saas。随着业务蓬勃发展,F6支持的商户数目短时间内暴增数十倍。同时,我们也逐步开展了面向技师等C端场景的一些业务,比如编码的解析,包括数据的查询等服务,这样对于稳定性的要求也是显著的提高的。
业务膨胀,我们学习一个定律叫做康威定律,这个康威定律也是it史上对我们整个组织架构提到一个微服务的拆分,是一个指导性的一个定律。它是合格的,任何的组织在设计系统的过程当中,它都是一个组织架构的一个翻版。随着业务膨胀,康威定律的作用会导致我们设计微服务的时候,它的拆分的方式趋同于组织的架构,业务增长会导致部门拆分,继而设计微服务时会十分靠近组织架构。纵使前期微服务架构和微服务拆分不一致,微服务也会逐步妥协组织架构。虽然微服务和组织架构的趋同导致整个系统的沟通效率比较高,但带来了分布式系统的问题,比如微服务之间的交互。没有人可以对服务整体性,全局性的了解,研发最直接的期望是希望在分布式的系统中有单机系统的排查效率,促使我们将系统以服务器为中心的思路转变为调用链为中心的思路。
F6最早进行业务开发的时,也是烟囱石的开建设,这和绝大部分公司都是类似的。单体的应用它是比较简单的,但是它在扩展器上面会存在很多的问题,包括它的可维护性,比如所有的研发都在这个系统上面进行开发,它的代码冲突会比较多,它什么时间你能发布它的发布会,造成多少业务量的这种损失,有可能都是比较危险的。所以,越来越多的情况会导致我们进行微服务的拆分,但是微服务的拆分和调用又会演化出来像类似于这一张图,这个是我从淘宝的论文当中摘录出来的一张,整个调用面是十分的复杂、繁琐。
从人的角度基本上是分不出来它的调用链度的,有没有什么方式能够去尽可能的降低我们线上排查故障的这种难度?以淘宝这个这张图为例,比方它有一个bye2引用,这个服务里面出现问题时,你如何知道它是它的问题,是它的下引文当中任何一个地方出现问题?那下面我们来具体的聊一聊F6的这个观测上面的引进。
我们对于日志的收集采用的是ELKStack, ELKStack是三个开源小项目的首字母缩写,虽然很多现在可能中间采用发布一下等,但是目前大家测估的时候还是elk,分别是Elasticsearch,Logstash和Kibana,我们重度依赖于elk 进行微服务日志的收集,与此同时,我们还使用了em公司开源的基于es的报警系统,叫 ElastAlert 这样一个组件。这个组件的主要功能是从es当中查询出来匹配的规则,对类型的数据进行报警,要么这个公司是类似于国内的发布点评,也许是类似的这样的一个公司,一个团购的公司。它提供关于es查询的一个组件,提供了较多规则,比方stack,或者其它出现监制的报警等,也较多介入了slack或者其它。
这张图描述我们通过日志收集整体进行日常查询的思路,比如研发会通过Kafka
查询线上的日志,Elastalert是通过匹配规则告警,它获取es日志中它发觉出异常数据,Kibana可以进行查询。通过这种方式也可以优先定位系统中的异常。
随着业务发展的诉求,对日志要求增多。比如我们团队非常多,我们需要配置各种告警规则,因此引入Grafara。Grafara逐步替代Kibana和es一些查询的功能,我们可以通过Grafara查询功能的一些插件,去查询对应的日志,进行告警,通过alert的功能来完成对应es的排查。同时我们可以使用Grafara做出更加直观的可视化的大屏比如电视进行展示。
除了日志之外,我们更多期望收集到Java应用的指标。我们线上应用可能出现限程,限程数过高等问题,所以我们引入了Zorka组件,这也是调研后才使用的组件。由于我们之前使用的是zabbix zorka和zabbix 可以简单进行结合,可以通过zorka将收集的jvm的数据信息上报给zabbix进行展示。
而zabbix又可以通过Grafara Zabbix 插件直接输出数据,所以,整体来我们可以将整个的应用的它们都收集到graphna界面,效果良好。Zorka它的工作机制是类似于通过zabbix Java变成way的方式,它也是一个Java a减进行通过自动Java a减直接换成了Java进程中,可以用来统计包括一些常见的应用容器,比如tomcat等,这些请求数的一些指标都可以收集,初步解决了我们对于Java进程的观测需求。
随着微服务的程度不断的提升,我们发现传统方式的运维成本越来越高,尤其是服务,机遇等方面。一旦我们发生一个应用的om,如果我们没有写比较好的自动恢复的脚本,这个应用可能少了一个节点,少了一个节点很有可能我们未察觉到的时,其它的应用节点会越来越多,请求越来越无法承受,到最后可能会出现整体服务的坏死。所以我们启动了云原生化的改造,云原生化的改造,在K8s这边,我们重点关注关于绪战争和存活战争的一些编写,通过这些单针的编写,我们尽可能的提升我们服务的自律能力。如果出现om,很有可能服务会自动恢复,启动一个新的节点,完成我们的数据的服务的正常提供。除了K8S之外,我们引入了Prometheus和ARMS应用监控,Prometheus作为CNCF的仅次于K8S的二号项目,基本上在整个metrics领域形成了足够的话语权。ARMS应用监控作为阿里云商业APM的拳头产品,我们作为一个线上服务,全部是重度依赖阿里云的这样一个公司。比如我们使用阿里云的ack ecs slb各种各样的组件,当然里面也提到arms,结合云原生的方式做到让研发不需要做到任何的代码的改动,可以直接拥有一个trace的功能。而且阿里云团队还在不停迭代,
可以支持越来越多的中间链,会是一个诊断的利器。可以看到,虽然我们没有整体的可观测性的这样一个认识,但是事实上也已经在围绕我们的login,是elk,比如magic Prometheus the trace of ARMS这样一个工作。
由于我们进行的云原生化的改造,这里面的监控模型也发生了变化。最早先的监控模型是push ,zorka我们每次发布都在同一个机器里,每一个应用都在同一个机器里,所以它有一个固定的host。但是当我们上了云原生之后,进行了容器化的改造,整个pod是在不停的飘,而且有可能会出现新的应用、扩容、缩容等问题。整个的监控模型逐步从push转换成的pull,也更加契合Prometheus的这样一个收集模型,所以,我们将zorka也逐步的从我们的可观测体系当中进行了剥离,,我们需要通过一些其它的数据来进行JVMaxexporter 的数据,我们不使用arms直接收集JVMaxexporter是因为arms我们不会覆盖我们的线上和线下所有的Java应用,比如我们测试环境、批发环境等环境,我们也希望有一些JVM数据的收集,但是因为arms整体还是有成本,所以我们并没有将arms作为一个完整的介入,当然我们线上的服务已经完整的介入。
通过我刚刚介绍的这种方式,我们选择了一个叫做JVMaxexporter的主键,JVMaxexporter也是Prometheus官方社区提供的exporter之一,JVMaxexporter通过Javaagent,直接利用Java的JVMax机制读取jvM的信息,可以将这个数据直接转化成为Prometheus可以辨识的metrics格式,让Prometheus对其进行监控和采集,通过Prometheus operator注册对应的service monitor完成指标。我们监控的一个level叫做APP为jvm monitor这样的一个service,但凡是有这个service的指标的pod,有这样的一个pod,我们可以自动的收集到它的应用的jvm的数据,它会发起到这个对应的叫metrics这样的一个HTT的pass下。通过编写对应的alert rule完成对应的监控告警,有一个JVMaxexporte的一个Java进程共存的这样一个关系,Prometheus通过定词的spark去拉取对应的数据去保存到自己的实时数据库当中,然后定期的运行对应的alert rule,能够完成应用的指标的考勤。
业务蓬勃发展之后,人员激增,微服务暴增,研发人数和告警都是剧烈的增长。为了提升告警的触达率和响应率,我们又重新使用了阿波罗这个配置中心的多语言SDK,自研了一套其阿波罗的业务的应用体系,它的整体流程大概是通过Grafara去收集到对应的es的报警,或者是一些其它的一些场景上面的报警,由于它有一个metrics是应用,F为应用,通过这个应用去关联到这个应用alert报警的时候会转发到这个购编写的精准告警服务上面,精准告警服务解析到对应的应用会去应用阿波罗,获取到对应的功能,姓名,几号等信息,通过这个信息通过钉钉进行报警,这样可以极大的提升了消息的阅读率。
之外,我们还引入了阿里云的应用实时监控服务arms, arms能够在无需代码进行任何改造的前提下,支持绝大部分中间链和框架,包括比如Kafka、fins ,cycle double等。同时云原生化后,仅需要在grand里面添加注解,去支持相关的加载,比如这边有Arms point or to auto enable以及upperic creator。这样的两个注解,通过这两个注解可以创建一个对应的同名的在ARM实例下面的监控,研发我们不需要关注任何的版本差异,发布重启之后可以自动升级,整体的微服务的可维护性极为友好,同时还提供了一个比较完整的trace式,这个是我们线上的一个应用节点里面调用的链路。包括它里面的整个一个类似于单个子的,大部分都是从可观测的这个一个很好的实践,它还提供了一些依赖客户,上下游的耗时等。
2020年后可观测深入人心,整体在国内微服务领域基本上是遍地开花,我们整体升级了我们的可观测的思路。业界广泛推行的可观测性包含三大技术,分别是日志事件,分布式链路追踪以及指标监控。任何时代都需要监控,监控一定是一个很重要的东西,但是它已经不再是一个核心需求,我们这张图里面可以得知监控,仅仅包含了造型和应用的概念,但是事实上可观察性包含了排错,剖析以及依赖分析。研发同学原先最早的监控主体是运维同学,但运维同学大部分只是处理的是系统的部的告警,比如机器X或者其它。如果现在上升到我们的微服务的领域里面,更多的可能是应用之间的一些问题,比如需要问你的牌照,举个简单的例子,比如现在的服务出现了慢请求,是因为什么问题,有可能是因为我的代码写的不好,有些锁,或者是我的现存池不足,或者是我的连接数不够,或者是我可能因为我的慢差。这些种种的问题都可能表现出来是一个特点,是慢,或者服务无法响应。这么多的可能性,需要通过可观测性才能够尽可能的排除到这种很多不可能的或者是是额外的这种分支能够去定位出来,真正这是它的原因,但是定位对应又不是一个完全真实的需求,更多的是利用可观测性,分析出来问题是在什么地方,然后我们通过替换对应的组件,通过去进行相关的垄断,或者是限流等措施,或者是扩容,能够尽可能的去提升我们整体的sla,剖析也是同样的道理,我们线上服务可能出现慢,比正常的慢,那我们需要通过什么样的办法能够去观测到?比如它每一个节点的耗时,每一个请求当中各种各样的耗时,除此之外还有依赖分析,这也是一个微服务相辅相成的课题。我的服务依赖是否合理,我的服务的依赖的调用链路是否正常,都可以通过可观测性给我们得到一个很好的解答。
随着运用越来越多,研发人数越来越多,对于可观测性、对于稳定性的诉求也越来越多,所以我们自研了一套简单的分析。通过文本相似度的算法,将当前服务日志进行归类,聚类分析。这是一个典型的OS发生故障,我们依赖的服务进行服务升级,这是我们通过日志的智能抓取分析出来的一个日志,但是如果我们可观测性做的足够好,我们也记录到了ons的升级的公告,或者是相关的一些变更,做很长时间的SRE之后,变更对于线上稳定性的破坏也是非常大,如果我们能把变更等,也收集到我们的可观的体系中,这是一个很好的做法。所以这样也是同样的道理,如果我们能将ons要升级的信息收集到我们的可观测的系统中,通过种种的事件关联,我们能够分析出它的根因是因为我们的基础英法团队在升级,对应的平均或者是其它的一些特征,对于我们系统的稳定性和对应的问题的排查是极为有帮助的。
在此期间,我们和ARMS团队也深入了合作,探索了一些可观测的最佳实践,ARMS最近提供了一个新的功能,将确trace ID直接扣出到SCTB头。这面有一个叫做一个eagleeye trace ID的响应标头,我们可以在介入层的日志当中将它输出,比如abstract或者express等,我们输出到对应的日志当中,通过Grafara进行检索。如果我们的客户在发生故障的时候,比方它出错,或者是它的一些请求与异常,如果在客户在上传的时候,将这些日志信息,包括trace ID一起上报到我们的服务器,最后转发到我们研发的同学手中,通过这个trace ID可以很快的定位到问题的原因,上下有何链路,不会出现可能需要根据大家业务同学的这个报错的IP,时间段,UA等信息,再去精确的去查询。但是trace ID在整个的调研当中是唯一的,是可以做一个很好的一个检索条件。同时,Arms支持在解决MBC透传trace ID,它支持Java的主流日志框架,包括logback,log4j等,我们可以将trace ID作为标准的back输出,是一个典型的日志输出的一个场景,这个是arms的后台的配置。对打开这个关联应用知识和trace ID,它这里面支持的各种各样的组件,我们只需要将一个trace ID在我们日志系统当中定义一下即可,我们可以输出对应的trace ID。这个方案比较小,也比较简单,对于研发的修改很小甚至免修改,对于整体的login和trace 的关联程度已经做到了比较大的提升,减少了我们的数据误导。
Arms除了支持整体的可观测,为了进一步降低PDR也是做了较多努力。刚刚提及整个arms,它提供了很多的数据,但是这个数据如何到达SRE,或者是研发运维同学的手里,是需要花点心思。arms上线了运维报警平台,通过可视化的方式完成了报警、转发、分流等事件处理。可以通过浸没功能,分组等,这是多种继承方式。目前F6在用的Prometheus Grafara 、ARMS以及云监控,云监控里面的数据包含很多,包括比如Nginx,刚提及的这个里面如果出现响应堆积等,如果nbs等服务都可以。研发同学或者其它同学在钉钉群里面认领对应的响应事件即可,同时这也支持相关的报表功能,定时提醒,还有事件升级等功能,也便于我们事后的复盘和改善。
这是一个典型的我们线上处理这种问题的一些截图,这是在钉钉群里面的一个告警,它会提示你上次相似的处理是谁处理的,一些大概的一些数据,有一个告警的列表,还有对应的一个事件处理流程,比如我可以过滤,可以分割内容,字段的丰富,通过字段丰富或者是匹配更新等这些方式,替换内容填充模板,我们可以用来去做精准告警,比方识别到这个应用是叫什么名称,然后我们可以通过让它去关联到对应的owner,或者是对应的告警人员即可,这样我们刚刚那个通过构写的那个SDK的应用也是可以逐步退出的,比较方便。
同时,我们也借鉴了arms的免修改注入agent的这种方式,arms通过一个叫做one pllot initcontainer的方式注入了很多的arms的一些信息,也挂载一个MT,日志都在下面,如果使用ARM同学可以关注,它的后面是这样的,它里面会出这样一个信息,也正因为有这样的一个initcontainer,所以它可以自动升级,在initcontainer当中它可以通过调用arms的接口获取到当前arms的最新版本,然后下载对应的Java最新版本,放到对应的目录下面,在这个目录下面和对应的数组进行通信,通过共享目录的方式,也是这边提到的共享的方法完成Java的共享。然后最核心的是通过Java to options这样的一个jvM的参数,实现Java Nginx 的挂载。这是一个Java to options,里面有一个Java Nginx 组件,它的核心思路是这样。这是一个现代社区比较主流的关于Flash的这样的一种方式,通过这个方式我们也模拟了这样的一套流程,通过openkruise 的组件去完成对应方式修改,这里做了一个简单的实践,利用openkruise去给对应的appoint打一个注解,这个注解不需要研发或者SRE团队去进行处理,只要编写这个CRD即可,直接注入了Java options,initcontainer是我们需要挂载的。这里应用场景也比较丰富,里面写了一个是叫sandbox,也可以去做应用流量的回放,比方gems and box和Peter,或者是koko。这是用来做自动化测试的,比方覆盖率等,有很多种方式去做。
除了arms等商业化产品之外,我们还积极拥抱开源,拥抱Prometheus,介入了比较多的export组件,极大地提升了整个系统的可观测性,包括了是ssl exporter,除此之外,还有exporter。或者是lolita exporter。Black box exporter可以做一些黑和探针,比如仅仅需要探测HTTP请求是否正常,HTTPS请求是否正常,DNS是否正常等。我们典型的例子是用来探测我们的当前服务的入口地址是否正常。
SSL证书异常更常见了,经常出现,每年出现,哪怕是大厂也会出现一些证书过期没有发现,没有及时更新这样的问题。那我们通过ssl exporter可以去定期的轮询我们对应的证书是否过期,通过这种方式可以进一步的提升我们的可观测性。
除了日常服务的可观测,我们还实现了成本可观测等持续优化的项目。对于云原生环境,我们可以利用kubecost 这个开源组件进行成本的优化,可以直接输出资源的使用率以及相关的报表等,进一步的反馈给研发同学优化。甚至可以用来发现你cpu和你的内存是否已成一个正常的比例,有没有太多使用cpu但是实际上不占用内存的这些或者是相反的一些组件,通过这样的一些方式能够尽可能的实现的资源的合理的分配。
它是一个比较简单的报表,F6这边的业务团队、研发团队大部分是以车进行命名,比如奔驰、迈巴赫、巴鲁等。
我们可以看到这是一个完整的报表,我们定期会把这个数据反馈给研发组,研发组根据这个报表来去判断它的是否需要进行一个持续的优化。
Ebpf,云原生组件发生到深水区,我们排查问题的时候,很多不再是应用层面,更多的有可能是系统层面,包括网络层面的,比如DNS导致的抖动,或者是网络同传等,均需要更加底层的数据进行追踪和排障。利用Ebpf 我们可以更好地回答谷歌,比如延迟,流量,错误饱和度等黄金指标,出现的问题,一个典型的例子是我们基因闪断切换的过程中,有可能会形成一些TCP的半开连接,这些半开连接对我们来是有害的,我们在业务系统当中可能利用了很多的类似prospect的这样一些功能,一旦发生的这种半开连接,可能对我们会产生一些业务上面的影响。这也是客观存在的一些问题,包括常见的利用对MQ的这种订阅或者是其它的一些课程都会有这种相关的信息。
还有TCP连接刚建立的时候,那边block是否合理,都可以通过这些数据能够得到一个响应。
混沌工程主要鼓励和利用可观测性,试图帮助您先发制人的发现和客服系统的弱点。2020年六月份,CNCF针对可观测性提出了特别兴趣小组,除了三大制度之外,logging,tracing metrics,在我们F6的时间,Logging这边可能绝大部分是以elk或者efk,tracing目前是arms,magic主要是Prometheus,它里面可能收集了一些自定义的业务数据,或者是JVM的这些数据,各种各样的load的数据。对于混沌工程是否能够划分在可观测性里面,是有社区是有些异议,但是CNCF确实是把整个可观测性的特别兴趣小组里面是包含了chaos-engineering 和持续优化。为什么这么做?是因为混动工程虽然我们可能认为是一种可观性或者分析工具,或者是一种可靠性,但是混动工程很重要的前提确实也是可观测性。试想如果你在实施活动过程的过程当中发生的故障,都不确定是否是你的混动工程引起的,这个问题比较麻烦,利用可观测性,我们尽可能的缩小我们的爆炸半径,定位我们的问题,通过chaos-engineering能够持续的正反优化我们的系统,能够提前发现我们系统的一些薄弱点,单点问题解决。为了系统的稳定性更好的保驾护航。Open telemetry ,open telemetry,简称 ot。这是一个通过多个项目合并出来的开源框架,我们需要更加面向终端研发的统一的、可观测性的视图。按照刚刚所,比如我希望把lock metrics和trace的数据进行互相的关联达标,尽可能的减少数据孤岛,通过多数据源的关联提升整体的可观测性。比如我们刚刚通过arms的HID,通过日志里面收集的这个数据,可以和arms的trace ID 进行关联,arms trace ID本质上虽然trace有可能是有采样率的,但是trace ID本质上已经生成了,也是在我们的请求链路当中,基本上都可以利用到trace ID只是arms的trace的采样会丢弃掉这个数据而已,但是整个trace。它有同样的trace,本质上也是一个很有效的信息。我们希望通过探索出来更好的比方将lock metrics和trace的互相关联的方式,减少这种数据孤岛,提升整体服务的可观测性,利用这种可观测性尽可能的缩短我们线上如果真的发生故障的这样的一个排查问题的时间,给我们业务服务恢复争取时间。