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

Posted 高可用架构

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在微服务架构下基于 Prometheus 构建一体化监控平台的最佳实践相关的知识,希望对你有一定的参考价值。

随着 Prometheus 逐渐成为云原生时代的可观测事实标准,那么今天为大家带来在微服务架构下基于 Prometheus 构建一体化监控平台的最佳实践和一些相关的思考,内容主要包括以下几个部分:

  • 微服务、容器化技术演进的监控之痛
  • 云原生时代,为什么是 Prometheus
  • 阿里云 Prometheus 在微服务场景的落地实践
  • 大规模落地实践挑战和解决方案
  • 云原生可观测性的发展趋势和展望

  • 01

    微服务、容器化技术演进的监控之痛

    Aliware



    01


    第一个挑战:监控对象动态化


    容器化部署使得我们的监控对象变得动态化。随着 K8s 这种服务编排框架大规模落地,应用部署单元从原来的主机变成一个 Pod。Pod 在每次发布时销毁重建,IP 也发生变化。在微服务体系下,我们讲究快速迭代、持续集成,这使得发布变得愈发频繁,Pod 生命周期变得非常短暂。据统计,平均每个 Pod 的生命周期只有两三天,然后就会被销毁,再去重建。而且随着 DevOps 普及,负责应用发布的角色发生变化,应用发布变得弱管控和更加敏捷,一个应用会不断的进行滚动发布,从而达成快速迭代的目标。

    所以说,随着软件生产流程的变化和相关技术的成熟,我们的监控对象处于一个不断频繁变化的状态之中。

    02


    第二个挑战:监控层次/对象多样化


    首先,Kubernetes 相关的 kube 组件以及容器层是我们必须要监控的新对象。其次,微服务拆分之后,以及行业在中间件,DB 等领域的精细化发展使我们发现依赖的 PaaS 层组件越来越多样化,对这些应用强依赖的 PaaS 组件也需要进行监控。最后就是多语言。当微服务拆分之后,每个团队都可以选择自己擅长的语言去进行应用开发。这就造成一个问题,即这些应用的监控指标需要支持各种语言的 client library 才能去生产和暴露。


    03


    第三个挑战:监控内容复杂化


    监控内容复杂化来源于以下几点,第一个是复杂的应用依赖。第二个是在高度分布式环境下,我们需要非常复杂,细颗粒度的指标才能描绘整个系统状态。


    上面这张图我们可以更直观的感受到以上挑战是如何产生的,左边是传统单体应用的部署架构,右边是微服务部署的架构。原来只需监控一个应用对象,现在变成了几十、上百个且不停的动态的发布,IP 地址不停变化。传统监控工具可能会采用静态配置的方式去发现这些监控目标。但在微服务场景下,这种方式已经无法实施。原来单体应用可能只需要依赖 mysql 就可以了。但现在依赖的组件越来越多。传统监控工具是没有办法全面支持这种庞大的监控需求,且传统监控工具缺乏在容器层的监控能力。

    为了解决上述问题,我们发现 Prometheus 或许是一个理想的解决方案。

    02

    云原生时代,为什么是 Prometheus

    Aliware


  • 动态化:Prometheus 具有先发优势。在 Kubernetes 诞生之初,标配监控工具就是 Prometheus,天然契合 Kubernetes 的架构与技术特征,可以去自动发现监控目标。在大规模、监控目标不停变化的监控场景下,根据实践经验,主动拉取采集是一种比较好的实现方式,可以避免监控目标指标漏采,监控目标需要解决维护采集点配置以及 push 模式实现成本较大等一系列问题。其次,动态化的容器指标通过 Kubernetes 的 Kubelet/VK 组件采集,它们天然采用 Prometheus 格式生产和暴露指标数据。


  • 多样化:因为 Kubernetes 有很多的控制面组件,比如 API server 等组件,也是天然通过 Prometheus 数据格式来暴露监控指标,这使得 Prometheus 采集这些组件的监控指标非常标准和简单。其次,Prometheus 是一个开放性社区,有 100+ 个官方或非官方 exporter 可以供大家使用。比如,你想监控数据库、消息队列、分布式存储、注册中心、网关,各种各样的 exporter 开箱即用,可以把原组件非 Prometheus 标准的数据格式转化成 Prometheus 的数据格式供采集器进行采集。再者,Prometheus 支持 go、Python、Java 等 20 多种语言,可以非常简单的为应用生成和暴露监控的 metric。最后,Prometheus 可扩展性非常强,如果上面都满足不了应用需求,它也有强大的工具可以帮助业务方轻松的写出自己的 exporter。


  • 复杂化:Prometheus 定义了一个多维模型。多维模型可以简单理解为我可以给任何事情都打上标签,通过标签的方式来描述对象的系统状态。多维模型听起来比较简单,但很多监控工具最开始无法用这种方式去描述它的监控目标。通过多维模型,我们可以很容易刻画出整个监控目标的复杂状态,还可以刻画出应用之间的依赖关系。



  • 其次,Prometheus 实现了一种称为 PromQL 的查询语言,非常强大,可以将复杂的指标进行过滤、聚合、计算。它内置有 20-30 种计算函数和算子,包括常见的累加,差值,平均值、最大最小值,P99,TopK 等,可以基于这些计算能力直接绘制指标视图和配置告警,这可以省去原本需要的代码开发工作,非常容易的得到想要的业务结果。

    可以看到上图中一个真实的 PromQL 语句,http_request_duration_seconds_bucket 是一个 Histogram 类型的指标,它有多个 bucket,通过上面的 PromQL 语句,不用编写任何代码就可以计算出 RT 超过 500ms 和 1200ms 的请求占比,从而得出 Apdex Score,评价某个接口的服务能力。


    03

    Prometheus 落地实践方案

    Aliware

    接下来,我们看一个完整的落地实践方案。其核心就是如何围绕 Prometheus 来构建可观测平台,也就是如何把描述系统状态的各个层次的指标数据都汇聚到 Prometheus 数据监控数据平台上。


    之前我们几乎是不可能完成这种将各类指标进行汇聚的工作的。因为每个监控工具专注的领域不一样,数据格式不一样,工具之间的数据无法打通,即使汇聚在一起也无法产生 1+1>2 的效果。


    但通过 Prometheus 可以把 IaaS、PaaS 层的各种组件的监控指标都汇聚在一起。如果需要采集一些业务指标、应用的健康状态、云上应用所依赖的云产品是否正常,Kubernetes 组件有没有在正常运行,容器的 CPU,内存水位是否符合预期,Node 节点 tcp 连接数分配有没有风险,或者需要将 tracing 转成 metric,log 转成 metric,甚至一些 CI/CD 事件想要和核心监控视图关联起来,从而快速发现到底监控视图的数据异常是不是由某次变更引起的。我们都有成熟的工具以将以上描述我们系统运行状态的指标采集到 Prometheus 平台。


    另外,我们还可以把一些把无意义的计算单元,通过标记的方式标记成有意义的业务语义,然后把这些指标也汇聚到 Prometheus 上面来。


    所以这里的核心思想就是打破数据边界,把所有能够真实反映我们当前运行系统状态的指标汇聚在一起,无代码编写成本,就可以将这些数据关联,生产出有效的监控视图和告警。在具体实施方面我们总结出三个层次,以便更好的实施。


    第一个层次:从业务视角定义核心目标
    首先,我们需要定义核心目标,这些监控的指标一定是为业务服务,指标本身并无实际意义,只是一个数值,只有确定的业务目标才能赋予这些指标生命力。


    第二个层次:聚焦核心指标&提供角色视图
    在制定核心目标后,我们需要确定核心目标可以被量化。需要特别注意,核心指标一定是动态变化的,因为微服务的特点就是要不停快速迭代。今天可能还没有依赖某组件,可能下个迭代就依赖了,如果你没有被依赖组件的指标,会非常痛苦。因为没有办法通过这些核心指标去完整映射核心目标到底有没有异常。另外,需要根据角色去提供视图,一个组织里不同角色关心的视图是不一样的,当出现问题时,角色视图可以帮助更快地排查问题。


    第三个层次:全量收集&提前定义&提前聚合/过滤
    想要实现上面两层的核心基础其实就是是全量收集,即能采集的指标一定要应采尽采。全量采集的技术基础是 metric 指标的存储成本是相对于 log 还有 trace 而言最小,即使全量采集也不会让成本膨胀太多,却能让你的核心目标度量效果即使在快速迭代的过程也不受损。


    在全量采集前提下,我们要尽早去聚合或过滤掉高基数的 label。高基数问题是时序场景常遇到的问题,我们会看到采集的容器层指标带一些 Pod ID,但这种 label 是没有实际业务意义,再比如 URL path 会发散,带上了 uid 或者 order id 之类的业务 id,我们可能关心的是整个接口的健康状态,而不是某一个 path 的,这时就需要把 path 聚合一下,通过这种聚合可以减少存储成本,提升存储稳定性,也不会影响核心目标的达成。


    另外,在我们采集指标时,尽量找出多层之间有关联关系的 label。比如在采集一些应用指标时,我们可以通过 Prometheus relabel 的功能把 pod name 一起采集过来,这样就可以直接建立应用和容器层的关联视图,在排查问题时通过关联分析减少 MTTD 时间。


    接下来,我们讲一下如何利用 Tag 细化监控范围。Pod 本身是没有实际的业务语义的,但打上一些标签后,比如 某个 Pod 属于登录服务还是支付服务,属于生产环境还是测试、预发环境。就使得 Pod 这个计算单元有了实际业务语义。当有了业务语义之后,就可以配置出低噪音的告警。比如当我们支付成功率低于三个 9 的时候,认为核心目标已经受损了,需要马上告警出来。告警之后通过 Tag,就可以迅速定位到底是生产环境还是测试环境的问题。


    如果是生产环境就要马上去处理,可以定位到底在北京哪个可用区,告警的原因到底是因为哪个服务的接口出现了异常。所以说告警的有效性也非常重要,因为我们在实践中都知道,如果告警一直是处于流量轰炸状态,告警最后就会变得没有意义。


    通过 Tag,我们可以提供场景化的视图,假设老板想要去捞取生产环境下支付服务 CPU 利用率 Top5 的 Pod 列表,通过 Tag 加上 PromQL 语言,我们一条语句就可以把这个视图马上捞取出来。


    讲一个真实的电商场景如何通过 Prometheus 构建统一监控平台的。从图中看到,电商系统的主体已经迁移到阿里云上,分两部分,一部分是在 Kubernetes 集群,另一部分是在 ECS 的虚机集群。每个服务依赖不同的中间件或 DB 组件,有些依赖云产品,还有一些依赖原有自建 DB 或组件。


    我们可以看到使用之前的监控方案,很难实现全面的监控指标采集。应用层的同学通常只关心应用层正不正常,有哪些指标可以反映健康状态,他们可能会选择一些 APM 工具,或者其使用的开发语言相关的特定监控工具,比如使用 Spring Boot 的开发同学会通过 Actuator 监控应用状态。而负责 SRE 的同学通常会关心基础设施正不正常,怎么监控 Kubernetes 组件,容器的黄金指标水位是否正常。他们可能是不同的部门,会通过不同监控工具实现不同的监控系统,这些系统之间是割裂的,所以你去排查一个问题,我们都有一个体感,很多时候可能是网络问题,有些时候可能是某一台主机有问题,影响了应用性能,如果只看应用层,会觉得应用代码没有问题,但是有了这样一个全局的视图,就会很快排查到影响你应用的问题点到底在哪。


    我们可以通过 node exporter 去采集 VM 层面 CPU、内存、 IO 黄金三指标,也可以通过云监控的 exporter,监控应用依赖的云服务健康状态。当然 Kubernetes 和容器这一层 Prometheus 提供的能力更加全面,比如 kube-state-metrics 可以监控 Kubernetes 的元信息,通过 cadvisor 可以采集容器运行时指标,还有各种 kube 组件的监控,动动手指头配置几个采集 job,或者直接用开源或者云产品,开箱即用。


    另外我们团队提供了 ARMS APM,以无侵入的方式去生产,暴露应用的指标,全面监控应用健康状态。如果不能满足需求的话,你也可以使用 Prometheus 官方的多语言 client library 或者三方提供的一些 client library 很方便的去生产和暴露你的指标。还有很多官方或者三方的 exporter 可以用来监控 mysql,redis,nginx,kafka 等 DB 和中间件。除此之外,针对特定语言开发,比如 JVM,还有 JMX exporter 可以使用,查看堆内存有使用正不正常,GC 是不是在频繁的发生。


    通过 Prometheus 及其生态,规范化,统一的指标可以很容易的汇聚在一起,接下来我们就可以定义 SLO。在电商系统场景下,以支付成功率为例,这是很要命的一个指标,如果你的支付成功率低了,可能今天 gaap 就会损失很大。通过 SLI 去准确衡量核心目标是否受损。比如 SLI 是应用层面的接口 error 这种指标,可能还需要关注应用运行的容器,其内存、CPU 是否在健康水位,如果超出健康水位,这可能就是预警,在接下来某段时间就会发生故障。有了这些指标,使用 Grafana 和 AlertManager,就可以轻松完成可视化和告警配置,在应用异常不符合预期时及时告警,快速定位问题范围。


    如图,我们可以看到 Grafana 全面的展示了应用层,依赖的中间件、容器层、以及主机层的全量视图。


    基于 Prometheus,我们还可以衍生出非常多的应用。举个例子,Kubernetes 上的网络拓扑是很难刻画出来的,但基于 epbf 技术可以采集 Kubernetes 工作负载间的各种关联关系,可以把这种关联关系转换成 metrics,结合 Prometheus 采集 Kubernetes 集群元信息指标,可以非常方便的刻画出整个网络拓扑,方便定位集群内的网络问题。我们已经提供了相关的云产品,并且由于基于 ebpf 实现,也是多语言适用且完全无侵入的。


    还有一个例子和资源使用成本相关,由于云原生架构的弹性和动态化,我们很难计量各个应用消耗了多少资源,付出多少成本。但通过 Prometheus 加上自己的账单系统,定义好每个资源的计费,很容易去刻画出来一个部门和各个应用的成本视图。当应用出现资源消耗不合理时,我们还可以给出优化建议。

    04

    大规模落地实践挑战和解决方案

    Aliware

    接下来我们讨论下,落地 Prometheus 有哪些技术上的挑战以及相应的解决方案,这其中包括:
  • 多云、多租场景
  • 规模化运维
  • 可用性降低,MTTD 和 MTTR 时间长
  • 大数据量、大时间跨度查询性能差
  • GlobalView
  • 高基数问题


  • 为了应对以上挑战,我们对采集和存储进行了分离。这样的好处就是采集端做的尽量轻,存储端可用性做的足够强,这样就可以支持公有云、混合云、边缘或者多元环境。在分离之后,我们针对采集、存储分别进行可用性优化,并保持与开源一致的使用方式。


    接下来,可以看到部署拓扑图,采集端就是部署在业务方的集群里面,所以天然就是多租的,存储端我们用超大规模 Kubernetes 集群进行多租部署,计算存储分离,这些租户共享资源池,在容器层物理隔离,通过云盘和 NAS 存储索引和指标数值文件,可以保证一定弹性和单租户水平扩容能力,同时我们对每个租户使用的资源又有限制,避免某个租户对资源的消耗影响到其他租户。

    最后为了解决多租问题,我们做了中心化的元信息管理,保证租户数据的最终一致性。在进行故障调度时,可以通过中心化的元信息管理,非常方便进行故障转移。改造之后,当 node 发生故障,在一分钟之内就可以恢复,Pod 发生故障,10s 可以恢复。


    我们对采集侧进行了可用性改造,因为开源 Prometheus 是一个单体应用,单副本是无法保障高可用的。我们把采集端改造成一个多副本模型,共享同样的采集配置,根据采集量将采集目标调度到不同的副本上。当采集量发生变化或有新增的采集目标时,会计算副本的采集水位,进行动态扩容,保证采集可用性。

    在存储侧,我们也做了一些可用性保障措施。在写的时候,可以根据时间线的数量来动态扩容存储节点,也可以根据索引所使用的 pagecache 有没有超限来进行扩容。在读的时候,也会根据时间线数量,还有时间点的数量进行限制,保证查询和存储节点的可用性。另外我们知道时序数据库都会做压缩,如果集中压缩的话,IO 抖动非常厉害,所以我们做了一个调度算法把节点进行分批压缩,这样就可以减少抖动。


    在大数据量查询性能方面,我们可以看一个比较典型的 PromQL 查询案例。总数据量有 6 亿个时间点,600 万个时间线。如果使用开源系统进行查询,要占用 25G 的带宽,查询耗时可能是三分钟。但我们做了一些优化,比如 DAG 执行优化,简单讲就是对执行语句进行解析,如果发现有重复的子查询,就去重,然后并行化查询降低 RT。

    还有算子下推,将一些算子计算逻辑从查询节点下推到存储节点实现,可以减少原始指标数据的传输,大幅度降低 RT。


    针对大促场景,应用开发者或 SRE 在大促之前频繁查询大盘,执行的 PromQL 除了起止时间有些微差别,其他都是一样的,因此,我们做了场景化设计,将计算结果缓存,对超出起止时间缓存范围的部分进行增量查询。

    最后通过 Gorilla 压缩算法结合流式响应,避免批量一次性的加载到内存里面进行计算。经过优化之后,对大规模、大数据量的查询性能优化到 8~10 秒,并对 70% 场景都可以提升 10 倍以上性能。


    这一部分简单聊一下安全问题。云上应用是非常注重安全的,有些指标数据比较敏感,可能不希望被无关业务方抓取到。因此,我们设计了租户级别的鉴权机制,会对生成 Token 的密钥进行租户级别加密,加密流程是企业级安全的。如果出现 Token 泄露,可以收敛影响范围到租户级别,只需要受影响的租户换一下加密密钥生成新的 Token,废弃掉旧 Token 就可以消除安全风险。

    除了以上部分,我们也做了一些其他技术优化,下面简单介绍一下。

  • 高基数问题
  • 通过预聚合,把发散指标进行收敛,在减少存储成本的同时,一定程度上缓解高基数问题。另外我们做了全局索引的优化,将时间线索引拆分到 shard 级别,当 shard 过期之后,索引也会随之删除,减少了短时间跨度查询时需要加载的时间线数量。

  • 大时间跨度查询
  • 实现 Downsampling,牺牲一定精度来换取查询性能与可用性。

  • 采集能力
  • 提升单副本采集能力,可以减少 agent 用户侧的资源消耗。


    最后是阿里云 Proemtheus 监控与开源版本的对比。

    在可用性方面,开源版本到了百万级时间线,内存消耗会出现暴涨,基本上是不可用的。而且因为是单副本,如果出现一些网络异常或者所在的宿主机出现问题,整个监控系统就是不可用的。

    虽然开源的 Thanos、Cortex 做了一些可用性增强,但总体来讲他们并没有完全解决可用性问题。我们做了采集存储架构分离,采集存储端理论上可以无限水平扩容,可用性比较高。而且存储时长理论上也没有上限,而开源版本存储一个月指标,时间线就会膨胀得非常厉害,查询和写入基本上都是不可用的。

    05

    云原生可观测性的发展趋势和展望

    Aliware

    最后聊一聊云原生可观测性的发展趋势,个人认为将来可观测性一定是标准化且由开源驱动的。现在整个软件架构体系变得越来越复杂,我们要监控的对象越来越多,场景也越来越广。封闭的单一厂商很难面面俱到的去实现全局可观测能力,需要社区生态共同参与,用开放、标准的方法来构建云原生可观测性。


    我们可以看一下 metric、log、tracing 的关系,这三者在不同维度上从低到高,各有特长。

    在告警有效性上来说,metric 是最有效的,因为 metric 最能真实反映系统状态,不会因为偶发抖动造成告警轰炸,告警平台完全失效的问题。但在排查问题的深度上,肯定还是需要去看 tracing 和 log。另外在单条记录存储成本上,metric 远低于 tracing 和 log。所以基于此,个人认为将来会以 metric 为接入点,再去关联 tracing 和 log,tracing 和 log 只在 metric 判定系统异常时才需要采集存储。这样就可以既保证问题抛出的有效性,又能降低资源使用成本,这样的形态是比较理想合理,符合未来发展趋势的。

    参考阅读:

  • 实时增量学习在云音乐直播推荐系统中的工程实践

  • 从Golang调度器的作者视角探究其设计之道!

  • 分布式数据库排序及优化

  • Dubbo3.0 阿里大规模实践解析——URL 重构

  • 一个C系程序员的Rust初体验

  • 本文由高可用架构翻译。技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。


    高可用架构
    改变互联网的构建方式

    51信用卡在微服务架构下的监控平台架构实践

    背景介绍


    51信用卡的技术架构是基于Spring Cloud所打造的微服务体系,随着业务的飞速发展,不断增多的微服务以及指标给监控平台带来了极大的挑战。监控团队在开源vs自研,灵活vs稳定等问题上需要不断做出权衡,以应对飞速发展的需求。本次将会分享我们在微服务下的白盒监控思考,以及如何将时下社区流行的Spring Cloud,K8S,Prometheus等开源技术在企业落地。


    本文整理自杨帆在QCon 2018 北京站上的演讲,原标题为《51信用卡在微服务架构下的监控平台架构实践》

    51信用卡在微服务架构下的监控平台架构实践

    这次主要讲的是关于微服务的监控,微服务看起来很美话,但实践起来却有很多坑,希望这次的分享能给大家一些收获或者思考。

    传统的监控分层

    传统的监控一般会将监控分层,比如我们常用的分层方式是将监控分成基础设施、系统、应用、业务和用户端这几层,分完层后将每层的监控做到位。

    51信用卡在微服务架构下的监控平台架构实践

    而在传统的监控里,zabbix 是最常用的开源软件,zabbix 的优点主要是成熟可靠,社区非常强大,几乎你的需求,社区都有一套对应的解决方案,但 zabbix 的缺点也很明显,就是太难用,很多监控配置加起来成本很高,甚至很多运维用了很久的 zabbix,还没学会怎么配置 HTTP 监控,这在应用较少的时候,还不是很明显的问题,但是到了微服务时代,这个问题就暴露得非常明显了,而且 zabbix 以机器为维度的监控也无法适用微服务时代的理念。

    以服务为维度的监控

    微服务监控比起传统应用的监控,最明显的改变就是视角的改变,我们把监控从分层+机器的视角转换成以服务为中心的视角,在微服务的视角下,我们的监控可以分为指标监控、链路监控和日志监控,在开源社区,这些监控也都有对应的解决方案,比如指标监控有 prometheus、influxdb,链路监控有 zipkin、pinpoint,日志则有 elk。

    51信用卡在微服务架构下的监控平台架构实践

    在51信用卡发展起步的时候,我们也同样使用这些开源方案来解决我们的监控问题,但当我们业务快速发展的时候,我们开始不断碰到监控上的挑战,其中有部分是互联网金融特有的,另一部分是微服务所带给我们的。


    微服务监控有什么特点?用一句话概括就是服务特别多,服务间的调用也变得非常复杂。我们其实是微服务的受害者,其实业内很多人做的架构只是服务化,并不够「微」,而我们做的比较彻底,我们线上很多服务都只有一个 API,但这样造成线上指标非常多,告警也非常多,读和写的压力都非常大。


    互联网金融是一个跟钱息息相关的行业,所以互联网金融对监控也有自己的要求。首先是对故障的容忍程度很低,监控的有效性需要被反复确认,其次是对监控的覆盖度,黑盒监控在互联网金融里很难行得通,白盒监控变得越来越重要,开发们迫切需要对自己的应用有全面的了解。然后是对告警的及时以及快速诊断有更高的需求,告警以及诊断信息在10分钟内发出与5分钟内发出有很大的差别,举个例子,如果有个活动有个漏洞被黑产行业抓住,如果能早一分钟确定问题关闭后门,就能给公司挽回巨大的损失。

    Prometheus 下的监控

    51信用卡在早期也同样使用 Prometheus,其实 Prometheus 是个很棒的产品,白盒监控的理念也很先进,自带告警以及 PromQL,稍微学习之后便能上手,作为 CNCF 的项目与 K8S 等开源产品结合得也很好。

    51信用卡在微服务架构下的监控平台架构实践

    在随着服务的增长,我们开始不断地踩坑,首先突出的问题就是 Prometheus 没有现成的分布式方案,性能遇到单机瓶颈之后只能手动给业务划分集群并且之间的数据不能共享,然后拉模式在兼容多数据源上也显得力不从心,比如我们有场景需要指定精确的时间,还有比如我们有些数据是从日志来的或是从 Kafka 来的,这些都没有现成的方案。


    微服务的指标增长其实比想像得要快很多,因为微服务架构下,我们总是迫切想要把应用的每个细节都搞清楚,比如主机指标、虚拟机指标、容器指标、应用性能指标、应用间调用指标、日志指标以及自定义的业务指标等等,甚至在这些指标下,我们还会给指标打上更多的标签,比如是哪个进程,哪个机房,我们大致算过一笔账,一个服务即使开发什么都不做,他通过基础框架就自带了5000个指标。


    我们内部也讨论过为什么指标会这么多,能不能把一些指标去掉,但很快我们就否决了去指标的想法,我们觉得业界的趋势是白盒监控会变得越来越重要,APM 的概念会变得越来越重要,devops 会和白盒监控不断发生化学反应,变成一种潮流。


    而在51信用卡,我们是怎么解决的呢,其实很简单,用三个字概况就是「平台化」,平台化的好处很多,最直观的好处就是提供了一个统一的平台去处理监控问题,并给开发带来了统一的使用体验。

    基于 Prometheus的架构改进

    我们首先要解决的问题是如何构建对上层统一的存储,一开始我们基于 Prometheus 的生态做了一些架构改进,将底层换成分布式的列式存储 Cassandra,并开发了推送服务和拉取服务来兼容原先的数据模型,在上层,我们开发了兼容 PromQL 的界面提供给开发使用。

    51信用卡在微服务架构下的监控平台架构实践

    但很快,我们就碰到了新的问题。


    首先是 labels 的匹配效率问题,当指标名相同的时候,由于 label 是自由组合的,在匹配部分 label 的时候,我们需要先将 labels 的元数据全部读出来,然后进行过滤,这样的效率会显得很低,我们的做法是在 label 元数据上面加上倒排索引,因为我们是分布式方案,倒排索引本身也需要分布式,所以我们直接使用 ES 来帮我们构建元数据。

    51信用卡在微服务架构下的监控平台架构实践

    第二个问题是预聚合,比如我们只想看 API 的整体访问量,但做这个查询的时候,我们会在底层读到4份数据,然后再聚合再显示出来,这样无疑也是一种浪费。我们的做法是引入预聚合机制,在纵向,我们需要舍弃维度,在横向,我们需要聚合时间轴。对于分布式而言,预聚合会显得比较麻烦,因为我们需要考虑的东西比较多,比如需要在内存里完成,需要合理将数据分批分配到不同机器,需要有一个窗口机制保证数据的及时有效又高性能。业内常用的做法是引入一个Storm 这样的流式计算或者 Spark Streaming 这样的微批计算,然后将计算完的结果推入缓存或者内存供告警来使用。

    51信用卡在微服务架构下的监控平台架构实践

    第三个问题是 Metric 的长度,因为在列式存储的底层,我们直接借鉴 Kairosdb 的存储格式,兼容 UTF8 的 Metric 而直接讲 Metric 转换成二进制存储在数据库里,如果指标很少,这个问题不大,但如果指标非常多,这会造成底层存储的存储浪费,而且影响索引的效率,这个问题的解决办法也很简单,直接引入一个Bitmap 机制就可以解决。


    第四个问题是维度重复,比如我们有三个指标,这三个指标的维度都一样,但这三个指标完全不同,代表不同的值,但存储在数据库的时候,它会占用三个series 的空间,查找的时候也不够高效,因为往往三个指标会同时查询同时展示。这个解决办法是将数据库里原本的 value 定义成多类型支持,不只是双精度浮点或是整型,增加 Map 的支持类型,并在数据库的上层做兼容。


    当初我们在解决这些问题的时候,我们发现社区已经有一个比较好的解决方案了,就是 Druid,不是阿里那个数据库连接池 Druid,而是 druid.io。它比较好地满足了 Bitmap、预聚合、复合类型、倒排索引、冷热数据这些需求。


    我们将拉服务和收服务做了进一步的改进,可以自动将数据做转换,兼容原先数据模型的同时,将数据也投递一份到 Druid 里。

    51信用卡在微服务架构下的监控平台架构实践

    至此我们基本完成了一个能够满足需求的存储架构改进。

    51信用卡在微服务架构下的监控平台架构实践

    最后限于时间关系,和大家分享两个非常有用又容易实践的告警智能诊断:


    第一个是和日志监控的联动,当一个告警发生的时候,我们以时间、服务为维度去匹配 ERROR 或是 Exception日志,并以 simhash 之类的相似算法排序日志,就会非常快速地找到问题的直接原因,不一定是 Root Cause,但告警的时候如果附上这个日志,对开发排查问题的效率会有很大的帮助。


    第二个是和链路监控的联动,当一个告警发生的时候,我们同样以时间、服务查询链路监控,并从日志监控里排名靠前的日志提取 trace id 后进行过滤,能很快发现故障的关联原因,这同样不一定是 Root Cause(很有可能是),但同样对开发排查问题很有帮助。

    未来

    最后展望一下未来,我们会继续在3个方向发力。

    • 第一个是更好的底层存储,Cassandra 毕竟是一个通用的列式数据库,对时序数据来说,有很多不好优化的地方,我们期望能够自研一个时序数据库来满足我们的业务需求。

    • 第二个是智能化的监控和告警,运用合适的算法并加上机器学习或是深度学习,探索出无阈值的告警体系,并自动分析出告警之间的关联关系,给出根因。

    • 第三个是APM和监控的更紧密结合,将链路监控、日志监控和指标监控直接合并,更深度地诊断系统,系统没有无法探查的秘密。

    51信用卡在微服务架构下的监控平台架构实践
    51信用卡在微服务架构下的监控平台架构实践

    作者介绍

    51信用卡 架构师,监控系统负责人


    2017年加入51信用卡,现任监控系统负责人,负责监控系统的架构升级及落地方案。在监控、私有云、分布式存储等方面有丰富的经验,同时对DevOps也充满兴趣,热衷于将开源技术与业务结合提升效率。


    英雄帖

    51信用卡技术团队正在招聘,技术岗位全线开放。如果你也想助力金融、码出NB未来,欢迎投递简历或询问:JSYF_HRBP@u51.com

    ……………………

    以上是关于在微服务架构下基于 Prometheus 构建一体化监控平台的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

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

    51信用卡在微服务架构下的监控平台架构实践

    基于 prometheus 的微服务指标监控

    基于 prometheus 的微服务指标监控

    爱奇艺号基于Prometheus的微服务应用监控实践

    微服务统计,分析,图表,监控, 分布式追踪一体化的 HttpReports 在 .Net Core 的应用