作者:宋傲(凡星),阿里云云原生应用平台研发工程师
1. 背景及现状
上图为阿里云内部实际使用的系统架构,系统主要用途为实时数据流的计算和存储。使用阿里云的容器服务ACK作为系统底座,容器化的部署、发布、管控等全部基于K8s标准。使用自己开发的Gateway service作为系统流量入口,并基于LoadBalancer类型的service部署。
此架构也是应用K8s做系统较为常见的做法,通过ACK提供的CCM组件自动将service和底层SLB实例进行绑定,通过此实例承接外部流量。Gateway收到上报的数据流后,将数据放入Kafka并在某个topic中进行数据缓冲。当Consumer感知到数据流的上报后,则会从Kafka相应的topic中对数据进行进一步计算处理,并将最终结果写入存储介质。
此处存在两种存储介质:其中阿里云块存储ESSD相对较快,但价格较高;文件存储NAS主要用于存放性能要求较低的数据。元数据由ACM进行管理,自研的组件Consumer和Center负责从存储介质中查询计算结果,并返回给用户。
系统目前为全球开服,部署在全球将近20个region中,从图中也可以间接看出数据读写链路较长,需要经过多个组件的处理。监控对象也较为复杂,包括基础设施(调度、存储、网络等)、中间件(Kafka)、业务组件(Gateway、Center、Consumer)。
可观测性主要包含Metrics、Tracing和Logging三类数据。三类数据各司其职,相辅相成。
Metrics负责回答系统是否出现问题,它也是系统的自监控体系入口。针对Metrics做异常的告警或问题的排查,可以快速确定系统是否有问题,是否需要人为介入处理。
Tracing负责回答系统问题出现在什么位置,它能够提供组件之间的调用关系、每一次请求以及哪两个组件之间的调用过程出现了问题等具体细节。
找到出现问题的组件后,需要通过最详细的问题日志即Logging来定位问题根因。
收集到三类数据后,下一步需要通过大盘将数据用可视化的方式展现,能够一眼确定问题所在,使问题排查更高效。
确定问题后,需要通过告警和应急处理流程来解决问题。
应急处理过程主要有以下几个要点:
第一, 需要分级的告警通知和升级策略,能够快速找到相应的人员处理告警。与此同时,若原定人员因为某些原因无法及时处理,还需将告警升级到其他人员以及时处理;
第二, 问题认领和处理流程标准化;
第三, 事后统计及复盘。系统出现故障并解决后,还需要事后的统计以及复盘工作,让系统通过故障和教训避免后续再出现相同的问题,让系统更稳定;
第四, 运维处理工具化、白屏化,尽量减少手动输入命令的工作,将整套标准的处理动作用工具进行固化。
2. 实践经验分享
监控的第一步是收集可观测数据,这些数据在系统里可以分为三个层面。
最上层为应用层,主要关心核心业务接口的健康度,通过RED(Rate、Error、Duration)三个黄金指标进行衡量。其中Rate指接口的QPS或TPS,Error指错误率或错误数,Duration指接口在多长时间内能够返回。可以通过黄金指标来定义SLO并分配Error Budget。如果Error Budget很快耗尽,则应及时调整SLO,直到系统优化到足够完善后,再将其调高。也可以通过Apdex Score衡量服务的健康度,计算公式如上图所示。此外,应用层也会关心与业务强相关的指标,比如营收、用户数、UV、PV等。
中间层为中间件和存储,主要关心系统里大量应用的Kafka client端消费位点的提交状况、生产者缓冲区的占用率、是否会提前将缓冲区占满导致新的消息进不来、消费延迟、平均消息大小等,比如Kafka Broker端的水位、读写流量、磁盘使用率等,再比如云盘ESSD的挂载成功率、IOPS、磁盘空余空间等。
最下层是基础设施层,关心的指标较为复杂,典型的有比如ECS(K8s Node)CPU 内存水位、重启次数、定时运维事件等,比如K8s核心组件的API server、ETCD、调度相关指标等,比如业务Pod的Pending状态、是否有资源可供足够的调度、OOMKilled事件、Error事件等,再比如VPC/SLB相关的出口带宽、丢弃连接数等。
监控ECS节点需要使用node-exporter Daemonset的方式部署,K8s云原生的核心组件可以通过Metrics接口将指标暴露,供Prometheus抓取。Kafka或存储组件由于使用了阿里云的云产品,本身提供了基础监控指标,可以直接接入。ACK对CSI存储插件也提供了非常核心的指标比如挂载率、iops、空间占用率等,也需要接入。应用层包括Java应用和Go应用,Java使用MicroMeter或Spring Boot Actuator做监控,Go应用直接使用Prometheus官方SDK做埋点。
基于ACK和K8s体系,Metrics协议的最佳选型即Prometheus。开源自建的Prometheus与云托管的接入难度不相上下,但可靠性、运维成本等方面,云托管的Prometheus更优于自建。比如使用ARMS体系,可以直接在集群里安装非常轻量级的探针,然后将数据中心化存储在全托管的存储组件,并围绕它做监控、告警、可视化等,整个过程非常方便,不需要自建开源组件。云托管在采集能力和存储能力上也更有优势。
Prometheus针对ECS节点、K8s核心组件、Kafka和存储组件都提供了一键接入的能力。
K8s基础监控和节点状态接入主要通过ACK组件管理中心,只需简单地安装相关组件,即可使用该能力。
Kafka的接入主要通过Prometheus云服务实例,云服务实例目前已经接入阿里云非常完整的PaaS层云产品。接入Kafka时,所需填写的指标都为常见指标,无需额外学习成本。
云盘ESSD监控的接入主要通过CSI存储插件监控。ACK里的csi-provisioner组件提供了很有用的可观测性能力,可以通过它提供的信息及时查看哪块盘没有挂载上、哪块盘挂在后iops达不到要求或配置告警,以及时发现云盘的异常状况。
通过ARMS Prometheus接入,预置采集的job比如K8s cluster级别、node级别的PV状态都可以很方便地进行监控。
应用层不存在一键接入的便捷方式,需要通过应用埋点+服务发现的方式,将整个应用的Metrics接口暴露出来,提供给ARMS Prometheus的探针抓取。
Java应用需要使用MicroMeter或Spring Boot Actuator进行埋点。
以上图代码为例,MicroMeter中很多JVM相关信息可以简单地通过几行代码进行暴露,其他更有帮助的信息,比如进程级别的memory或thread、system信息等也可以通过很简单的方式将其接入。设置完埋点后,需要在内部启动server,将Metrics信息通过HTTP接口的方式暴露,最后绑定指定的端口。至此,埋点流程结束。
此外,如果有业务指标,只需将自己的指标注册到全局的Prometheus Registry即可。
ARMS探针抓取暴露的端点,只需添加ServiceMonitor,由ServiceMonitor直接通过控制台白屏化的方式,简单地写几行YAML的定义,即可完整地将整个监控的采集、存储和可视化跑通。
Go应用与Java大同小异,只是埋点方式有所区别,主要使用Prometheus官方的SDK埋点。
以上图为例,比如系统里有一个查询组件关心每一条查询的时间分布,可以使用Prometheus里面直方图类型的指标,记录每个请求的时间分布,并在埋点的时候指定常用的分统进行统计。再由ServiceMonitor将Go应用的endpoint写入,最终在控制台上完成整套应用的接入。
ARMS还提供了基于eBPF的无侵入可观测性实现方案,主要适用于不希望修改代码的场景,使用无侵入的方式监控系统接口的 RED,通过ARMS Cmonitor探针结合eBPF的方式,通过系统内核的filter实现信息的抓取和存储。
使用上述方式需要在集群里额外安装Cmonitor App,安装后可在Daemonset看到Cmonitor Agent,每个节点都需要启动Cmonitor Agent,作用是通过eBPF的方式注册到系统内核中,抓取整台机器的网络流量,然后过滤出想要的service网络的拓扑等信息。如上图,它可以监控整个系统的QPS、响应时间的分布等信息。
接下篇:
https://developer.aliyun.com/article/1222694?groupCode=alisoftwaretech