关于腾讯云:Prometheus-Metrics-设计的最佳实践和应用实例看这篇够了

8次阅读

共计 9718 个字符,预计需要花费 25 分钟才能阅读完成。

Prometheus 是一个开源的监控解决方案,部署简略易使用,难点在于如何设计合乎特定需要的 Metrics 去全面高效地反映零碎实时状态,以助力故障问题的发现与定位。本文即基于最佳实际的 Metrics 设计办法,联合具体的场景实例——TKE 的网络组件 IPAMD 的外部监控,以集体实践经验谈一谈如何设计和实现适宜的、可能更好反映零碎实时状态的监控指标(Metrics)。该篇内容适于 Prometheus 或相干监控零碎的初学者(可无任何根底理解),以及近期有 Prometheus 监控计划搭建和保护需要的零碎开发管理者。通过这篇文章,能够加深对 Prometheus Metrics 的了解,并能针对实际的监控场景提出更好的指标(Metrics)设计。

1 引言

Prometheus 是一个开源的监控解决方案,它可能提供监控指标数据的采集、存储、查问以及监控告警等性能。作为云原生基金会 (CNCF) 的毕业我的项目,Prometheus 曾经在云原生畛域失去了大范畴的利用,并逐步成为了业界最风行的监控解决方案之一。

Prometheus 的部署和应用能够说是简略易上手,然而如何针对实际的问题和需要设计合适的 Metrics 却并不是那么间接可行,反而须要优先解决裸露进去的诸多不确定问题,比方何时选用 Vector,如何设计合适的 buckets,Summary 和 Histogram 指标类型的取舍等。然而,要想无效助力故障及问题的发现与定位,必须要有一个正当无效的 Metrics 去全面高效地反映零碎实时状态。

本文将介绍基于最佳实际的 Metrics 设计办法,并联合具体的场景实例——TKE 的网络组件 IPAMD 的外部监控,以集体实践经验谈一谈如何设计和实现适宜的、可能更好反映零碎实时状态的监控指标(Metrics)。

本文之后的第 2 节将对 Prometheus 的 Metrics 做简略的介绍,对此已有理解的读者可跳过。之后第 3 节将介绍 Metrics 设计的最佳实际。第 4 节将联合具体的实例利用相干设计办法。第 5 节将介绍 Golang 上指标收集的实现计划。

2 Prometheus Metrics Type 简介

Prometheus Metrics 是整个监控零碎的外围,所有的监控指标数据都由其记录。Prometheus 中,所有 Metrics 皆为时序数据,并以名字作辨别,即每个指标收集到的样本数据蕴含至多三个维度的信息:名字、时刻和数值。

而 Prometheus Metrics 有四种根本的 type:

  • Counter: 只增不减的单变量
  • Gauge:可增可减的单变量
  • Histogram:多桶统计的多变量
  • Summary:聚合统计的多变量

此外,Prometheus Metrics 中有一种将样本数据以标签(Label)为维度作切分的数据类型,称为向量(Vector)。四种根本类型也都有其 Vector 类型:

  • CounterVec
  • GaugeVec
  • HistogramVec
  • SummaryVec

Vector 相当于一组同名同类型的 Metrics,以 Label 做辨别。Label 能够有多个,Prometheus 理论会为每个 Label 组合创立一个 Metric。Vector 类型记录数据时需先打 Label 能力调用 Metrics 的办法记录数据。

如对于 HTTP 申请提早这一指标,因为 HTTP 申请可在多个地区的服务器解决,且具备不同的办法,于是,可定义名为 http_request_latency_seconds 的 SummaryVec,标签有 regionmethod,以此示意不同地区服务器的不同申请办法的申请提早。

以下将对每个类型做具体的介绍。

2.1 Counter

  • 定义:是枯燥递增的计数器,重启时重置为 0,其余时候只能减少。
  • 办法:

    type Counter interface {Metric  Collector  // 自增 1  Inc()  // 把给定值退出到计数器中. 若值小于 0 会 panic  Add(float64)}
  • 常测量对象:
    • 申请的数量
    • 工作实现的数量
    • 函数调用次数
    • 谬误产生次数

2.2 Gauge

  • 定义:示意一个可增可减的数字变量,初值为 0
  • 办法:

    type Gauge interface {Metric  Collector  Set(float64)    // 间接设置成给定值  Inc()   // 自增 1  Dec()   // 自减 1  Add(float64)     // 减少给定值,可为负  Sub(float64)    // 缩小给定值,可为负  // SetToCurrentTime 将 Gauge 设置成以后的 Unix 工夫戳  SetToCurrentTime()}
  • 常测量对象:
    • 温度
    • 内存用量
    • 并发申请数

2.3 Histogram

  • 定义:Histogram 会对观测数据取样,而后将观测数据放入 有数值上界 的桶中,并记录 各桶中数据的个数,所有数据的个数和数据数值总和。
  • 办法:

    type Histogram interface {Metric  Collector  // Observe 将一个观测到的样本数据退出 Histogram 中,并更新相干信息  Observe(float64)}
  • 常测量对象:
    • 申请时延
    • 回复长度
    • … 各种有样本数据
  • 具体实现:Histogram 会依据观测的样本生成如下数据:

    inf 表无穷值,a1,a2,… 是枯燥递增的数值序列。

    • [basename]_count: 数据的个数,类型为 counter
    • [basename]_sum: 数据的加和,类型为 counter
    • [basename]_bucket{le=a1}: 处于 [-inf,a1] 的数值个数
    • [basename]_bucket{le=a2}: 处于 [-inf,a2] 的数值个数
    • [basename]_bucket{le=<+inf>}:处于 [-inf,+inf] 的数值个数,prometheus 默认额定生成,无需用户定义
  • Histogram 能够计算样本数据的百分位数,其计算原理为:通过找特定的百分位数值在哪个桶中,而后再通过插值失去后果。比方目前有两个桶,别离存储了 [-inf, 1] 和[-inf, 2]的数据。而后当初有 20% 的数据在 [-inf, 1] 的桶,100% 的数据在 [-inf, 2] 的桶。那么,50% 分位数就应该在 [1, 2] 的区间中,且处于(50%-20%) / (100%-20%) = 30% / 80% = 37.5% 的地位处。Prometheus 计算时假如区间中数据是均匀分布,因而间接通过线性插值能够失去 (2-1)*3/8+1 = 1.375.

2.4 Summary

  • 定义:Summary 与 Histogram 相似,会对观测数据进行取样,失去数据的个数和总和。此外,还会取一个滑动窗口,计算窗口内样本数据的分位数。
  • 办法:

    type Summary interface {Metric  Collector  // Observe 将一个观测到的样本数据退出 Summary 中,并更新相干信息  Observe(float64)}
  • 常测量对象:
    • 申请时延
    • 回复长度
    • … 各种有样本数据
  • 具体实现:Summary 齐全是在 client 端聚合数据,每次调用 obeserve 会计算出如下数据:
    • [basename]_count: 数据的个数,类型为 counter
    • [basename]_sum: 数据的加和,类型为 counter
    • [basename]{quantile=0.5}: 滑动窗口内 50% 分位数值
    • [basename]{quantile=0.9}: 滑动窗口内 90% 分位数值
    • [basename]{quantile=0.99}: 滑动窗口内 99% 分位数值

理论分位数值可依据需要制订,且是对每一个 Label 组合做聚合。

2.5 Histogram 和 Summary 简略比照

能够看出,Histogram 和 Summary 类型测量的对象是比拟靠近的,但依据其实现形式和其自身的特点,在性能消耗、实用场景等方面具备肯定差异,本文总结如下:

3 Metrics 设计的最佳实际

3.1 如何确定须要测量的对象

在具体设计 Metrics 之前,首先须要明确须要测量的对象。须要测量的对象应该根据具体的问题背景、需要和需监控的零碎自身来确定。

思路 1:从需要登程

Google 针对大量分布式监控的经验总结出四个监控的黄金指标,这四个指标对于一般性的监控测量对象都具备较好的参考意义。这四个指标别离为:

  • 提早:服务申请的工夫。
  • 通信量:监控以后零碎的流量,用于掂量服务的容量需要。
  • 谬误:监控以后零碎所有产生的谬误申请,掂量以后零碎谬误产生的速率。
  • 饱和度:掂量以后服务的饱和度。次要强调最能影响服务状态的受限制的资源。例如,如果零碎次要受内存影响,那就次要关注零碎的内存状态。

而笔者认为,以上四种指标,其实是为了满足四个监控需要:

  • 反映用户体验,掂量系统核心性能。如:在线零碎的时延,作业计算零碎的作业实现工夫等。
  • 反映零碎的服务量。如:申请数,收回和接管的网络包大小等。
  • 帮忙发现和定位故障和问题。如:谬误计数、调用失败率等。
  • 反映零碎的饱和度和负载。如:零碎占用的内存、作业队列的长度等。

除了以上惯例需要,还可依据具体的问题场景,为了排除和发现以前呈现过或可能呈现的问题,确定相应的测量对象。比方,零碎须要常常调用的一个库的接口可能耗时较长,或偶有失败,可制订 Metrics 以测量这个接口的时延和失败数。

思路 2:从需监控的零碎登程

另一方面,为了满足相应的需要,不同零碎须要观测的测量对象也是不同的。在 官网文档 的最佳实际中,将须要监控的利用分为了三类:

  • 线上服务零碎(Online-serving systems):需对申请做即时的响应,申请发起者会期待响应。如 web 服务器。
  • 线下计算零碎(Offline processing):申请发起者不会期待响应,申请的作业通常会耗时较长。如批处理计算框架 Spark 等。
  • 批处理作业(Batch jobs):这类利用通常为一次性的,不会始终运行,运行实现后便会完结运行。如数据分析的 MapReduce 作业。

对于每一类利用其通常状况下测量的对象是不太一样的。其总结如下:

  • 线上服务零碎:次要有申请、出错的数量,申请的时延等。
  • 线下计算零碎:最初开始解决作业的工夫,目前正在解决作业的数量,收回了多少 items,作业队列的长度等。
  • 批处理作业:最初胜利执行的时刻,每个次要 stage 的执行工夫,总的耗时,解决的记录数量等。

除了零碎自身,有时还需监控子系统:

  • 应用的库(Libraries): 调用次数,胜利数,出错数,调用的时延。
  • 日志(Logging):计数每一条写入的日志,从而可找到每条日志产生的频率和工夫。
  • Failures: 谬误计数。
  • 线程池:排队的申请数,正在应用的线程数,总线程数,耗时,正在解决的工作数等。
  • 缓存:申请数,命中数,总时延等。

最初的测量对象的确定应联合以上两点思路确定。

3.2 如何选用 Vector

选用 Vec 的准则:

  • 数据类型相似但资源类型、收集地点等不同
  • Vec 内数据单位对立

例子:

  • 不同资源对象的申请提早
  • 不同地区服务器的申请提早
  • 不同 http 申请谬误的计数

此外,官网文档 中倡议,对于一个资源对象的不同操作,如 Read/Write、Send/Receive,应采纳不同的 Metric 去记录,而不要放在一个 Metric 里。起因是监控时个别不会对这两者做聚合,而是别离去观测。

不过对于 request 的测量,通常是以 Label 做辨别不同的 action。

3.3 如何确定 Label

依据 3.2,常见 Label 的抉择有:

  • resource
  • region
  • type

确定 Label 的一个重要准则是:同一维度 Label 的数据是可均匀和可加和的,也即单位要对立。如风扇的风速和电压就不能放在一个 Label 里。

此外,不倡议下列做法:

my_metric{label=a} 1my_metric{label=b} 6my_metric{label=total} 7

即在 Label 中同时统计了分和总的数据,倡议采纳 PromQL 在服务器端聚合失去总和的后果。或者用另外的 Metric 去测量总的数据。

3.4 如何命名 Metrics 和 Label

好的命名可能见名知义,因而命名也是良好设计的一环。

Metric 的命名:

  • 须要合乎 pattern: a-zA-Z*:*
  • 应该蕴含一个单词作为前缀,表明这个 Metric 所属的域。如:
    • prometheus_notifications_total
    • process_cpu_seconds_total
    • ipamd_request_latency
  • 应该蕴含一个单位的单位作为后缀,表明这个 Metric 的单位。如:
    • http_request_duration_seconds
    • node_memory_usage_bytes
    • http_requests_total (for a unit-less accumulating count)
  • 逻辑上与被测量的变量含意雷同。
  • 尽量应用根本单位,如 seconds,bytes。而不是 Milliseconds, megabytes。

Label 的命名:

  • 根据抉择的维度命名,如:
    • region: shenzhen/guangzhou/beijing
    • owner: user1/user2/user3
    • stage: extract/transform/load

3.5 如何设计合适的 Buckets

依据前述 histogram 的统计原理可知,合适的 buckets 能使 histogram 的百分位数计算更加精确。

现实状况下,桶会使得数据分布呈阶梯状,即各桶区间内数据个数大致相同。如图 1 所示,是自己在理论场景下配置的 buckets 数据直方图,y 轴为 buckets 内的数据个数,x 轴是各 buckets,能够看出其近似成阶梯状。这种状况下,以后桶个数下对数据的分辨率最大,各百分位数计算的准确率较高。

图 1 较为理想的桶数据分布

而依据笔者实践经验,为了达成以上指标,buckets 的设计可听从如下教训:

  • 须要晓得数据的大抵散布,若当时不晓得可先用默认桶({.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10})或 2 倍数桶({1,2,4,8…})察看数据分布再调整 buckets。
  • 数据分布较密处桶距离制订的较窄一些,散布稠密处可制订的较宽一些。
  • 对于少数时延数据,个别具备长尾的个性,较合适用指数模式的桶(ExponentialBuckets)。
  • 初始桶上界个别笼罩 10% 左右的数据,若不关注头部数据也能够让初始上界更大一些。
  • 若为了更精确计算特定百分位数,如 90%,可在 90% 的数据处加密散布桶,即缩小桶的距离。

4 实例:TKE-ENI-IPAMD Metrics 设计与布局

4.1 组件简介

该组件用于反对腾讯云 TKE 的策略路由网络计划。在这一网络计划中,每个 pod 的 IP 都是 VPC 子网的一个 IP,且绑定到了所在节点的弹性网卡上,通过策略路由连通网络,并且使得容器能够反对腾讯云的 VPC 的所有个性。

其中,在 2.0.0 版本以前,tke-eni-ipamd 组件是一个 IP 调配治理的 GRPC Server,其主要职责为:

  • cni IP 真正调配 / 删除的 GRPC Server,调配 / 开释 IP 会调用腾讯云弹性网卡接口执行相应的 IP 绑定 / 解绑操作
  • Node 控制器(用于给 Node 绑定 / 解绑弹性网卡)
  • Stateulfset 控制器(用于给 Statefulset 预留 IP 资源)

其工作原理和流程如图 2 所示:

图 2 tke-eni-ipamd(v2.0.0-) 工作原理和流程

4.2 IPAMD 的应用场景和咱们的要求

背景:

  • ip 调配 / 开释对时延比拟敏感,为了不便确定 ip 调配 / 开释过程中性能瓶颈是由咱们本身代码造成的还是底层模块造成的(如 ipamd 调用的 vpc 接口等)。同时也不便对咱们的代码和推动底层模块的性能优化。
  • ipamd 运行过程中可能会呈现故障等问题,为了及时发现故障,定位问题,也须要有外部监控。

需要:

  • 须要可能统计 ip 调配和开释各个阶段的时延,以确定性能瓶颈
  • 须要晓得以后的并发申请数,以确定 IPAMD 负载
  • vpc 接口 ip 调配 / 开释,弹性网卡创立 / 绑定 / 解绑 / 开释耗时比拟长,并且常常有失败状况。须要可能统计这些接口的时延和调用成功率,以定位性能瓶颈。
  • node controller,statefulset controller 进行 sync 阶段会有一系列流程,心愿能分明次要流程耗时,不便定位瓶颈
  • 弹性网卡的创立 / 删除等过程中容易产生脏数据,须要可能统计脏数据的个数,以发现脏数据问题。
  • 须要有较强的实时性,可能分明的看到最近(~ 分钟级别)零碎的运行状态

咱们的场景:

  • ipamd 是部署在每个用户集群中的一个组件
  • 每个用户集群内有 prometheus server 做聚合,而后每个 region 也有 server 去拉取数据

4.3 总体设计

因而,须要以下几类 Metric:

  • ip alloc/free 各阶段时延
  • 根本运行信息:申请并发数、内存用量、goroutine 数,线程数
  • vpc 接口时延
  • vpc 接口调用成功率
  • controller sync 时延
  • 脏数据计数

4.4 Histogram vs. Summary

时延可抉择 Histogram 或 Summary 进行测量,如何抉择?

基于 2.5 节的两者比照,有如下剖析:

Summary:

  • 长处:
    1. 可能十分精确的计算百分位数
    2. 不须要提前晓得数据的散布
  • 毛病:
    1. 灵活性有余,实时性须要通过 maxAge 来保障,写死了后灵活性就不太够(比方想晓得更长维度的百分位数)
    2. 在 client 端曾经做了聚合,即在各个用户集群的 ipamd 中曾经聚合了,咱们如果须要察看全副 user 下的百分位数数据是不行的(只能看均值)
    3. 用户集群的 ipamd 的调用频率可能很低(如小集群或者稳固集群),这种状况下 client 端聚合计算百分位数值失去意义(数据太少不稳固),如果把 maxAge 增大则失去实时性

Histogram:

  • 长处:
    1. 兼具灵活性和实时性
    2. 能够灵便的聚合数据,察看各个尺度和维度下的数据
  • 毛病:
    1. 须要提前晓得数据的大抵散布,并以此设计出适合而精确的桶序列
    2. 难以通过 Label 串联多种 Metrics,因为各个 Metrics 的数据分布可能差别较大,如果都只用一种桶序列的话会导致百分位数计算差别较大

Summary 的毛病过于致命,难以回避。Histogram 的毛病能够通过减少工作量(即通过测试环境中的试验来确定各 Metrics 的大抵散布)和减少 Metrics(不必 Label 辨别)来较好解决。

所以偏向于应用 Histogram。

4.5 Metrics 布局示例

具体的 Metrics 布局内容较多,这里选取了一些代表性的样例,列举如下:

注 1:DefBuckets 指默认桶({.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10})。

注 2:以上 buckets 继续微调中。

5 指标收集的 Golang 实现计划

5.1 总体实现思路

  • 利用 prometheus 的 golang client 实现自定义的 exporter(包含自定义的 Metrics),并嵌入到 ipamd 代码中,以收集数据
  • 所有的 Metrics 作为 Metrics 包的内部变量可供其余包应用,调用测量方法
  • 自定义 exporter 参考 prometheus client golang example
  • 将收集到的数据通过 http server 裸露进去

5.2 Metrics 收集计划

计划 1:非侵入式装璜器模式

样例: kubelet/kuberuntime/instrumented_services.go

type instrumentedRuntimeService struct {service internalapi.RuntimeService}func recordOperation(operation string, start time.Time) {metrics.RuntimeOperations.WithLabelValues(operation).Inc()    metrics.DeprecatedRuntimeOperations.WithLabelValues(operation).Inc()    metrics.RuntimeOperationsDuration.WithLabelValues(operation).Observe(metrics.SinceInSeconds(start))    metrics.DeprecatedRuntimeOperationsLatency.WithLabelValues(operation).Observe(metrics.SinceInMicroseconds(start))}func (in instrumentedRuntimeService) Status() (*runtimeapi.RuntimeStatus, error) {const operation = "status"    defer recordOperation(operation, time.Now())    out, err := in.service.Status()    recordError(operation, err)    return out, err}

长处:

  • 下层调用函数处简直不必批改,只需批改调用的实例
  • 形象较好,非侵入式设计,代码耦合度低

毛病:

  • 需独自封装每个调用函数,复用度低
  • 无奈封装外部函数,只能实用于测量对外服务函数的数据

计划 2:defer 函数收集

样例:

func test() (retErr error){defer func(){metrics.LatencySeconds.Observe(...)    }()    ...    func body    ...}

长处:

  • 下层调用函数处齐全不必批改
  • 实用于所有函数的测量

毛病:

  • 有点滥用 defer
  • 侵入式设计,具备肯定的耦合度

5.3 目前 IPAMD 的指标收集实现计划

  • 时延统计:通过 golang 的 time 模块计时,在函数中嵌入 time.Now 和并在其后 defer time.Since 来统计。
  • 调用成功率统计:调用次数在接口函数里间接用 counter 进行统计,失败次数在 defer 里获取命名返回值统计,最初在 prometheus server 端聚合的时候通过 PromQL 利用这两个数据计算出调用成功率。
  • 并发申请数的统计:在最外层的 AddPodIP 和 DelPodIP 中,在函数中和 defer func 中别离调用 Inc 和 Dec。

6 总结

本文介绍了 Prometheus Metrics 及最佳实际的 Metrics 设计和收集实现办法,并在具体的监控场景—— TKE 的网络组件 IPAMD 的外部监控中利用了相干办法。

具体而言,本文基于最佳实际,答复了 Prometheus Metrics 设计过程中的若干问题:

  • 如何确定须要测量的对象:根据需要 (反映用户体验、服务量、饱和度和帮忙发现问题等) 和需监控的具体零碎。
  • 何时选用 Vec:数据类型相似但资源类型、收集地点等不同,数据单位对立。
  • 如何确定 Label:可均匀和可加和的,单位要对立;总和数据另外计。
  • 如何命名 Metrics 和 Label:见名知义,应蕴含监控的零碎名 / 模块名,指标名,单位等信息。
  • 如何设计合适的 Buckets:根据数据分布制订,密集局部桶区间较窄,总体桶散布尽量靠近阶梯状。
  • 如何取舍 Histogram 和 Summary:Histogram 计算误差大,但灵活性较强,实用客户端监控、或组件在零碎中较多、或不太关怀准确的百分位数值的场景;Summary 计算准确,但灵活性较差,实用服务端监控、或组件在零碎中惟一或只有个位数、或须要晓得较精确的百分位数值 (如性能优化场景) 的场景。

此外,Metrics 设计并不是欲速不达的,需根据具体的需要的变动进行重复迭代。比方需新增 Metrics 去发现定位可能呈现的新问题和故障,再比方 Buckets 的设计也须要变动来适应测量数据分布产生的变动,从而取得更准确的百分位数测量值。

参考资料

  1. Prometheus 官网文档:https://prometheus.io/docs/in…
  2. Go client library:https://github.com/prometheus…

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

正文完
 0