Prometheus架构与实践分享

DevOpSec
• 阅读 2294

Prometheus已经被广泛应用于数据中心监控,尤其是和Kubernetes结合的容器监控。本文主要从架构分析到落地实践,详细介绍Prometheus原理和使用。对比Prometheus与其他监控工具(Zabbix、Open-Falcon)的特点与使用场景。然后介绍Prometheus与Kubernetes集成,主要从监控和自动伸缩两个方面。最后通过企业案例,分享实践经验和注意事项。

Kubernetes从2014年开源以来,迅速成为容器管理的领头羊,它是Google Borg系统的开源实现。和Kubernetes一起火起来的还有另一个开源项目Prometheus,它是Google BorgMon的开源实现。

2016年,由Google发起的Linux基金会旗下的原生云基金会(Cloud Native Computing Foundation)将Prometheus纳入其第二大开源项目。Prometheus在开源社区也十分活跃,在GitHub上拥有两万多Star,并且系统每隔一两周就会有一个小版本的更新。

Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库。从字面上理解,Prometheus由两个部分组成,一个是监控报警系统,另一个是自带的时序数据库(TSDB)。

Prometheus架构与实践分享

上图是Prometheus整体架构图,左侧是各种符合Prometheus数据格式的exporter,除此之外为了支持推动数据类型的Agent,可以通过Pushgateway组件,将Push转化为Pull。Prometheus甚至可以从其它的Prometheus获取数据,组建联邦集群。Prometheus的基本原理是通过HTTP周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口并且符合Prometheus定义的数据格式,就可以接入Prometheus监控。

上侧是服务发现,Prometheus支持监控对象的自动发现机制,从而可以动态获取监控对象。

图片中间是Prometheus Server,Retrieval模块定时拉取数据,并通过Storage模块保存数据。PromQL为Prometheus提供的查询语法,PromQL模块通过解析语法树,调用Storage模块查询接口获取监控数据。图片右侧是告警和页面展现,Prometheus将告警推送到alertmanger,然后通过alertmanger对告警进行处理并执行相应动作。数据展现除了Prometheus自带的WebUI,还可以通过Grafana等组件查询Prometheus监控数据。

在Prometheus之前市面已经出现了很多的监控系统,如Zabbix、Open-Falcon等。那么Prometheus和这些监控系统有啥异同呢?我们先简单回顾一下这些监控系统。

Prometheus架构与实践分享

Zabbix是由Alexei Vladishev开源的分布式监控系统,支持多种采集方式和采集客户端,同时支持SNMP、IPMI、JMX、Telnet、SSH等多种协议,它将采集到的数据存放到数据库中,然后对其进行分析整理,如果符合告警规则,则触发相应的告警。

Zabbix核心组件主要是Agent和Server,其中Agent主要负责采集数据并通过主动或者被动的方式采集数据发送到Server/Proxy,除此之外,为了扩展监控项,Agent还支持执行自定义脚本。Server主要负责接收Agent发送的监控信息,并进行汇总存储,触发告警等。

为了便于快速高效的配置Zabbix监控项,Zabbix提供了模板机制,从而实现批量配置的目的。

Zabbix Server将收集的监控数据存储到Zabbix Database中。Zabbix Database支持常用的关系型数据库,例如MySQL、PostgreSQL、Oracle等,默认MySQL。Zabbix Web页面(PHP编写)负责数据查询。Zabbix由于使用了关系型数据存储时序数据,所以在监控大规模集群时常常在数据存储方面捉襟见肘。为此Zabbix 4.2版本后也开始支持时序数据存储,不过目前还不成熟。

Prometheus架构与实践分享

Open-Falcon是小米开源的企业级监控工具,用Go语言开发而成,包括小米、滴滴、美团等在内的互联网公司都在使用它,是一款灵活、可扩展并且高性能的监控方案,主要组件包括了:

  • Falcon-agent:用Go语言开发的Daemon程序,运行在每台Linux服务器上,用于采集主机上的各种指标数据,主要包括CPU、内存、磁盘、文件系统、内核参数、Socket连接等,目前已经支持200多项监控指标。并且,Agent支持用户自定义的监控脚本。
  • Hearthbeat server:简称HBS心跳服务,每个Agent都会周期性地通过RPC方式将自己的状态上报给HBS,主要包括主机名、主机IP、Agent版本和插件版本,Agent还会从HBS获取自己需要执行的采集任务和自定义插件。
  • Transfer:负责接收Agent发送的监控数据,并对数据进行整理,在过滤后通过一致性Hash算法发送到Judge或者Graph。
  • Graph:RRD数据上报、归档、存储的组件。Graph在收到数据以后,会以RRDtool的数据归档方式来存储,同时提供RPC方式的监控查询接口。
  • Judge:告警模块,Transfer转发到Judge的数据会触发用户设定的告警规则,如果满足,则会触发邮件、微信或者回调接口。这里为了避免重复告警引入了Redis暂存告警,从而完成告警的合并和抑制。
  • Dashboard:面向用户的监控数据查询和告警配置界面。

下表通过多维度展现了他们的各自的优缺点:

Prometheus架构与实践分享

从开发语言上看,为了应对高并发和快速迭代的需求,监控系统的开发语言已经慢慢从C语言转移到Go。不得不说,Go凭借简洁的语法和优雅的并发,在Java占据业务开发,C占领底层开发的情况下,准确定位中间件开发需求,在当前开源中间件产品中被广泛应用。

从系统成熟度上看,Zabbix是老牌的监控系统:Zabbix是在1998年出现的,系统功能比较稳定,成熟度较高。而Prometheus和Open-Falcon都是最近几年才诞生的,虽然功能还在不断迭代更新,但站在巨人的肩膀之上,在架构设计上借鉴了很多老牌监控系统的经验。

从系统扩展性方面看,Zabbix和Open-Falcon都可以自定义各种监控脚本,并且Zabbix不仅可以做到主动推送,还可以做到被动拉取,Prometheus则定义了一套监控数据规范,并通过各种exporter扩展系统采集能力。

从数据存储方面来看,Zabbix采用关系数据库保存,这极大限制了Zabbix采集的性能,Open-Falcon采用RDD数据存储,并且可以对接到OpenTSDB,而Prometheus自研一套高性能的时序数据库,在V3版本可以达到每秒千万级别的数据存储,通过对接第三方时序数据库扩展历史数据的存储。

从配置和维护的复杂度上看,Prometheus只有一个核心server组件,一条命令便可以启动,相比而言,其他系统配置相对麻烦,尤其是Open-Falcon。

从社区活跃度上看,目前Zabbix社区活跃度比较低,Open-Falcon虽然也比较活跃,但基本都是国内的公司参与,Prometheus在这方面占据绝对优势,社区活跃度最高,并且受到CNCF的支持,后期的发展值得期待。

从容器支持角度看,由于Zabbix出现得比较早,当时容器还没有诞生,自然对容器的支持也比较差。Open-Falcon虽然提供了容器的监控,但支持力度有限。Prometheus的动态发现机制,不仅可以支持Swarm原生集群,还支持Kubernetes容器集群的监控,是目前容器监控最好解决方案。Zabbix在传统监控系统中,尤其是在服务器相关监控方面,占据绝对优势。伴随着容器的发展,Prometheus开始成为主导及容器监控方面的标配,并且在未来可见的时间内被广泛应用。总体来说,对比各种监控系统的优劣,Prometheus可以说是目前监控领域最锋利的“瑞士军刀”了。

Prometheus架构与实践分享

标格式分为两个部分:一份是指标名称,另一个是指标标签。标签可体现指标的维度特征,用于过滤和聚合。它通过标签名(label name)和标签值(label value)这种键值对的形式,形成多种维度。例如,对于指标http_request_total,可以有{status="200", method="POST"}和{status="200", method="GET"}这两个标签。在需要分别获取GET和POST返回200的请求时,可分别使用上述两种指标;在需要获取所有返回200的请求时,可以通过http_request_total{status="200"}完成数据的聚合,非常便捷和通用。

指标类型有四种:

  • Counter(计数器):计数统计,累计多长或者累计多少次等。它的特点是只增不减,譬如HTTP访问总量。
  • Gauge(仪表盘):数据是一个瞬时值,如果当前内存用量,它随着时间变化忽高忽低。如果需要了解某个时间段内请求的响应时间,通常做法是使用平均响应时间,但这样做无法体现数据的长尾效应。例如,一个HTTP服务器的正常响应时间是30ms,但有很少几次请求耗时3s,通过平均响应时间很难甄别长尾效应。
  • Histogram(直方图):服务端分位,不同区间内样本的个数,譬如班级成绩,低于60分的9个,低于70分的10个,低于80分的50个。
  • Summary(摘要):客户端分位,直接在客户端通过分位情况,还是用班级成绩举例:0.8分位的是,80分,0.9分为85分,0.99分为的是98分。

Prometheus架构与实践分享

Prometheus通过HTTP接口的方式从各种客户端获取数据,这些客户端必须符合Prometheus监控数据格式,通常有两种方式,一种是侵入式埋点监控,通过在客户端集成,如果Kubernetes API直接通过引入Prometheus go client,提供/metrics接口查询kubernetes API各种指标;另一种是通过exporter方式,在外部将原来各种中间件的监控支持转化为Prometheus的监控数据格式,如redis exporter将Reids指标转化为Prometheus能够识别的HTTP请求。

HTTP返回Header和Body如上图所示,指标前面两行#是注释,标识指标的含义和类型。指标和指标的值通过空格分割,开发者通常不需要自己拼接这种个数的数据, Prometheus提供了各种语言的SDK支持。

Prometheus并没有采用json的数据格式,而是采用text/plain纯文本的方式,这是它的特殊之处。

Prometheus架构与实践分享

Prometheus为了支持各种中间件以及第三方的监控提供了exporter,大家可以把它理解成监控适配器,将不同指标类型和格式的数据统一转化为Prometheus能够识别的指标类型。

譬如Node exporter主要通过读取Linux的/proc以及/sys目录下的系统文件获取操作系统运行状态,reids exporter通过Reids命令行获取指标,mysql exporter通过读取数据库监控表获取MySQL的性能数据。他们将这些异构的数据转化为标准的Prometheus格式,并提供HTTP查询接口。

Prometheus架构与实践分享

Prometheus提供了两种数据持久化方式:一种是本地存储,通过Prometheus自带的TSDB(时序数据库),将数据保存到本地磁盘,为了性能考虑,建议使用SSD。但本地存储的容量毕竟有限,建议不要保存超过一个月的数据。Prometheus本地存储经过多年改进,自Prometheus 2.0后提供的V3版本TSDB性能已经非常高,可以支持单机每秒1000w个指标的收集。

Prometheus本地数据存储能力一直为大家诟病,但Prometheus本地存储设计的初衷就是为了监控数据的查询,Facebook发现85%的查询是针对26小时内的数据。所以Prometheus本地时序数据库的设计更多考虑的是高性能而非分布式大容量。

另一种是远端存储,适用于大量历史监控数据的存储和查询。通过中间层的适配器的转化,Prometheus将数据保存到远端存储。适配器实现Prometheus存储的remote write和remote read接口,并把数据转化为远端存储支持的数据格式。目前,远端存储主要包括OpenTSDB、InfluxDB、Elasticsearch、M3DB等,其中M3DB是目前非常受欢迎的后端存储。

Prometheus架构与实践分享

Prometheus数据展现除了自带的WebUI还可以通过Grafana,他们本质上都是通过HTTP + PromQL的方式查询Prometheus数据。和关系型数据库的SQL类似,Prometheus也内置了数据查询语言PromQL,它提供对时间序列数据丰富的查询,聚合以及逻辑运算的能力。

数据运算包括了:

  • +(加法)
  • -(减法)
  • *(乘法)
  • /(除法)
  • %(求余)
  • ^(幂运算)

聚合包括了:

  • sum(求和)
  • min(最小值)
  • max(最大值)
  • avg(平均值)
  • stddev(标准差)
  • stdvar(标准差异)
  • count(计数)
  • count_values(对value进行计数)
  • bottomk(后n条)
  • topk(前n条)
  • quantile(分布统计)

如果需要获取某个时刻的数据可以通过curl 'http://Prometheus地址:9090/api/v1/query?query=up&time=xx'查询监控数据,其中query参数就是一个PromQL表达式。除此之外,还支持范围查询query\_range,需要额外添加下面的参数:start(起始时间)、end(结束时间)、step=(查询步长)。

Prometheus架构与实践分享

当接收到请求参数后,通过PromQL引擎解析PromQL,确定查询的数据序列和时间范围,通过tsdb接口获取对应数据块(chunks),最后根据聚合函数处理监控数据并返回。

Prometheus架构与实践分享

如果监控数据达到告警阈值Prometheus Server会通过HTTP将告警发送到告警模块alertmanger。Prometheus告警配置也是通过yaml文件,核心是上面的expr表达式(告警规则)和查询一样也是一个PromQL表达式。for代表持续时间,如果在for时间内持续触发Prometheus才发出告警。

告警组件alertmanger地址是在Prometheus的配置文件中指定,告警经过alertmanger去重、抑制等操作,最后执行告警动作,目前支持邮件、slack、微信和webhook,如果是对接钉钉,便可以通过webhook方式触发钉钉的客户端发送告警。

Prometheus架构与实践分享

为了扩展单个Prometheus的采集能力和存储能力,Prometheus引入了“联邦”的概念。多个Prometheus节点组成两层联邦结构,如图所示,上面一层是联邦节点,负责定时从下面的Prometheus节点获取数据并汇总,部署多个联邦节点是为了实现高可用以及数据汇聚存储。下层的Prometheus节点又分别负责不同区域的数据采集,在多机房的事件部署中,下层的每个Prometheus节点可以被部署到单独的一个机房,充当代理。

Improbable开源的Thanos提供了Prometheus集群化能力,感兴趣的朋友可以深入了解一下。

Prometheus的流行和Kubernetes密不可分,下面将介绍如何通过Prometheus监控Kubernetes集群。首先介绍Prometheus的自动发现机制。

Prometheus架构与实践分享

Prometheus有两种方式配置监控对象,一种是通过静态文件配置,另一种是动态发现机制。

目前动态发现目前已经支持Kubernetes、etcd、Consul等多种服务,动态发现可以减少运维人员手动配置,在容器运行环境中尤为重要,容器集群通常在几千甚至几万的规模,如果每个容器都需要单独配置监控项不仅需要大量工作量,而且容器经常变动,后续维护更是异常麻烦。针对Kubernetes环境的动态发现,Prometheus通过Watch Kubernetes API动态获取当前集群所有主机、容器以及服务的变化情况。

Prometheus架构与实践分享

通过自动发现机制,Prometheus可以动态获取Node和Pod的变化,将Node exporter和cAdvisor加入监控。针对容器常用的监控指标包括:

CPU利用率:

  1. rate(container_cpu_usage_seconds_total{
  2. container_name="xxx", pod_name="xxx"
  3. }[5m]
  4. )

内存用量(使用内存减去缓存):

  1. container_memory_usage_bytes{
  2. container_name="xxx", pod_name="xxx"
  3. }
  4. -
  5. container_memory_cache{
  6. container_name="xxx", pod_name="xxx"
  7. }

网络发送速率:

  1. rate(container_network_transmit_bytes_total{
  2. pod_name="xxxx"
  3. }[5m]
  4. )

网络接收速率:

  1. rate(container_network_receive_bytes_total{
  2. pod_name="xxxx"
  3. }[5m]
  4. )

Prometheus架构与实践分享

和其他的Kubernetes的Operator类似,Prometheus Operator通过定义下面四种Kubernetes的CRD资源,从而实现通过操作Kubernetes资源去管理Prometheus的监控和告警的目标。

  • Prometheus:Prometheus Deployment定义
  • ServiceMonitor:Prometheus监控对象的定义
  • PrometheusRule:告警规则
  • Alertmanager:Alertmanager Deployment定义

Prometheus架构与实践分享

HPA是Kubernetes提供的水平伸缩服务,原生支持基于CPU利用率的扩缩容。如果用户希望根据自定义指标(如QPS)扩容,可以借助Kubernetes的custom metrics API。

Kubernetes资源扩展通常由两种方式,一种是通过上面Operator使用的CRD,另一种是通过Aggregated API Server(未来可能会被Kubebuilder代替)。custom-metrics-apiserver便是通过Aggregated API扩展Kubernetes的custom metric接口。

HPA查询自定义监控数据的请求通过kube-apiserver代理到custom-metrics-apiserver,并通过prometheus-adapter转化为对Prometheus数据查询,从而实现自定义指标的扩缩容。

Prometheus架构与实践分享

宜信容器云是宜信内部基于Kubernetes搭建的容器管理平台,用户可以通过平台一键部署自己的服务。平台主要功能包括了服务管理(灰度发布、自动伸缩、多集群部署等)、镜像管理、监控告警、CICD、Nginx管理、Ceph存储等多个功能。其中监控和告警和自动伸缩都是基于Prometheus构建。

Prometheus架构与实践分享

Prometheus采集的数据包括了主机性能监控、容器性能监控、Nginx访问流量、Kubernetes状态以及平台各个组件的性能指标。目前Prometheus本地数据指保留一个月,历史数据保存到M3DB中。

Prometheus一方面为页面提供性能指标查询,如nginx qps、容器CPU利用率,另一方便提供基于这些指标的性能告警,告警发送至alertmanger中,并通过alertmanger的webhook触发ipaas执行后续的告警处理(短信和邮件)。

Prometheus架构与实践分享

为了支持容器的多指标、多集群自动伸缩,平台开发一套自动伸缩模块,通过cluster-mgr定时获取Prometheus监控指标,并模仿Kubernetes的HPA计算出目标的容器副本数,最后通过调用ipaas扩容多个集群的容器副本。

最后我个人想表达,Prometheus也并非银弹。

首先,Prometheus只针对性能和可用性监控,并不具备日志监控等功能,并不能通过Prometheus解决所有监控问题。

其次,Prometheus认为只有最近的监控数据才有查询的需要,所有Prometheus本地存储的设计初衷只是保持短期(一个月)的数据,并非针对大量的历史数据的存储。如果需要报表之类的历史数据,则建议使用Prometheus的远端存储如OpenTSDB、M3DB等。

Prometheus还有一个小瑕疵是没有定义单位,这里需要使用者自己去区分或者事先定义好所有监控数据单位,避免数据缺少单位问题。

Q&A

Q:现在有高可用方案吗?

A:Prometheus的联邦或者Improbable开源的Thanos都是高可用方案。

Q:Promethues占用内存很好,我们的环境下45w指标大概要占用8G左右的内存,经常出现Prometheus容器OOM,请问有什么办法可以优化内存占用吗?

A:数据指标如果确实比较大,可以考虑Prometheus的hash采集,分摊压力。在生产过程中很多指标都是可以省去的,譬如Kubernetes中的Sandbox容器的指标。

Q:Prometheus的push方式(push推送给pushgateway)和pull正常的方式方式的性能比较,谁更好呢?

A:pushgateway本身作为数据转发的代理,本身性能损耗很少。建议直接提供prometheus的pull支持。

Q:针对于一些公司自有业务的进程数据监控是依赖于自研的go-clent上报吗?还是说一些三方的client?

A:如果可以二次开发建议直接在代码里面加入Prometheus采集的支持,处理Go以外还有Java、Python的SDK支持。如果不能二次开发也可以在外部通过exporter方式。

Q:如果有多个副本CPU利用率,还是用container_name来算就有问题了吧?另外问一下,不同版本的Pod(比如发版之后)怎么比较其CPU利用率?另外Histogram的metrics有分析过吗?查询一个月的数据应该蛮有压力的吧还是做了优化,是否有必要?

A:多副本需要group。不同版本数据都在Prometheus存储,可以通过容器名称汇聚查询出来,一个月数据step可以调整的大一些。目前看一个月内的查询基本控制在2s以内。发版之后Pod name名字是不一样的,一种方式是通过保持container name,另外一种方式是通过前缀,正则匹配,我用的后者,不过会出现很多空线条,因为前面版本不存在这个Pod name标签的metrics,这个和多副本的container_name也算是有点冲突。metric名称应该是固定的,用正则匹配,不会有问题的,历史都会查出来,另外我发现histogram的metrics超过7天之后就没有什么参考价值了 所以对于查询一个月感觉意义不大,比如prometheus_http_request_duration_seconds,metrics还是重在实时性。

Q:时序数据库跟传统数据库的优势在哪?应该如何进行选型?

A:时序数据是保存随时间变化的量,查询也是时间维度,从而实现高压缩比。关系型数据优势在于数据管理。

Q:比如要做每日用户登录数统计,具体应该怎么做?需要哪些流程和步骤?

A:需要程序里面集成SDK,并提供查询累计登录用户的http接口,并在Prometheus配置这个target。 返回搜狐,查看更多

责任编辑:

本文转自 https://www.sohu.com/a/342733264_198222,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
DOIS 2019 DevOps国际峰会北京站来袭~
DevOps国际峰会是国内唯一的国际性DevOps技术峰会,由OSCAR 联盟指导、DevOps时代社区与高效运维社区联合主办,共邀全球80余名顶级专家畅谈DevOps体系与方法、过程与实践、工具与技术。会议召开时间:2019070508:00至2019070618:00结束会议召开地点:北京主办单位:DevOps
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
DevOpSec
DevOpSec
Lv1
懂开发的运维,懂安全的运维。公众号:DevOpSec
文章
57
粉丝
6
获赞
26