监控指标能给我们解决什么问题

监控指标能给我们解决什么问题?

度量(Metrics)的目的是揭示系统的总体运行状态。

简单来说,度量就是用经过聚合统计后的高维度信息,以最简单直观的形式来总结复杂的过程,为监控、预警提供决策支持。

最具代表性的是promthues+grafana

没用过也没有关系,打开电脑,按 CTRL+ALT+DEL 呼出任务管理器,看看下面这个熟悉的界面,它也是一个非常具有代表性的度量系统。

监控指标能给我们解决什么问题_第1张图片

在总体上,度量可以分为客户端的指标收集、服务端的存储查询以及终端的监控预警三个相对独立的过程,每个过程在系统中一般也会设置对应的组件来实现。

那么现在呢,你不妨先来看一下我在后面举例时会用到的 Prometheus 组件流程图,图中 Prometheus Server 左边的部分都属于客户端过程,而右边的部分就属于终端过程。

监控指标能给我们解决什么问题_第2张图片

虽然说Prometheus在度量领域的统治力,暂时还不如日志领域中 Elastic Stack 的统治地位那么稳固,但在云原生时代里,它基本已经算得上是事实标准了。所以接下来,我就主要以 Prometheus 为例,给你介绍这三部分组件的总体思路、大致内容与理论标准。

指标收集

我们先来了解下客户端指标收集部分的核心思想。这一部分主要是解决两个问题:“如何定义指标”以及“如何将这些指标告诉服务端”。

如何定义指标?

首先我们来聊聊“如何定义指标”这个问题。乍一看你可能会觉得它应该是与目标系统密切相关的,必须根据实际情况才能讨论,但其实并不绝对。

所有通用的度量系统都是面向指标的数据类型来设计的,现在我就来一一给你解读下:

  • 计数度量器(Counter):这是最好理解也是最常用的指标形式,计数器就是对有相同量纲、可加减数值的合计量。比如业务指标像销售额、货物库存量、职工人数等;技术指标像服务调用次数、网站访问人数等,它们都属于计数器指标。
  • 瞬态度量器(Gauge):瞬态度量器比计数器更简单,它就表示某个指标在某个时点的数值,连加减统计都不需要。比如当前 Java 虚拟机堆内存的使用量,这就是一个瞬态度量器;再比如,网站访问人数是计数器,而网站在线人数则是瞬态度量器。
  • 吞吐率度量器(Meter):顾名思义,它是用于统计单位时间的吞吐量,即单位时间内某个事件的发生次数。比如在交易系统中,常以 TPS 衡量事务吞吐率,即每秒发生了多少笔事务交易;再比如,港口的货运吞吐率常以“吨 / 每天”为单位计算,10 万吨 / 天的港口通常要比 1 万吨 / 天的港口的货运规模更大。
  • 直方图度量器(Histogram):直方图就是指常见的二维统计图,它的两个坐标分别是统计样本和该样本对应的某个属性的度量,以长条图的形式记录具体数值。比如经济报告中,要衡量某个地区历年的 GDP 变化情况,常会以 GDP 为纵坐标、时间为横坐标构成直方图来呈现。
  • 采样点分位图度量器(Quantile Summary):分位图是统计学中通过比较各分位数的分布情况的工具,主要用来验证实际值与理论值的差距,评估理论值与实际值之间的拟合度。比如,我们说“高考成绩一般符合正态分布”,这句话的意思就是:高考成绩高低分的人数都比较少,中等成绩的比较多,按不同分数段来统计人数,得出的统计结果一般能够与正态分布的曲线较好地拟合。
  • 除了以上常见的度量器之外,还有 Timer、Set、Fast Compass、Cluster Histogram 等其他各种度量器,采用不同的度量系统,支持度量器类型的范围肯定会有所差别,比如 Prometheus 就支持了上面提到的五种度量器中的 Counter、Gauge、Histogram 和 Summary 四种。

如何将这些指标告诉服务端?

它通常有两种解决方案:拉取式采集(Pull-Based Metrics Collection)和推送式采集(Push-Based Metrics Collection)。

所谓 Pull 是指度量系统主动从目标系统中拉取指标;相对地,Push 就是由目标系统主动向度量系统推送指标。

不过一般来说,度量系统只会支持其中一种指标采集方式,这是因为度量系统的网络连接数量,以及对应的线程或者协程数可能非常庞大,如何采集指标将直接影响到整个度量系统的架构设计。

然而Prometheus 在基于 Pull 架构的同时,还能够有限度地兼容 Push 式采集,这是为啥呢?原因是它有 Push Gateway 的存在。

如下图所示,这是一个位于 Prometheus Server 外部的相对独立的中介模块,它会把外部推送来的指标放到 Push Gateway 中暂存,然后再等候 Prometheus Server 从 Push Gateway 中去拉取。

监控指标能给我们解决什么问题_第3张图片

Prometheus 设计 Push Gateway 的本意是为了解决 Pull 的一些固有缺陷,比如目标系统位于内网,需要通过 NAT 访问外网,而外网的 Prometheus 是无法主动连接目标系统的,这就只能由目标系统主动推送数据;又比如某些小型短生命周期服务,可能还等不及 Prometheus 来拉取,服务就已经结束运行了,因此也只能由服务自己 Push 来保证度量的及时和准确。

而在由 Push 和 Pull 决定完该谁主动以后,另一个问题就是:指标应该通过怎样的网络访问协议、取数接口、数据结构来获取呢?

跟计算机科学中其他类似的问题一样,人们一贯的解决方向是“定义规范”,应该由行业组织和主流厂商一起协商出专门用于度量的协议,目标系统按照协议与度量系统交互。比如说,网络管理中的SNMP、Windows 硬件的WMI,以及第 41 讲中提到的 Java 的JMX都属于这种思路的产物。但是这里不适合,因为Promtheues度量面向的是广义上的信息系统,它横跨存储(日志、文件、数据库)、通讯(消息、网络)、中间件(HTTP 服务、API 服务),直到系统本身的业务指标,甚至还会包括度量系统本身(部署两个独立的 Prometheus 互相监控是很常见的)。

如此一来,既然没有了标准,有一些度量系统,比如老牌的 Zabbix 就选择同时支持了 SNMP、JMX、IPMI 等多种不同的度量协议。

而另一些以 Prometheus 为代表的度量系统就相对强硬,它们不支持任何一种协议,只允许通过 HTTP 访问度量端点这一种访问方式。如果目标提供了 HTTP 的度量端点(如 Kubernetes、Etcd 等本身就带有 Prometheus 的 Client Library)就直接访问,否则就需要一个专门的 Exporter 来充当媒介。

这里的 Exporter 是 Prometheus 提出的概念,它是目标应用的代表,它既可以独立运行,也可以与应用运行在同一个进程中,只要集成 Prometheus 的 Client Library 就可以了。(相当于加了这一个插件,就可以被prom拉数据)

Exporter 的作用就是以 HTTP 协议(Prometheus 在 2.0 版本之前支持过 Protocol Buffer,目前已不再支持)返回符合 Prometheus 格式要求的文本数据给 Prometheus 服务器。得益于 Prometheus 的良好社区生态,现在已经有大量、各种用途的 Exporter,让 Prometheus 的监控范围几乎能涵盖到所有用户关心的目标,绝大多数用户都只需要针对自己系统业务方面的度量指标编写 Exporter 即可。你可以参考下这里给出的表格:

监控指标能给我们解决什么问题_第4张图片

另外顺便一提,在前面我提到了一堆没有希望成为最终答案的协议,比如 SNMP、WMI 等等。不过现在一种名为OpenMetrics的度量规范正逐渐从 Prometheus 的数据格式中分离出来,有望成为监控数据格式的国际标准,在这里提一嘴Docker的,“容器运行时接口”(Container Runtime Interface,CRI)也是这样从Docker独立出来的,关于OpenMetrics最终结果究竟如何,要看 Prometheus 本身的发展情况,还有 OpenTelemetry 与 OpenMetrics 的关系如何协调。

存储查询

好,那么当指标从目标系统采集过来了之后,就应该存储在度量系统中,以便被后续的分析界面、监控预警所使用。

存储数据对于计算机软件来说其实是司空见惯的操作,但如果用传统关系数据库的思路来解决度量系统的存储,效果可能不会太理想。

我举个例子,假设你要建设一个中等规模、有着 200 个节点的微服务系统,每个节点要采集的存储、网络、中间件和业务等各种指标加一起,也按 200 个来计算,监控的频率如果按秒为单位的话,一天时间内就会产生超过 34 亿条记录,而对于这个结果你可能会感到非常意外:

因为在实际情况中,大多数这种 200 节点规模的系统,本身一天的生产数据都远到不了 34 亿条,那么建设度量系统,肯定不能让度量反倒成了业务系统的负担。可见,度量的存储是需要专门研究解决的问题。至于具体要如何解决,让我们先来观察一段 Prometheus 的真实度量数据吧:

{
  // 时间戳
  "timestamp": 1599117392,
  // 指标名称
  "metric": "total_website_visitors",
  // 标签组
  "tags": {
    "host": "icyfenix.cn",
    "job": "prometheus"
  },
  // 指标值
  "value": 10086
}

通过观察,我们可以发现这段度量数据的特征:每一个度量指标由时间戳、名称、值和一组标签构成,除了时间之外,指标不与任何其他因素相关。

当然,指标的数据总量固然是不小的,但它没有嵌套、没有关联、没有主外键,不必关心范式和事务,这些就都是可以针对性优化的地方。事实上,业界也早就有了专门针对该类型数据的数据库,即“时序数据库”(Time Series Database)。

我们应该注意到,存储数据库在写操作时,时序数据通常只是追加,很少删改或者根本不允许删改。因此,针对数据热点只集中在近期数据、多写少读、几乎不删改、数据只顺序追加等特点,时序数据库被允许可以做出很激进的存储、访问和保留策略(Retention Policies):

  • 以日志结构的合并树(Log Structured Merge Tree,LSM-Tree)代替传统关系型数据库中的B+Tree作为存储结构,LSM 适合的应用场景就是写多读少,且几乎不删改的数据。
  • 设置激进的数据保留策略,比如根据过期时间(TTL),自动删除相关数据以节省存储空间,同时提高查询性能。对于普通的数据库来说,数据会存储一段时间后被自动删除的这个做法,可以说是不可想象的。
  • 对数据进行再采样(Resampling)以节省空间,比如最近几天的数据可能需要精确到秒,而查询一个月前的数据只需要精确到天,查询一年前的数据只要精确到周就够了,这样将数据重新采样汇总,就极大地节省了存储空间。

而除此之外,时序数据库中甚至还有一种并不罕见却更加极端的形式,叫做轮替型数据库(Round Robin Database,RRD),它是以环形缓冲(在“服务端缓存”一节介绍过)的思路实现,只能存储固定数量的最新数据,超期或超过容量的数据就会被轮替覆盖,因此它也有着固定的数据库容量,却能接受无限量的数据输入。

所以,Prometheus 服务端自己就内置了一个强大的时序数据库实现,我说它“强大”并不是客气,在DB-Engines中近几年它的排名就在不断提升,目前已经跃居时序数据库排行榜的前三。

这个时序数据库提供了一个名为 PromQL 的数据查询语言,能对时序数据进行丰富的查询、聚合以及逻辑运算。

当然了,某些时序库(如排名第一的InfluxDB)也会提供类 SQL 风格的查询,但 PromQL 不是,它是一套完全由 Prometheus 自己定制的数据查询DSL,写起来的风格有点像带运算与函数支持的 CSS 选择器。比如,我要查找网站 icyfenix.cn 的访问人数的话,会是如下写法:

// 查询命令:
total_website_visitors{host=“icyfenix.cn”}

// 返回结果:
total_website_visitors{host=“icyfenix.cn”,job="prometheus"}=(10086)

这样,通过 PromQL 就可以轻易实现指标之间的运算、聚合、统计等操作,在查询界面中也往往需要通过 PromQL 计算多种指标的统计结果,才能满足监控的需要,语法方面的细节我就不详细展开了,具体你可以参考Prometheus 的文档手册。

好,接下来我们继续探讨聚合度量的第三个过程:终端的监控预警。

监控预警

Prometheus 提供了专门用于预警的 Alert Manager,我们将 Alert Manager 与 Prometheus 关联后,可以设置某个指标在多长时间内、达到何种条件就会触发预警状态,在触发预警后,Alert Manager 就会根据路由中配置的接收器,比如邮件接收器、Slack 接收器、微信接收器,或者更通用的WebHook接收器等来自动通知我们。

小结

传统监控和可观测性之间的关键区别在于:可观测性是系统或服务内在的固有属性,而不是在系统之外对系统所做出的额外增强,后者是传统监控的处理思路。

除此之外,构建具有可观测性的服务,也是构建健壮服务不可缺少的属性,这是分布式系统架构师的职责。那么作为服务开发者和设计者,我们应该在其建设期间,就要设想控制系统会发出哪些信号、如何接收和存储这些信号,以及如何使用它们,以确保在用户能在受到影响之前了解问题、能使用度量数据来更好地了解系统的健康状况和状态。

你可能感兴趣的:(java,大数据,开发语言)