整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

云原生监控事实标准—Prometheus基本原理与开

云原生监控事实标准—Prometheus基本原理与开发指南

读:本文由梯度科技云管研发部高级工程师周宇明撰写,共分为7章,紧密围绕Prometheus的基本原理与开发指南展开介绍:

1.监控系统概述

1.1.监控的作用

为了构建稳定性保障体系,核心就是在干一件事:减少故障。

减少故障有两个层面的意思,一个是做好常态预防,不让故障发生;另一个是如果故障发生,要能尽快止损,减少故障时长,减小故障影响范围。监控的典型作用就是帮助我们发现及定位故障。

监控的其他作用:日常巡检、性能调优的数据佐证、提前发现一些不合理的配置。

之所以能做到这些,是因为所有优秀的软件,都内置了监控数据的暴露方法,让用户可以对其进行观测,了解其健康状况:比如各类开源组件,有的是直接暴露了 Prometheus metrics 接口,有的是暴露了 HTTP JSON 接口,有的是通过 JMX 暴露监控数据,有的则需要连上去执行命令。另外,所有软件都可以使用日志的方式来暴露健康状况。

因此,可被监控和观测,也是我们开发软件时必须考虑的一环。

1.2.监控架构分类

  • Metrics(指标)

定义:可进行聚合计算的原子型数据,通常通过多个标签值来确定指标唯一性。

特点:指标数据仅记录时间戳和对应的指标数值,通常存储在时间序列数据库中(TSDB),存储成本低,可用于渲染趋势图或柱状图,可灵活配置告警规则,对故障进行快速发现和响应;但是不适合用于定位故障原因。

实现方案:Zabbix、Open-Falcon、Prometheus

  • Logging(日志)

定义:离散事件,是系统运行时发生的一个个事件的记录。

特点:日志数据可以记录详细的信息(请求响应参数、自定义文字描述、异常信息、时间戳等),一般用于排查具体问题;日志通常存储在文件中,数据非结构化,存储成本高,不适合作为监控数据的来源。

实现方案:ELK、Loki

  • Tracing(链路)

定义:基于特定请求作用域下的所有调用信息。

特点:一般需要依赖第三方存储,在微服务中一般有多个调用信息,如从网关开始,A服务调用B服务,调用数据库、缓存等。在链路系统中,需要清楚展现某条调用链中从主调方到被调方内部所有的调用信息。不仅有利于梳理接口及服务间调用的关系,还有助于排查慢请求或故障产生的原因。

实现方案:jaeger、zipkin、Skywalking

  • 指标监控发展史Zabbix

企业级的开源解决方案,擅长设备、网络、中间件的监控。

优点:

  • 平台兼容性好,可运行在 Windows、Linux、Solaris、AIX、OS X等平台上;
  • 架构简单,易于维护、备份。

缺点:

  • 使用数据库存储,无法水平扩展,容量有限;
  • 面向资产管理的逻辑,使得监控指标的数据结构固化,没有灵活的标签设计,无法适应云原生架构下动态多变的环境。Open-Falcon

Open-Falcon 最初来自小米,14 年开源,当时小米有 3 套 Zabbix,1 套业务性能监控系统 perfcounter。Open-Falcon 的初衷是想做一套大一统的方案,来解决这个乱局。

优点:

  • 比Zabbix容量大得多,不仅可以处理设备、中间件层面监控,还可以处理应用层面监控;
  • Go语言开发,易于二次开发。

缺点:

  • 组件拆分比较散,部署相对比较麻烦;
  • 生态不够庞大,开源软件的治理架构不够优秀。Prometheus

Prometheus 的设计思路来自Borgmon,就像 Borgmon 是为 Borg 而生的,而 Prometheus 就是为 Kubernetes 而生的。提供了多种服务发现机制,大幅简化了 Kubernetes 的监控。

Prometheus2.0版本开始,重新设计了时序库,性能和可靠性都大幅提升。

优点:

  • 对 Kubernetes 支持很好,Prometheus 是云原生架构下监控的标配;
  • 生态庞大,有各种各样的 Exporter,支持各种各样的时序库作为后端的备用存储,也有很好的支持多种不同语言的 SDK,供业务代码嵌入埋点。

缺点:

  • 设置数据采集和告警策略需要修改配置文件,协同起来比较麻烦。
  • Exporter 参差不齐,通常是一个监控目标一个 Exporter,管理成本较高。指标监控典型架构

  • 采集器

有两种典型的部署方式,一种是跟随监控对象部署,比如所有的机器上都部署一个采集器,采集机器的 CPU、内存、硬盘、IO、网络相关的指标;另一种是远程探针式,比如选取一个中心机器做探针,同时探测很多个机器的 PING 连通性,或者连到很多 MySQL 实例上去,执行命令采集数据。

Telegraf:

InfluxData 公司的产品,主要配合 InfluxDB 使用。Telegraf 也可以把监控数据推给 Prometheus存储;

Telegraf 是指标领域的 All-In-One 采集器,支持各种采集插件,只需要使用这一个采集器,就能解决绝大部分采集需求;

Telegraf 采集的很多数据都是字符串类型,但如果把这类数据推给 Prometheus 生态的时序库,比如 VictoriaMetrics、M3DB、Thanos 等,它就会报错。

Exporter

Exporter是专门用于Prometheus 生态的采集器,但是比较零散,每个采集目标都有对应的 Exporter 组件,比如 MySQL 有 mysqld_exporter,Redis 有 redis_exporter,JVM 有 jmx_exporter。

Exporter 的核心逻辑,就是去这些监控对象里采集数据,然后暴露为 Prometheus 协议的监控数据。比如 mysqld_exporter,就是连上 MySQL,执行一些类似于 show global status 、show global variables 、show slave status 这样的命令,拿到输出,再转换为 Prometheus 协议的数据;

很多中间件都内置支持了 Prometheus,直接通过自身的 /metrics 接口暴露监控数据,不用再单独伴生 Exporter;比如 Kubernetes 中的各类组件,比如 etcd,还有新版本的 ZooKeeper、 RabbitMQ;

不管是Exporter还是支持Prometheus协议的各类组件,都是提供 HTTP 接口(通常是 /metrics )来暴露监控数据,让监控系统来拉,这叫做 PULL 模型。

Grafana-Agent

Grafana 公司推出的一款 All-In-One 采集器,不但可以采集指标数据,也可以采集日志数据和链路数据。

如何快速集成各类采集能力的呢?Grafana-Agent 写了个框架,方便导入各类 Exporter,把各个 Exporter 当做 Lib 使用,常见的 Node-Exporter、Kafka-Exporter、Elasticsearch-Exporter、Mysqld-Exporter 等,都已经完成了集成。对于默认没有集成进去的 Exporter,Grafana-Agent 也支持用 PULL 的方式去抓取其他 Exporter 的数据,然后再通过 Remote Write 的方式,将采集到的数据转发给服务端。

很多时候,一个采集器可能搞不定所有业务需求,使用一款主力采集器,辅以多款其他采集器是大多数公司的选择。

  • 时序库

Prometheus TSDB

Prometheus本地存储经历过多个迭代:V1.0(2012年)、V2.0(2015年)、V3.0(2017年)。最初借用第三方数据库LevelDB,1.0版本性能不高,每秒只能存储5W个样本;2.0版本借鉴了Facebook Gorilla压缩算法,将每个时序数据以单个文件方式保存,将性能提升到每秒存储8W个样本;2017年开始引入时序数据库的3.0版本,并成立了Prometheus TSDB开源项目,该版本在单机上提高到每秒存储百万个样本。

3.0版本保留了2.0版本高压缩比的分块保存方式,并将多个分块保存到一个文件中,通过创建一个索引文件避免产生大量的小文件;同时为了防止数据丢失,引入了WAL机制。

InfluxDB

InfluxDB 针对时序存储场景专门设计了存储引擎、数据结构、存取接口,国内使用范围比较广泛,可以和 Grafana、Telegraf 等良好整合,生态是非常完备的。

不过 InfluxDB 开源版本是单机的,没有开源集群版本。

M3DB

M3DB 是 Uber 的时序数据库,M3 在 Uber 抗住了 66 亿监控指标,这个量非常庞大。其主要包括4个组件:M3DB、M3 Coordinator、M3 Query、M3 Aggregator,我们当前产品中Prometheus的远程存储就是通过M3DB实现的。

  • 告警引擎

用户会配置数百甚至数千条告警规则,一些超大型的公司可能要配置数万条告警规则。每个规则里含有数据过滤条件、阈值、执行频率等,有一些配置丰富的监控系统,还支持配置规则生效时段、持续时长、留观时长等。

告警引擎通常有两种架构,一种是数据触发式,一种是周期轮询式。

数据触发式,是指服务端接收到监控数据之后,除了存储到时序库,还会转发一份数据给告警引擎,告警引擎每收到一条监控数据,就要判断是否关联了告警规则,做告警判断。因为监控数据量比较大,告警规则的量也可能比较大,所以告警引擎是会做分片部署的,这样的架构,即时性很好,但是想要做指标关联计算就很麻烦,因为不同的指标哈希后可能会落到不同的告警引擎实例。

周期轮询式,通常是一个规则一个协程,按照用户配置的执行频率,周期性查询判断即可,做指标关联计算就会很容易。像 Prometheus、Nightingale、Grafana 等,都是这样的架构。

生成事件之后,通常是交给一个单独的模块来做告警发送,这个模块负责事件聚合、收敛,根据不同的条件发送给不同的接收者和不同的通知媒介。

  • 数据展示

监控数据的可视化也是一个非常通用且重要的需求,业界做得最成功的是Grafana,采用插件式架构,可以支持不同类型的数据源,图表非常丰富,基本是开源领域的事实标准。

Prometheus入门

2.1.主要特点

  • PromQL多维度数据模型的灵活查询;
  • 定义了开放指标数据的标准,自定义探针(Exporter等);
  • Go语言编写,拥抱云原生;
  • 数据采集方式以pull为主、push为辅;
  • 二进制文件直接启动、也支持容器镜像化部署;
  • 支持多种语言客户端;
  • 支持本地和第三方远程存储、高效的存储;
  • 可扩展,功能分区+联邦集群;
  • 结合Grafana可以做到出色的可视化功能;
  • 精确告警:基于PromQL可以进行告警设置、预测等;另外还提供了分组、抑制、静默等功能防止告警风暴;
  • 支持动态发现机制:Kubernetes;

2.2. 局限性

  • 主要针对性能和可用性监控,不适用日志、事件、调用链等监控;
  • 关注近期发生的事,而不是跟踪数周或数月的数据,监控数据默认保留15天;
  • 本地存储有限,存储大量历史数据需要对接第三方远程存储;
  • 采用联邦集群方式时,没有提供统一的全局视图。

2.3. 架构剖析

  • Job/Exporter

prometheus监控探针,共收录有上千种Exporter,用于对第三方系统进行监控,方式是获取第三方系统的监控数据然后按照Prometheus的格式暴露出来;没有Exporter探针的第三方系统也可以自己定制开发。

不过Exporter种类繁多会导致维护压力大,也可以考虑用Influx Data公司开源的Telegraf统一进行管理。使用Telegraf集成Prometheus比单独使用Prometheus拥有更低的内存使用率和CPU使用率。

  • PushGateway

是支持临时性job主动推送指标的中间网关。

使用场景:临时/短作业、批处理作业、应用程序与Prometheus之间有防火墙或不在同一个网段;

不过该解决方案存在单点故障问题、必须使用PushGateway的API从推送网关中删除过期指标。

  • Service Discovery(服务发现机制)

可以使用Kubernetes的API获取容器信息的变化来动态更新监控对象;

  • Prometheus Server(核心监控服务)Retrieval(抓取)

从Job、Exporter、PushGateway3个组件中通过HTTP轮询的形式拉取指标数据;

  • Storage(存储)

本地存储:直接保存到本地磁盘,从性能上考虑,建议使用SSD且不要保存超过一个月的数据;

远程存储:适用于存储大量监控数据,支持的远程存储包括OpenTSDB、InfluxDB、M3DB、PostgreSQL等;需要配合中间层适配器进行转换;

  • PromQL(查询)

多维度数据模型的灵活查询。

  • Dashboard(可视化)

实际工作中使用Grafana,也可以调用HTTP API发送请求获取数据;

  • Alertmanager(告警引擎)

独立的告警组件,可以将多个AlertManager配置成集群,支持集群内多个实例间通信;

PromQL入门

  • 初识PromQL 时间序列

按照一定的时间间隔产生的一个个数据点,这些数据点按照时间戳和值的生成顺序存放,得到了向量(vector)。

每条时间序列是通过指标名称和一组标签集来命名的。

矩阵中每一个点都可以称之为一个样本(Sample),主要有3方面构成:

指标(Metrics):包括指标名称(__name__)和一组标签集名称;

时间戳(TimeStamp):默认精确到毫秒;

样本值(Value):默认使用64位浮点类型。

  • 指标

时间序列的指标可以基于Bigtable设计为Key-Value存储的方式:

Prometheus的Metrics可以有两种表现方式(指标名称只能由ASCII字符、数字、下划线、冒号组成,冒号用来表示用户自定义的记录规则):

分别对应的查询形式(以下两个查询语句等价):

  • 4大选择器匹配器相等匹配器(=):对于不存在的标签可以使用Label=""的形式查询不等匹配器(!=):相等匹配器的否定正则表达式匹配器(=~):前面或者后面加上".*"

所有PromQL语句必须包含至少一个有效表达式(至少一个不会匹配到空字符串的标签过滤器),因此,以下三种示例是非法的:

  • 正则表达式相反匹配器(!~):正则表达式匹配器的否定瞬时向量选择器

用于返回在指定时间戳之前查询到的最新样本的瞬时向量。

  • 区间向量选择器

高级应用:

  • 偏移量修改器

瞬时偏移向量

高级应用:

  • 4大指标类型 计数器(Counter)

只增不减,一般配合rate(统计时间区间内增长速率)、topk(统计top N的数据)、increase等函数使用;

increase(v range-vector)获取区间向量的第一个和最后一个样本并返回其增长量:

为什么increase函数算出来的值非33?真实计算公式:(360 - 327) / (1687922987 - 1687922882) * 120=37.71428571428571

irate(v range-vector)是针对长尾效应专门提供的用于计算区间向量的增长速率的函数,反应的是瞬时增长率,敏感度更高。长期趋势分析或告警中更推荐rate函数。

rate(v range-vector) 求取的是每秒变化率,也有数据外推的逻辑,increase 的结果除以 range-vector 的时间段的大小,就是 rate 的值。

rate(jvm_memory_used_bytes{id="PS Eden Space"}[1m]) 与 increase(jvm_memory_used_bytes{id="PS Eden Space"}[1m])/60.0 是等价的

  • 仪表盘(Gauge)

表示样本数据可任意增减的指标;实际更多用于求和、取平均值、最大值、最小值。

without可以让sum函数根据相同的标签进行求和,但是忽略掉without函数覆盖的标签;如上图,可以忽略掉id,只按照堆/非堆的区别进行内存空间求和。

  • 直方图(Histogram)

用于描述数据分布,最典型的应用场景就是监控延迟数据,计算 90 分位、99 分位的值。

有些服务访问量很高,每秒几百万次,如果要把所有请求的延迟数据全部拿到,排序之后再计算分位值,这个代价就太高了。使用 Histogram 类型,可以用较小的代价计算一个大概值。

Prometheus的Histogram类型计算原理:bucket桶排序+假定桶内数据均匀分布。

Histogram 这种做法性能有了巨大的提升,但是要同时计算成千上万个接口的分位值延迟数据,还是非常耗费资源的,甚至会造成服务端 OOM。

数据解析:http://ip:9090/metrics prometheus_http_request_duration_seconds

  • 汇总(Summary)

在客户端计算分位值,然后把计算之后的结果推给服务端存储,展示的时候直接查询即可。

Summary 的计算是在客户端计算的,也就意味着不是全局(整个服务)的分位值,分位值延迟数据是进程粒度的。

负载均衡会把请求均匀地打给后端的多个实例。一个实例内部计算的分位值,理论上和全局计算的分位值差别不会很大。另外,如果某个实例有故障,比如硬盘问题,导致落在这个实例的请求延迟大增,我们在实例粒度计算的延迟数据反而更容易发现问题

数据解析:http://ip:9090/metrics go_gc_duration_seconds

  • 13种聚合操作
  • without 和 by 用来保留不同维度的可选操作符,其余11个聚合操作都是用于瞬时向量,使用相同的分组逻辑:
  • sum
  • min
  • max
  • avg
  • count
  • count_values(对value进行计数)
  • stddev(标准差)
  • stdvar(标准差异)
  • bottomk(样本值最小k个元素)
  • topk(样本值最大k个元素)
  • quantile(分布统计)without、by

述两个查询是等价的;同一个聚合语句中不可同时使用by和without,by的作用类似于sql语句中的分组(group by),without语义是:除开XX标签,对剩下的标签进行分组。

  • stdvar

数学中称为方差,用于衡量一组数据的离散程度:数据分布得越分散,各个数据与平均数的差的平方和越大,方差就越大。

  • stddev

标准差:用方差开算术平方根。

  • count、count_values

count:对分组中时间序列的数目进行求和

count_values:表示时间序列中每一个样本值(value)出现的次数,实践中一般用于统计版本号。

  • quantile

用于计算当前样本数据值的分布情况,例如计算一组http请求次数的中位数:

  • 3种二元操作符算术运算符(加减乘除模幂)集合/逻辑运算符

仅用于瞬时向量之间,and(并且)、or(或者)、unless(排除)

内置函数absent扮演了not的角色;

absent应用场景,配置告警规则:

  • 比较运算符(==!=> < >=<=),无需过多解释

PromQL高级实战

  • Prometheus内置函数

  • 动态标签函数

提供了对时间序列标签的自定义能力。

label_replace(input_vector, "dst", "replacement", "src", "regex")

label_join(input_vector, "dst", "separator", "src_1", "src_2" ...)

  • 时间日期函数(没有时区的概念)多对多运算算函数(absent,常用于检测服务是否存活)Counter函数

resets函数用于统计计数器重置次数,两个连续的样本之间值减少,被认为是一次计数器重置,相当于是进程重启次数。

  • Gauge函数predict_linear(v range-vector, t scalar)

预测时间序列v在t秒后的值

  • deriv(v range-vector)

使用简单的线性回归计算区间向量v中各个时间序列的导数

  • delta(v range-vector)

计算区间向量内第一个元素和最后一个元素的差值:

  • idelta(v range-vector)

最新的两个样本值之间的差值,如上图例子,返回值为整数

  • holt_winters(v range-vector, sf scalar, tf scalar)

要求sf > 0, tf <=1

霍尔特-温特双指数平滑算法,暂时想不到应用场景

  • changes(v range-vector)

返回区间向量中每个样本数据值变化的次数,如果样本值没有变化就返回1;

prometheus提供度量标准process_start_time_seconds记录每一个targets的启动时间,该时间被更改则意味着进程重启,可以发出循环崩溃告警:

expr: avg wtihout(instance) (changes{process_start_time_seconds [1h]}) > 3

  • 时间聚合函数

  • HTTP API API响应格式

调用成功会返回2XX状态码

resultType: matrix(区间向量) | vector(瞬时向量) | scalar | string

  • 表达式查询
  • /api/v1/query(瞬时数据查询)

入参:PromQL表达式、时间戳、超时设置(可全局设置)

  • /api/v1/query_range(区间数据查询)

入参:PromQL表达式、起始时间戳、结束时间戳、查询时间步长(不能超过11000)、超时设置(可全局设置)

  • 其他拓展
  • /api/v1/targets(获取监控对象列表)
  • /api/v1/rules(获取告警规则数据)
  • /api/v1/alerts(获取告警列表)
  • /api/v1/alertmanagers(获取关联的告警引擎)
  • /api/v1/targets/metadata(获取监控对象元数据)
  • /api/v1/metadata(获取指标元数据)
  • /status(prometheus配置、版本等数据)
  • TSDB管理API

启动参数带上--web.enable-admin-api

执行以下命令可对数据库进行备份:

curl -X POST http://your_ip:9090/api/v1/admin/tsdb/snapshot

备份目录:/prometheus/data/snapshot

删除序列:http:// your_ip:9090/api/v1/admin/tsdb/delete_series

释放空间:http:// your_ip:9090/api/v1/admin/tsdb/clean_tombstones

  • 可定期执行的规则记录规则

预先计算经常需要用到的或计算量较大的表达式,并将结果保存为一组新的时间序列。

  • 告警规则

  • 指标的抓取与存储

抓取前依赖服务发现,通过relabel_configs的方式自动对服务发现的目标进行重新标记;

抓取后主要指标保存在存储系统之前,依赖作业内的metrics_relabel_configs实现。

  • 用relabel_configs抓取指标

重写instance实现告警同时显示服务名+IP端口

  • 用metrics_relabel_configs抓取指标

将监控不需要的数据直接丢掉,不在prometheus保存,配置方法类似。

告警引擎深度解析

  • Alertmanager架构解析

从左上开始,Prometheus 发送的警报到 Alertmanager;

  • 警报会被存储到 AlertProvider 中,Alertmanager 的内置实现就是包了一个 map,也就是存放在本机内存中,这里可以很容易地扩展其它 Provider;
  • Dispatcher 是一个单独的 goroutine,它会不断到 AlertProvider 拉新的警报,并且根据 YAML 配置的 Routing Tree 将警报路由到一个分组中;
  • 分组会定时进行 flush (间隔为配置参数中的 group_interval), flush 后这组警报会走一个 Notification Pipeline 链式处理;
  • Notification Pipeline 为这组警报确定发送目标,并执行抑制逻辑,静默逻辑,发送与重试逻辑,实现警报的最终投递;Alertmanager配置文件解读
  • 全局配置(global):定义一些全局的公共参数,如全局SMTP设置、Slack配置等;
  • 模板(template):定义告警通知的模板,如HTML模板、邮件模板;
  • 告警路由(route):告警的分组聚合,根据自定义标签匹配,确定当前告警应该如何处理;
  • 接收者(receivers):邮箱、webhook等,一般配合告警路由使用;
  • 抑制规则(inhibit_rules):减少垃圾告警产生;

(word不方便添加代码块,如果公众号可以添加代码块,上图内容可以单独提供代码)

  • 关于告警的应用与问题处理

关键配置参数:

prometheus.yml

  • scrape_interval:prometheus从采集器抓取数据间隔,默认1分钟;
  • scrape_timeout:数据抓取超时时间,默认10秒钟;
  • evaluation_interval:评估告警规则的时间间隔(即多长时间计算一次告警规则是否触发),默认1分钟;

alertmanager.yml

  • group_wait:初始等待时间,一组告警消息第一次发送前的等待时间,在这个时间内允许为同一组告警收集更多初始告警,此参数的作用是防止短时间内出现大量告警的情况下,接收者被消息淹没。【此参数建议设置为0到5分钟】。
  • group_interval:睡眠/唤醒周期,一组告警消息被成功发送后,会进入睡眠/唤醒周期,此参数是睡眠状态将持续的时间,在睡眠状态下该组消息可能会有明细内容变化。睡眠结束后进入唤醒状态,如果检查到有明细内容存在变化,则发送新告警消息;如果没有变化,则判断是否达到“重复发送间隔时间”来决定是否发送。【此参数建议设置为5到30分钟】。
  • repeat_interval:重复发送间隔时间,此参数是指同一个消息组在明细内容不变的情况下,连续多长时间不发送告警消息。不过此参数值并不代表告警的实际重复间隔,因为在上一次发送消息后并等待了“重复发送间隔时间”的时刻,该消息组可能处在睡眠状态;所以实际的告警间隔应该大于“重复发送间隔时间”且小于“重复发送间隔时间”与“睡眠/唤醒周期”之和。【此参数建议设置为3小时以上】。

本地存储与远程存储

  • 压缩算法
  • Prometheus本地存储经历过多个迭代:V1.0(2012年)、V2.0(2015年)、V3.0(2017年)。最初借用第三方数据库LevelDB,1.0版本性能不高,每秒只能存储5W个样本;2.0版本借鉴了Facebook Gorilla压缩算法,将每个时序数据以单个文件方式保存,将性能提升到每秒存储8W个样本;2017年开始引入时序数据库的3.0版本,并成立了Prometheus TSDB开源项目,该版本在单机上提高到每秒存储百万个样本。
  • 3.0版本保留了2.0版本高压缩比的分块保存方式,并将多个分块保存到一个文件中,通过创建一个索引文件避免产生大量的小文件;同时为了防止数据丢失,引入了WAL机制。

  • 本地存储文件结构解析

  • 存储原理解析
  • 按时间顺序生成多个block文件,其中第一个block称为head block,存储在内存中且允许被修改,其它block文件则以只读的方式持久化在磁盘上。
  • 抓取数据时,Prometheus周期性的将监控数据以chunk的形式添加到head block中,同时写日志。会按2小时一个block的速率进行磁盘持久化。
  • 崩溃后再次启动会以写入日志的方式实现重播,从而恢复数据。
  • 2小时的block会在后台压缩成更大的block,数据被压缩合并成更高级别的block文件后删除低级别的block文件。

  • M3DB远程存储技术M3特性

主要包括4个组件:M3DB、M3 Coordinator、M3 Query、M3 Aggregator

  • M3DB:分布式时序库,为时间序列数据和反向索引提供了可伸缩、可扩展的存储。
  • M3 Coordinator:辅助服务,用于协调上游系统(如Prometheus和M3DB)之间的读写操作,是用户访问M3DB的桥梁。
  • M3 Query:分布式查询引擎,可查询实时和历史指标,支持多种不同的查询语言(包括PromQL)。
  • M3 Aggregator:聚合层,作为专用度量聚合器运行的服务。M3DB特性
  • 分布式时间序列存储,单个节点使用WAL提交日志并独立保存每个分片的时间窗口。
  • 集群管理建立在etcd之上(分布式服务注册中心)。
  • 内置同步复制功能,具有可配置的持久性和读取一致性。
  • 自定义压缩算法M3TSZ float64。M3DB限制
  • M3DB主要是为了减少摄取和存储数十亿个时间序列的成本并提供快速可伸缩的读取,因此存在一些限制,不适合用作通用时序库。
  • M3DB旨在尽可能避免压缩,目前M3DB仅在可变压缩时间序列窗口内执行压缩,因此乱序写入仅限单个压缩时间序列窗口的大小。
  • M3DB针对float64值的存储和检索进行优化,无法将其用作包含任意数据结构的通用时序库。M3DB分布式架构

  • Coordinator:m3coordinator用于协调群集中所有主机之间的读取和写入。这是一个轻量级的过程,不存储任何数据。该角色通常将与Prometheus实例一起运行。
  • Storage Node:在这些主机上运行的m3dbnode进程是数据库的主力,它们存储数据,并提供读写功能。
  • Seed Node:首先,这些主机本身就是存储节点。除了该职责外,他们还运行嵌入式ETCD服务器。这是为了允许跨集群运行的各种M3DB进程以一致的方式推断集群的拓扑/配置。

梯度运维管理平台监控模块架构 ★

前有网友提出,想要用代码监控一个接口,定时访问它,如果接口返回值发生某些变化就提醒用户。

于是,我写了个简单的脚本。

脚本编写时,考虑的是放在目标网站的控制台来执行。之所以这样做,是因为如果放在页面外部执行,往往需要补环境,费时费力。

核心代码

// 变量声明&定时器
let _timer=null;
let _subjects=[];
_timer=setInterval(()=> {
    getData()
}, 60000);

// 接口访问
function getData () {
    return fetch("https://mail.126.com/xxxx", {
        "xxx": {},
      }).then((res)=> {
        res.text().then((str)=> {
            str=(str || '').replace(/\n/g, '')
            let subjects=str.match(/('subject':'.*?',)/g)
            if (_subjects.length===0) {
                _subjects=subjects
            } else if (subjects[0] !==_subjects[0]) {
                notificationHandler();
            }
        })
    }).catch(err=> {
        console.log('err:', err)
    });
}

// 发送通知
function notificationHandler () {
    let notification;
    if (window.Notification && Notification.permission==='granted') {
        notification=new Notification('收到新邮件啦', {
            dir: 'ltr',
            body: `收到新邮件啦,快去看看吧`
        });
    } else if (Notification.permission !=='denied') {
        Notification.requestPermission().then(function(permission) {
            if (permission==='granted') {
                notification=new Notification('收到新邮件啦', {
                    dir: 'ltr',
                    body: `收到新邮件啦,快去看看吧`
                });
            }
        });
    }
    if (notification) {
        notification.onclick=()=> {
            window.focus();
        };
    }
}

上述代码中的相关逻辑是以邮箱收件箱为例。

将代码放到控制台执行后,每隔1分钟访问一次接口,当响应内容有变化时,会向用户发送系统通知;当用户点击通知面板时,系统就会将焦点给到受监控的网页,方便用户对网页进行查看。

注意事项

1)要求浏览器支持Notification这个API,这个API对应的就是系统右下角的通知功能,目前主流浏览器都是支持的。

系统通知

2)在控制台运行代码前,需要用户已经授权浏览器可以使用Notification权限,如果不知道是否允许,可以在控制台执行代码:

Notification.requestPermission().then(function(permission) {console.log(permission)})

返回值为 granted 说明是已授权的;

如果不是,那么浏览器会弹出提示询问我们是否允许;

如果权限是denied,而且看不到弹窗,那么可以重启浏览器再做尝试。

申请权限

前一直觉得监控告警是件很神奇的事情,仿佛可望不可及,今天我们就一起来解开它神秘的面纱哈哈~~

我的电脑是win10系统,我在电脑上安装了Docker Desktop软件,使用docker部署的

prometheus、pushgateway和alertmanager。

一、拉取prometheus、pushgateway和alertmanager的镜像,命令很简单:

docker pull prom/prometheus

docker pull prom/pushgateway

docker pull prom/alertmanager

可以通过docker images命令查看镜像是否拉取成功。

二、配置prometheus,创建prometheus.yml

global:
  scrape_interval:     60s
  evaluation_interval: 60s


alerting:
  alertmanagers:
  - static_configs:
    - targets: ["ip:9093"]	#这里是alertmanager的地址,注意这个地址是宿主机的地址,不可以写localhost或者127.0.0.1,下面的ip同理

rule_files:
  - "rule/*.yml"	#alertmanager的告警规则文件

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['ip:9090']
        labels:
          instance: prometheus
  - job_name: pushgateway
    static_configs:
      - targets: ['ip:9091']
        labels:
          instance: pushgateway

可以在rule文件夹下创建一个test_rule.yml

groups:
 - name: test_rule
   rules:
   - alert: chat接口超时1500ms个数 # 告警名称
     expr: test_metric > 0 # 告警的判定条件,参考Prometheus高级查询来设定
     for: 1m # 满足告警条件持续时间多久后,才会发送告警
     labels: #标签项
      team: node
     annotations: # 解析项,详细解释告警信息
      summary: "异常服务节点:{{$labels.exported_instance}}"
      description: "异常节点:{{$labels.exported_instance}}: 异常服务名称: {{$labels.Service_Name}} "
      value: "chat接口超时1500ms个数:{{$value}}"

其中exported_instance和Service_Name都是我们往pushgateway中推送的数据,通过{{$labels.xxx}}的形式可以获取到

三、配置alertmanager.yml,创建alertmanager.yml



global:
  resolve_timeout: 5m #处理超时时间,默认为5min
  smtp_smarthost: 'smtp.126.com:25' # 邮箱smtp服务器代理,我这里是126的
  smtp_from: '###@126.com' # 发送邮箱名称=邮箱名称
  smtp_auth_username: '###@126.com' # 邮箱名称=发送邮箱名称
  smtp_auth_password: '#####' # 授权码
  smtp_require_tls: false
  smtp_hello: '126.com'
 
templates:
  - 'test.tmpl'		#告警信息模板
 
route:
  group_by: ['alertname'] #报警分组依据
  group_wait: 10s #最初即第一次等待多久时间发送一组警报的通知
  group_interval: 10m # 在发送新警报前的等待时间
  repeat_interval: 1h # 发送重复警报的周期 对于email配置中,此项不可以设置过低,>否则将会由于邮件发送太多频繁,被smtp服务器拒绝
  receiver: 'email' # 发送警报的接收者的名称,以下receivers name的名称
 
receivers:
- name: 'email'
  email_configs: # 邮箱配置
  - to: '###@126.com'  # 接收警报的email配置
    headers: { Subject: "[WARN] 报警邮件"} # 接收邮件的标题
    send_resolved: true
    html: '{{ template "test.html" .}}'	#这个test.html就是模板中define的名称,需要对应起来
  webhook_configs:
  - url: 'http://ip:9093/alertmanager/hook'	#这个是alertmanager的地址,ip也是宿主机的ip
inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'dev', 'instance']

再配置test.tmpl

{{ define "test.html" }}
<table border="1">
        <tr>
                <td>报警项</td>
                <td>实例</td>
                <td>报警阀值</td>
                <td>开始时间</td>
        </tr>
        {{ range $i, $alert :=.Alerts }}
                <tr>
                        <td>{{ index $alert.Labels "alertname" }}</td>
                        <td>{{ index $alert.Labels "instance" }}</td>
                        <td>{{ index $alert.Annotations "value" }}</td>
                        <td>{{ $alert.StartsAt }}</td>
                </tr>
        {{ end }}
</table>
{{ end }}

配置结束,下面开始启动容器

一、启动pushgateway:docker run -d --name=pushgateway -p 9091:9091 prom/pushgateway

可以登录http://localhost:9091/查看:

二、启动alertmanager

docker run -d -p 9093:9093 --restart=always --name=alertmanager -v  宿主机的alertmanager.yml地址:/etc/alertmanager/alertmanager.yml -v  宿主机的test.tmpl地址:/etc/alertmanager/test.tmpl prom/alertmanager:latest

登录http://localhost:9093/查看:

三、启动prometheus容器

docker run -d -p 9090:9090  --restart=always --name=prometheus -v 宿主机的prometheus.yml地址:/etc/prometheus/prometheus.yml -v 宿主机的rule文件夹路径:/etc/prometheus/rule/ prom/prometheus

登录 http://localhost:9090/查看:

查看监控情况:

此时环境已经全部部署完毕,下面可以往pushgateway中推送数据,查看告警情况

echo "test_metric 2" | curl --data-binary @- http://127.0.0.1:9091/metrics/job/test_job/instance/192.168.0.1/Service_Name/ai_sym_interface

这个命令的意思是向job为test_job中推送数据,instance为192.168.0.1,Service_Name为ai_sym_interface,值为2

可登录pushgateway查看推送情况:

由于prometheus监控了pushgateway的数据指标,所以在prometheus中也可以看到这条数据:

由于我们配置了test_rule.yml,当test_metric大于0并持续一秒会发送,报警邮件:

至此,邮箱告警就完成了,其他的告警也是同样的道理,可以继续研究,加油~!

原文链接:记忆旅途