当前位置: 首页 > 科技观察

在微服务架构下基于 Prometheus 构建一体化监控平台的优秀实践

时间:2023-03-15 15:39:38 科技观察

微服务架构下基于Prometheus搭建一体化监控平台的优秀实践最佳实践和一些相关思考主要包括以下几个部分:微服务和容器化技术演进中的监控之痛云原生时代,为什么是Prometheus阿里云Prometheus在微服务场景和大规模落地实践中的挑战与解决方案云原生可观测性的发展趋势与展望一、微服务与容器化技术演进中的监控痛点1、第一个挑战:动态监控对象容器化部署让我们的监控对象动态化。随着K8s服务编排框架的大规模落地,应用部署单元从原来的host变成了pod。Pod每次发布都会被销毁重建,IP也会发生变化。在微服务体系下,我们讲究快速迭代和持续集成,这使得发布更加频繁,Pod生命周期变得很短。据统计,每个Pod的平均生命周期只有两三天,然后就会被销毁重建。而且,随着DevOps的普及,负责应用发布的角色发生了变化,应用发布的可控性越来越弱,越来越敏捷。一个应用会被不断的推出来达到快速迭代的目的。因此,随着软件生产过程的变化和相关技术的成熟,我们的监控对象处于不断变化和频繁变化的状态。2、第二个挑战:监控层面/对象多样化首先,Kubernetes和容器层相关的kube组件是我们必须监控的新对象。其次,在微服务拆分之后,行业在中间件、DB等领域的细粒度发展,我们发现依赖的PaaS层组件越来越多样化,应用程序依赖的这些PaaS组件也越来越多。需要被监控。最后是多语言。微服务拆分后,每个团队可以选择自己擅长的语言进行应用开发。这就产生了一个问题,就是这些应用的监控指标需要通过支持各种语言的客户端库来生产和暴露。3、挑战之三:监控内容的复杂性监控内容的复杂性来自于以下几点。首先是复杂的应用程序依赖性。二是在高度分布式的环境中,我们需要非常复杂、细粒度的指标来描述整个系统的状态。在上图中,我们可以更直观地感受到上述挑战是如何产生的。左边是传统单体应用的部署架构,右边是微服务部署的架构。以前只需要监控一个应用对象,现在变成几十个、上百个动态发布,IP地址不断变化。传统的监控工具可能使用静态配置来发现这些监控目标。但是在微服务场景下,这种方式已经行不通了。事实证明,单体应用程序可能只需要依赖MySQL。但是现在要依赖的组件越来越多。传统的监控工具无法完全支撑这种庞大的监控需求,传统监控工具缺乏容器层的监控能力。为了解决上述问题,我们发现Prometheus可能是一个理想的解决方案。2、云原生时代,为什么Prometheus是动态的:Prometheus具有先发优势。在Kubernetes诞生之初,标准的监控工具是Prometheus,它天然契合Kubernetes的架构和技术特点,能够自动发现监控目标。在监控目标不断变化的大规模监控场景中,根据实践经验,主动拉取是一种较好的实现方式,可以避免遗漏监控目标指标。监控目标需要解决维护采集点配置和推送方式等一系列问题,如实施成本大。其次,通过Kubernetes的Kubelet/VK组件收集动态容器指标,天然使用Prometheus格式生产和暴露指标数据。多元化:因为Kubernetes有很多控制面组件,比如APIserver等组件,自然而然的也会通过Prometheus的数据格式暴露监控指标,这使得Prometheus收集这些组件的监控指标变得非常标准和简单。其次,Prometheus是一个开放的社区,有100多个官方或非官方的出口商可供所有人使用。比如你要监控数据库、消息队列、分布式存储、注册中心、网关等,开箱即用各种exporter,将原始组件的非Prometheus标准数据格式转换成Prometheus数据收集器执行的格式。收藏。此外,Prometheus支持go、Python、Java等20多种语言,可以轻松生成和暴露应用的监控指标。最后,Prometheus的可扩展性很强。如果以上都不能满足应用需求,它还有强大的工具可以帮助业务方轻松编写自己的exporter。并发症:普罗米修斯定义了一个多维模型。多维模型可以简单理解为我可以给任何东西贴上标签,通过标签来描述对象的系统状态。多维模型听起来比较简单,但是很多监控工具一开始并不能这样描述它的监控目标。通过多维模型,我们可以很容易地描述整个监控目标的复杂状态,也可以描述应用之间的依赖关系。其次,Prometheus实现了一种名为PromQL的查询语言,它非常强大,可以过滤、聚合和计算复杂的指标。内置20-30种计算函数和运算符,包括常用的累加、差值、平均值、最大值和最小值、P99、TopK等,并可以直接基于这些计算能力绘制指标视图和配置报警,可以节省了原本需要的代码开发工作,很容易得到想要的业务结果。您可以在上图中看到一个真实的PromQL语句。http_request_duration_seconds_bucket是一个直方图类型的指标,它有多个桶。通过上面的PromQL语句,不用写任何代码就可以计算出RT超过500ms和1200ms的请求占比。从而得到ApdexScore来评价接口的服务能力。3.Prometheus登陆实践方案接下来,我们来看一个完整的登陆实践方案。其核心是如何围绕Prometheus搭建一个可观察的平台,即如何将描述系统状态的各级指标数据收集到Prometheus数据监控数据平台。以前我们几乎不可能完成这种收集各种指标的工作。由于各个监控工具关注的领域不同,数据格式不同,工具之间的数据无法打通,即使聚集在一起也无法产生1+1>2的效果。但是通过Prometheus,可以将IaaS和PaaS层各个组件的监控指标汇集在一起??。如果需要收集一些业务指标,应用的健康状态,云应用依赖的云产品是否正常,Kubernetes组件是否正常运行,容器的CPU和内存水平是否达到预期,以及Node节点的TCP连接数分配是否有风险,或者需要将tracing转为metric,log转为metric,甚至是一些CI/CD事件关联到核心监控视图,从而快速找出监控视图中的数据异常是否是由某个变化引起的。我们都有成熟的工具收集上述描述我们系统运行状态的指标到Prometheus平台。此外,我们还可以通过标记将一些无意义的计算单元标记为有意义的业务语义,然后将这些指标聚合到Prometheus。所以这里的核心思想就是打破数据边界,把所有能够真实反映我们当前操作系统状态的指标汇集起来。无需编码成本,我们就可以将这些数据关联起来,产生有效的监控视图和告警。在具体实施上,我们总结了三个层次,以便更好地实施。第一层次:从业务角度定义核心目标。首先,我们需要定义核心目标。这些监控指标必须服务于业务。指标本身没有实际意义,只是一个数值。只有某些业务目标才能赋予这些指标生命力。.第二层:聚焦核心指标,提供角色观核心目标设定好后,要确保核心目标可以量化。需要特别注意的是,核心指标必须是动态变化的,因为微服务的特点就是不断快速迭代。你今天可能不依赖某个组件,但你可能在下一次迭代中依赖它。如果你没有依赖组件的指标,那将是非常痛苦的。因为没有办法通过这些核心指标来完全映射出核心目标是否有异常。此外,还需要提供基于角色的视图。组织中的不同角色关注不同的观点。当出现问题时,角色视图可以帮助更快地解决问题。第三层:全量采集&超前定义&超前聚合/过滤实现以上两层的核心基础其实就是全量采集,即能采集的指标都要采集。全量采集的技术基础是metric指标相对于log和trace的存储成本最小。即使是全量采集也不会增加太多的成本,但即使在快速迭代的过程中,也能让你的核心目标测出效果。没有损坏。在全量采集的前提下,我们需要尽快聚合或过滤掉基数大的标签。高基数问题是时序场景中的常见问题。我们会在收集到的容器层指标中看到一些PodID,但是这种标签没有实际的业务意义。比如url路径会发散,带来uid或者orderid等业务id,我们可能关心的是整个接口的健康状态,而不是某条路径。这时候我们就需要聚合路径。这种聚合可以降低存储成本并提高存储稳定性。影响核心目标的实现。另外,我们收集指标的时候,尽量找出多层之间有关联的标签。比如在采集一些应用的指标时,我们可以使用Prometheus的relabel功能将pod名称采集到一起,这样就可以直接建立应用与容器层的关联视图,排查问题时通过关联分析减少MTTD时间.接下来说说如何使用Tag来细化监控范围。Pod本身并没有实际的业务语义,而是打上一些标签后,比如一个Pod是属于登录服务还是支付服务,是属于生产环境还是测试预发布环境。这使得计算单元Pod具有实际的业务语义。有了业务语义之后,就可以配置低噪音警报了。比如,当我们支付成功率低于三个9时,我们认为核心目标已经损坏,需要立即报警。告警后,通过Tag可以快??速定位问题出在生产环境还是测试环境。如果是生产环境,必须马上处理。可以定位北京是哪个可用区,告警原因是哪个服务接口异常。所以,报警的有效性也是非常重要的,因为在实践中我们都知道,如果报警一直处于流量轰炸的状态,报警最终会变得毫无意义。通过Tag,我们可以提供基于场景的视图。假设老板想获取生产环境支付业务CPU使用率前5的Pod列表。通过Tag和PromQL语言,我们可以用一条语句立即得到这个视图。说说一个真实的电商场景是如何通过Prometheus搭建统一监控平台的。从图中可以看出,电商系统主体已经迁移到阿里云上,分为两部分,一个在Kubernetes集群,一个在ECS虚拟机集群。每个服务依赖不同的中间件或DB组件,有的依赖云产品,有的依赖原有的自建DB或组件。我们可以看到,使用之前的监控方案,很难做到全面的监控指标采集。应用层的同学通常只关心应用层是否正常,有哪些指标可以反映健康状态。他们可能会选择一些APM工具,或者与他们使用的开发语言相关的特定监控工具。比如使用SpringBoot的同学会通过Actuator监控应用状态。负责SRE的同学通常关心的是基础设施是否正常,Kubernetes组件如何监控,容器的黄金指标水位是否正常。他们可能是不同的部门,他们会通过不同的监控工具来实现不同的监控系统。这些系统是分散的,所以当你解决问题时,我们都有感觉。很多时候可能是网络问题,有时候也可能是问题。某主机出现问题,影响应用性能。如果只看应用层,你会认为应用代码没有问题,但有了这样的全局观,你会很快找出影响你应用的问题点在哪里。我们可以使用nodeexporter来采集VM层面的CPU、内存、IO三大黄金指标,也可以使用cloudmonitoringexporter来监控应用所依赖的云服务的健康状态。当然,Prometheus在Kubernetes和容器层提供的能力更全面。比如kube-state-metrics可以监控Kubernetes的元数据,cadvisor可以收集容器运行时指标,也可以监控各种kube组件。一个采集作业,或者直接使用开源或者云产品,开箱即用。此外,我们团队提供ARMSAPM,以非侵入方式生产,暴露应用指标,全面监控应用健康状态。如果不能满足你的需求,你也可以使用Prometheus官方的多语言客户端库或者第三方提供的一些客户端库来轻松生产和暴露你的指标。也有很多官方或者第三方的exporter可以用来监控db和mysql、redis、nginx、kafka等中间件。另外,对于特定语言的开发,比如JVM,还有JMXexporter可以用来检测堆内存是否被正常使用,GC是否频繁发生。通过Prometheus及其生态,可以很容易的将规范化、统一的指标汇集在一起??,进而定义SLO。在电商系统的场景下,以支付成功率为例,这是一个非常关键的指标。如果你的付款成功率很低,GAAP今天可能会损失很多。使用SLI准确衡量核心目标是否受到损害。例如,SLI是应用程序级别接口错误的指标。您可能还需要关注运行应用程序的容器、其内存和CPU是否处于健康水位。如果超过了健康水位,这可能是一个预警,一定时间内就会出现故障。有了这些指标,使用Grafana和AlertManager,就可以轻松完成可视化和告警配置,在应用异常不符合预期时及时告警,快速定位问题范围。如图所示,我们可以看到Grafana全面展现了应用层、依赖中间件、容器层、宿主层的全貌。基于Prometheus,我们还可以衍生出很多应用。比如Kubernetes上的网络拓扑很难描述,但是基于epbf技术,可以收集Kubernetes工作负载之间的各种关系,并将这种关系转化为指标,结合Prometheus收集Kubernetes集群元信息指标,它非常方便描述整个网络拓扑,方便定位集群中的网络问题。我们已经提供了相关的云产品,而且因为是基于ebpf实现的,所以也适用于多种语言,完全无侵入。另一个例子与资源使用成本有关。由于云原生架构的弹性和动态性,我们很难衡量每个应用程序消耗了多少资源,花费了多少。但是通过加入Prometheus和自己的计费系统,定义每一个资源的计费,就很容易描述一个部门和每一个应用的成本视图。当应用的资源消耗不合理时,我们也可以给出优化建议。4.大规模实施的实际挑战和解决方案接下来我们来讨论Prometheus实施的技术挑战和相应的解决方案,包括:多云多租户场景下大规模运维的可用性降低,MTTD和MTTR时间数据量大,长时间跨度查询性能差,GlobalView基数高为了应对以上挑战,我们将采集和存储分离。这样做的好处是采集端要尽量轻,存储端的可用性要足够强,可以支持公有云、混合云、边缘,或者多种环境。分离后,我们分别优化了采集和存储的可用性,并保持与开源相同的使用方式。接下来,您可以看到部署拓扑图。采集端部署在业务端的集群中,自然是多租户的。在存储端,我们采用超大规模的Kubernetes集群进行多租户部署。计算和存储是分开的。这些租户共享资源池,容器层物理隔离,通过云盘和NAS存储索引和索引值文件,可以保证一定的灵活性和单租户水平扩展能力,同时我们对使用的资源有限制由每个租户来避免一个租户的资源分配消耗影响其他租户。最后,为了解决多租户问题,我们实现了元信息集中管理,保证租户数据的最终一致性。在进行故障调度时,通过集中的元信息管理可以很方便的进行故障转移。改造后,节点故障1分钟内恢复,Pod故障10秒内恢复。我们在获取端做了易用性的提升,因为开源的Prometheus是单体应用,单一的副本无法保证高可用。我们将采集端改造为多副本模型,共享相同的采集配置,根据采集量将采集目标调度到不同的副本。当采集量发生变化或有新的采集目标时,会计算副本采集水位,动态扩容,保证采集可用性。在存储方面,我们也实施了一些可用性保证。写的时候可以根据时间线的数量动态扩展存储节点,也可以根据索引使用的pagecache是??否超过限制来扩展容量。读取时也会根据时间线和时间点的数量进行限制,保证查询和存储节点的可用性。此外,我们知道时间序列数据库会被压缩。如果集中压缩的话,IO抖动会很厉害,所以我们做了一个调度算法,对节点进行分批压缩,从而减少抖动。在大数据查询性能方面,我们可以看一个典型的PromQL查询案例。总数据量有6亿个时间点和600万条时间线。如果使用开源系统查询,会占用25G带宽,查询可能需要三分钟。但是,我们做了一些优化,比如DAG执行优化。简单的说,就是解析执行语句。如果发现重复的子查询,我们将删除重复的,然后将查询并行化以减少RT。还有算子下推,将查询节点的部分算子计算逻辑下推到存储节点,可以减少原始指标数据的传输,大大降低RT。对于大促场景,应用开发者或SRE在大促前频繁查询行情。除了开始和结束时间之外,执行的PromQL是相同的。因此,我们做了场景设计,并缓存了计算结果。对起止时间缓存范围部分进行增量查询。最后将Gorilla压缩算法与流式响应相结合,避免一次性批量加载到内存中进行计算。优化后,针对海量大数据的查询性能优化到8-10秒,70%的场景性能可以提升10倍以上。这部分简单说一下安全问题。云应用非常注重安全,一些指标数据比较敏感,可能不会被无关的业务方获取。因此,我们设计了租户级别的认证机制,在租户级别对生成Token的密钥进行加密,加密过程是企业级安全的。如果出现代币泄露,影响范围可以降到租户级别。受影响的租户只需更改加密密钥生成新令牌,并丢弃旧令牌即可消除安全风险。除了以上部分,我们还做了一些其他的技术优化,下面简单介绍一下。对于高基数问题,通过预聚合收敛发散指标,可以在一定程度上缓解高基数问题,同时降低存储成本。此外,我们通过将时间线索引拆分到分片级别来优化全局索引。当分片过期时,索引也将被删除,减少了短跨度查询需要加载的时间线数量。大时间跨度查询实现了Downsampling,牺牲了一定的精度来换取查询的性能和可用性。采集能力提高了单副本的采集能力,可以减少代理用户端的资源消耗。最后是阿里云Proemtheus监控与开源版本的对比。在可用性方面,当开源版本达到百万级时间线后,内存消耗会暴涨,基本无法使用。并且由于是单副本,如果所在主机出现一些网络异常或者问题,整个监控系统就会不可用。虽然开源的Thanos和Cortex做了一些可用性的提升,但总体来说,并没有彻底解决可用性问题。我们已经分离了收集和存储架构。采集存储端理论上可以无限扩展,可用性比较高。另外,存储时间理论上没有上限。但是如果开源版本存储指标1个月,时间线会膨胀很多,查询和写入基本不可用。5.云原生可观察性的发展趋势和前景最后说一下云原生可观察性的发展趋势。我个人认为未来的可观察性一定是标准化的,开源驱动的。现在整个软件架构体系越来越复杂,我们需要监控的对象越来越多,场景也越来越广。封闭的单一供应商很难在各个方面实现全球可观察性。它需要社区生态的参与,以开放和标准的方式构建云原生的可观察性。我们可以看看metric、log、tracing之间的关系。这三者在从低到高的不同维度上各有所长。在告警有效性方面,metric是最有效的,因为metric最能反映系统状态,不会因为偶尔的抖动导致告警轰炸,导致告警平台彻底失效。但是从排查的深度来说,看tracing和log肯定是有必要的。另外,在单条记录的存储成本上,metric远低于tracing和log。所以基于此,我个人认为以后会以metric作为接入点,然后将trace和log关联起来。tracing和log只有在metric判断系统异常时才需要收集和存储。这样既可以保证问题的有效性,又可以降低资源使用成本。这种形式是理想合理的,符合未来的发展趋势。