监控-Prometheus10-Prometheus监控系统生产部署
1、最佳实践原则
- 在Prometheus官网中对如何更好地使用该监控系统做了充分的说明,包括指标和标签命名、控制台和仪表盘、测量仪表、直方图和摘要、告警、用好PushGateway等。
- Prometheus监控系统创始人之一Julius Volz在2018年4月北京QCon大会上做了《Prometheus监控系统最佳实践与常见陷阱(Prometheus Best Practices and BeastlyPitfalls)》主题演讲,对如何用好Prometheus监控系统从实践上做了系统性总结。
1、指标与标签的命名
- 指标命名必须符合数据模型的有效字符。应该有一个与度量所属的域相关的应用程序前缀(客户端库函数有时将前缀称为命名空间),特定应用程序前缀通常是应用程序名称本身。
- 在所有标签维度上测量的逻辑内容要相同,包括请求持续时间、数据传输字节数、即时资源使用率(百分比)等。
- 标签是用来区分正在测量的事物的特征,不要将标签名称放在度量名称中,这会导致冗余,将显著增加存储的数据量。
- Prometheus中没有任何单位是硬编码的,但为了更好地兼容,应该使用国际基本单位。
2、控制台和仪表盘
- 不要试图在控制台展示每一种数据,而是要考虑最可能的故障模式以及如何区分。
- 与其在单个大仪表盘上显示每个服务的信息,不如为每个服务构建单独的仪表盘,包括每个服务的延迟和错误。
- 然后可以从顶部开始,一直钻取到有问题的服务。
- 我们发现:控制台上的图形不超过5个;每个图表上的图(线)不超过5个;使用控制台模板展示时,在右侧表格中数据项不要超过30个。
3、测量仪表
- 在使用同一个文件中创建的实例化度量类,在跟踪错误时,容易做到警报从控制台到代码进行切换。出于不同的监控目的,服务通常可以分为在线服务、离线处理和批处理作业三种类型。此外系统还有库接口、日志信息、失效、线程池、高速缓存、采集器等部分,这些也需要被监控。
4、直方图和摘要
- 直方图和摘要是更复杂的度量类型,要准确地使用这些度量类型难度很大。
- 直方图和摘要两个样本的观测结果,通常是请求持续时间或响应大小,跟踪观测的数量和观测值的总和,然后计算观测的平均值。
- 请注意,观测的数量本质上是一个计数器(它只会增加)。观测值之和也是计数器,如请求持续时间或响应大小从不为负数。
- 原则上,可以使用摘要和直方图来观测负值(例如摄氏温度)。在这种情况下,观察值的总和会下降,这时不能再对其应用rate函数。有两条经验法则:
- 如果需要聚合,请选择直方图。
- 如果知道将要观察的值的范围和分布,请选择一个直方图;如果需要精确的分位数,不论值的范围和分布,请选择摘要。
5、告警
- 确保警报的简单,准确发出告警,拥有良好的控制台,便于查明原因。发出警报时确保Prometheus服务、警报管理器、推送网关和其他监控基础设施是正常运行的。可以对根因发出警报,这有助于减少噪声。例如从Pushgateway到Prometheus再到Alertmanager最后到email的黑盒测试,比单个警报都要好。将Prometheus的白盒监控与外部黑盒监控相结合,可以捕捉到难以觉察的问题,并在内部系统完全失效的情况下作为备用手段。
6、使用PushGateway
- Pushgateway是一种中介服务,它允许你从无法抓取的作业中推送度量。建议在某些有情况下使用Pushgateway,当使用Pushgateway而不是Prometheus通常的Pull模型时,有几个陷阱需要注意:
- 当通过一个Pushgateway监视多个实例时,Pushgateway既可以成为单一故障点,又可能成为潜在的瓶颈。
- Prometheus实时采集Up状态度量来做健康监控会失效。
- Pushgateway将信息永远暴露给Prometheus,除非手动删除信息。
2、数据存储
- 对于如何构建适合生产环境使用的Prometheus系统,需要对Prometheus的数据存储有比较深入的理解。
- Prometheus的数据存储分为本地存储和远端存储两种方式。
- 本地存储:Prometheus自带的时序数据库将数据存储在本地,从而实现了高性能的读写。
- 远端存储:因为时序数据库是非集群数据库,这样就限制了它的存储容量,无法保存大量的历史监控数据,为此Prometheus引入了远端存储。
2.1、本地存储
- Prometheus的本地存储经历了三个版本:V1(2012)、V2(2015)、V3(2017)。从V2开始,Prometheus的数据存储充分借鉴了Facebook的Gorilla设计思想及Facebook内部的长期使用经验,总结了时序数据的特点:
- 相邻数据点时间戳的差值相对固定,即使有变化,也仅在一个很小的范围内浮动。
- 相邻数据点的值的变化幅度很小,甚至无变化。
- 对热数据的查询频率远远高于对非热数据的查询频率,并且数据离现在越近,热度越高。
1、高效的本地存储模型
- 在Facebook上发表的关于Gorilla的文章(http://www.vldb.org/pvldb/vol8/p1816-teller.pdf)中提出了一种压缩算法,可以将16字节的数据压缩到1.37字节,节省12倍内存,并且通过分块(chunk)方式保存,数据要在服务器内存里积累一定的时间再写入磁盘,如图14-1所示。
- 其原理非常简单,首先是对时间戳采用两次去差值的方式,加入三个时间点:t(N-2)=02:00:00、t(N-1)=02:01:02、t(N)=02:02:02。在第1次压缩时,t(N-1)-t(N-2)=62,t(N)-t(N-1)=60;在第2次压缩时,60-62=-2。采用保存差值的方式来大幅度降低存储空间,采样的频率通常也是固定的,这样差值几乎都是0。对于指标值,则对相邻指标进行异或(XOR)操作,如果前后两个采样值相等,二者异或的结果为0,则只需要保存一个0,而且监控数据通常变化不大,异或的结果将会很小,便于保存。
- 但Prometheus V2的存储设计存在很大的问题:
- (1)每个序列都对应一个文件并且文件有10MB,这样会耗尽文件系统的Inode,并且同时随机读写了这么多的文件,磁盘的性能会大大降低,对于SSD还会存在写放大的问题。
- (2)被监控对象越来越多且不断更新。例如,在Kubernetes容器监控方面,容器的生命周期比较短暂,指标不停变化,会形成“时序流失”。随着时间的推移,虽然有LevelDB负责时序的索引,但这些时间序列数量会线性增长,导致内存加压过多,如图14-2所示。
-
- (3)无法预测容量。数据首先在内存中缓慢构建,在被保存到磁盘中后,内存中的数据会被回收,这样发生时序流失时,内存的消耗就会增加。如果要查询已经存储到磁盘的历史数据,则再次将相关数据全部加载到内存中,此时很容易发生内存溢出(Out Of Memory,OOM),导致Prometheus被“杀掉”,给运维人员造成很大的压力。
- 在2017年Prometheus的存储迎来了由Fabian主导开发的V3版本(https://github.com/Prometheus/tsdb)。在V3版本中保留了V2高压缩比的分块保存方式,并将多个分块保存到一个文件中,通过创建一个index做索引文件,避免产生大量的小文件;同时为了防止数据丢失,引入了WAL(write-ahead-log,写入日志)机制。
- 如图14-3所示,PrometheusV3将整个存储空间按时间水平拆分成很多独立区间,每个区间就相当于一个独立的数据库。
- Prometheus V3版本存储引擎具有优点:
- 从V2版本的每个时序一个文件改进到V3版本的一段时间一个文件,可以有效避免时序流失的问题,还可以任意组织多个分块的数据到一个文件中。
- 每个文件分块最大支持512MB,可避免SSD写效率问题。
- 在删除数据时直接删除分区即可。
- 在查询历史数据时,由于已经按照时间排序,可以将内存数据和此磁盘数据合并,通过懒加载的方式载入数据。不需要将所有磁盘数据加载到内存,避免发生OOM(内存溢出)。
- 在V3版本的存储结构中wal目录保存的是监控数据的WAL。采用自定义的存储格式将采样数据保存在本地磁盘当中。按照两个小时为一个时间窗口,将两小时内产生的数据存储在一个块(Block)中,每一个块中包含该时间窗口内的所有采样数据(chunks)、元数据文件(meta.json)以及索引文件(index)。
- 而在当前时间窗口内正在收集的采样数据,Prometheus直接将数据保存在内存当中。为了确保此期间如果Prometheus发生崩溃或者重启时能够恢复数据,Prometheus启动时会以WAL方式来实现重载,从而恢复数据。此期间如果通过API删除时间序列,删除记录也会保存在单独的逻辑文件tombstone中。
- 通过时间窗口的形式保存所有的采样数据,可以明显提高Prometheus的查询效率,当查询一段时间范围内的所有采样数据时,只需要简单地从落在该范围内的块中查询数据即可。该存储方式也简化历史数据的删除逻辑。只要一个块的时间范围落在了配置的保留范围之外,直接丢弃该块即可。
2、本地存储配置
- 用户可以通过命令行启动时加参数的方式修改本地存储的配置。在一般情况下,Prometheus中存储的每一个采样约占用1~2字节。如果需要对Prometheus Server的本地磁盘空间做容量规划,可以通过以下公式计算:
- 需要磁盘容量=保留时间(秒)×每秒采样数×采样大小(字节数)
- 在保留时间(retention_time_seconds)和采样大小(bytes_per_sample)不变的情况下,如果想减少本地磁盘的容量需求,只能通过减少每秒获取采样数(ingested_samples_per_second)的方式。有两种手段,一是减少时间序列的数量,二是增加采样的时间间隔。考虑到Prometheus会对时间序列进行压缩,因此减少时间序列的数量效果更明显。
3、从失效中恢复
- 如果本地存储由于某些原因出现了失效,最直接的方式就是停止Prometheus并且删除data目录中的所有数据。当然也可以尝试删除那些发生失效的块目录,这就意味着用户会丢失该块中保存两小时的监控数据。
2.2、远端存储
- Prometheus高效的本地存储模型,可以让单台Prometheus能够高效地处理大量数据,减少其自身运维和管理的复杂度,同时能够满足大部分用户监控规模的需求。但是本地存储也意味着Prometheus无法长时间保存数据,无法存储大量历史数据,同时也无法灵活扩展。
- 为了保持Prometheus的简单性,Prometheus并没有尝试在本地解决以上问题,而是定义了两个标准接口:远端读/远端写(remote_read/remote_write),让用户可以基于这两个接口对接任意第三方的存储服务,这种方式在Prometheus中称为远端存储(Remote Storage)。目前已经实现Adapter的远端存储主要包括InfluxDB、OpenTSDB、CreateDB、TiKV、Cortex、M3DB等。
1、远端存储读/写结构
- Prometheus的远端读/写是通过一个适配器实现的,如图14-6所示。
- 用户可以在Prometheus配置文件中指定远端写入(RemoteWrite)的URL地址,一旦设置了该配置项,Prometheus将样本数据通过HTTP的形式发送给适配器(Adaptor)。而用户则可以在适配器中对接外部任意的服务。外部服务可以是真正的存储系统,或公有云的存储服务,也可以是消息队列等任意形式。
- 在远端读的流程当中,当发起查询请求后,Prometheus将向remote_read中配置的远端URL发起查询请求(matchers,ranges),适配器Adaptor根据请求条件从第三方存储服务中获取响应的数据。同时将数据转换为Prometheus的原始样本数据返回给Prometheus本地存储。当获取到样本数据后,Prometheus在本地使用PromQL对样本数据进行二次处理。
- 注意,即使使用了远程读,Prometheus中对于规则文件的处理以及Metadata API的处理,都只是在本地存储中完成的。
- 当然也可以通过自己编写Remote Stoarge Adaptor来实现远端存储,但这需要分别创建用于支持remote_read和remote_write的HTTP服务。
2、设置配置文件
- 用户需要使用远程读写功能时,需要在Prometheus配置文件中添加remote_write和remote_read配置,其中URL用于指定远程读/写的HTTP服务地址。如果该URL启动了认证则可以通过basic_auth进行安全认证配置。对于https的支持需要设定tls_concig。proxy_url主要用于Prometheus无法直接访问适配器服务的情形。
- remote_write和remote_read具体配置如下所示:
remote_write: url: <string> [ remote_timeout: <duration> | default = 30s ] write_relabel_configs: [ - <relabel_config>... ] basic_auth: [ username: <string> ] [ password: <string> ] [ bearer_token: <string> ] [ bearer_token_file: /path/to/bearer/token/file ] tls_config: [ <tls_config> ] [ proxy_url: <string> ] remote_read: url: <string> required_matchers: [ <labelname>: <labelvalue>... ] [ remote_timeout: <duration> | default = 30s ] [ read_recent: <boolean> | default = false ] basic_auth: [ username: <string> ] [ password: <string> ] [ bearer_token: <string> ] [ bearer_token_file: /path/to/bearer/token/file ] [ <tls_config> ] [ proxy_url: <string> ]
3、使用Influxdb作为Remote Stoarge
- 目前Prometheus社区提供了部分对第三方数据库远端存储的支持https://prometheus.io/docs/operating/integrations/#remote-endpoints-and-storage。
- 可以使用Influxdb作为Prometheus的远端存储,从而确保当Prometheus发生宕机或者重启之后能够从Influxdb中恢复和获取历史数据。
3、构建联邦集群系统
3.1、联邦集群基础
- 早期,Prometheus的核心工程师做出明智的决定,让Prometheus保持简洁和可组合性。从一开始,Prometheus设计成可以很好地完成一小部分工作,并与其他可选组件无缝协作。以下是Prometheus设计范围外的一些内容:
- 长期存储。单个Prometheus实例提供持久存储时间序列数据的功能,但它们不能作为分布式数据存储系统,不提供跨节点复制和自动修复等功能。这意味着,持久性存储保证仅限于单台机器。幸运的是,Prometheus提供了一个远程写入API,可用于将时间序列数据传输到其他系统存储。
- 全局数据视图。如上所述,Prometheus实例充当隔离数据存储单元。Prometheus实例可以联邦,但这会给Prometheus设置增加很多复杂性,而且Prometheus不是设计为分布式数据库。这意味着,没有简单的途径来实现时间序列数据的单一、一致的“全局”视图。
- 多租户。Prometheus本身没有的租户概念。这意味着,对于特定租户的数据访问和资源使用配额等事物,它无法提供任何形式的细粒度控制。
- 在社区发展过程中,出现了联邦集群、Thanos集群等解决方案。
- 单个Prometheus Server可以轻松处理数以百万级的时间序列。当然根据规模的变化,Prometheus同样可以轻松地进行扩展。
- Prometheus支持使用联邦集群的方式对Prometheus进行扩展。
- 对于大部分监控规模而言,只需要在每一个数据中心(例如EC2可用区、Kubernetes集群)安装一个Prometheus Server实例,就可以在各个数据中心处理上千规模的集群。
- 同时将Prometheus Server部署到不同的数据中心,可以避免网络配置的复杂性。
- 联邦集群架构如图14-7所示,在每个数据中心部署单独的Prometheus Lx用于采集当前数据中心监控数据。并由一个中心的Prometheus Hx负责聚合多个数据中心的监控数据。
- 每一个Prometheus实例包含一个/federate接口,用于获取一组指定的时间序列的监控数据。因此在中心Prometheus Hx中只需配置一个采集任务,用于从其他Prometheus Lx中获取监控数据。配置如下:
scrape_configs: - job_name:'federate' scrape_interval: 15s honor_labels: true metrics_path: '/federate' params: 'match[]': - '{job="prometheus"}' - '{__name__=~"job:.*"}' - '{__name__=~"node.*"}' static_configs: - targets: - '192.168.0.11:9090' - '192.168.0.12:9090'
- params用于控制Prometheus在向Target实例请求监控数据的URL当中添加请求参数。
http://192.168.0.11:9090/federate?match[]={job%3D"prometheus"}&match[]={__name__%3D~"job%3A.*"}&match[]={__name__%3D~"node.*"}
- 通过URL中的match[]参数指定要获取的时间序列。match[]参数必须是一个瞬时向量选择器,例如up或者{job="api-server"}。配置多个match[]参数,用于获取多组时间序列的监控数据。
- horbor_labels如果配置为true,可以确保当采集到的监控指标冲突时,能够自动忽略冲突的监控数据;如果配置为false,Prometheus会自动将冲突的标签替换为“exported_”的形式。
- 将honor_labels设置为“true”对于federation和抓取Pushgateway等用例是有用的,在这些用例中,target中指定的所有标签都应该被保留。
- 联邦模式可以实现Prometheus监控Prometheus。遵循以下两点:
- 网格模式。在同一个数据中心,每个Prometheus监控其他的Prometheus。
- 上下级模式。上一级的Prometheus监控数据中心级别的Prometheus。
- 这种架构不仅降低了单个Prometheus的负载,而且通过联邦节点汇聚核心数据,降低了本地的存储压力。为了避免下层Prometheus的单点故障,可以部署多套Prometheus节点,只是在效率上会差很多,每个监控对象都会被重复采集,数据也会被重复保存。
- 联邦集群方案并不是最完善的解决方案,原因如下:
- 这种配置方式相对复杂,缺少统一的全局视图。
- 对历史数据的存储问题仍未得到彻底解决,必须依赖第三方存储,且缺少针对历史数据的降准采样能力。
- 最根本的原因是Prometheus在设计之初就定位为实时监控系统。
3.2、实现联邦集群
1、部署环境
- 10.1.1.11:CentOSLinuxrelease7.7.1908(Core),Prometheus L1
- 10.1.1.12:CentOSLinuxrelease7.7.1908(Core),Prometheus L2
- 10.1.1.13:CentOSLinuxrelease7.7.1908(Core),Prometheus H1
- 10.1.1.14:CentOSLinuxrelease7.7.1908(Core),node_exporter
2、部署Prometheus Lx节点
- Prometheus Lx节点就是普通的Prometheus。
- (1)部署Prometheus L1
- 部署在10.1.1.11
global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "node_exporter" static_configs: - targets: ["10.1.1.14:9100"]
- (2)部署Prometheus L2
- 部署在10.1.1.12
global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"]
3、部署Prometheus Hx节点
- 部署一个Prometheus Hx联邦节点,从两个Prometheus Lx中读取数据。
- 部署在10.1.1.13
global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: 'federate' scrape_interval: 15s honor_labels: true metrics_path: '/federate' params: 'match[]': - '{job="prometheus"}' - '{__name__=~"job:.*"}' - '{__name__=~"node.*"}' static_configs: - targets: - '10.1.1.11:9090' - '10.1.1.12:9090'
- 查看联邦Prometheus节点
4、Thanos集群解决方案
- Prometheus在小规模的部署中,完全不需要依赖其他组件就可以达到监控的目的。但在应对大规模、大数据量的集群时,就存在缺少集群、数据可靠性保障的支持。Prometheus虽然支持联邦部署模式,但这个架构还是会有其他问题,如数据会被重复储存在两个地方,还有被拉取的Prometheus机器有可能发生超时现象。另外,监控数据分散在多台Prometheus监控节点,在变动或者长期存储时依赖本地磁盘,本地磁盘一般不是高可用的存储,监控数据就变得没有可靠性保障。
- 为了解决上述问题,产生了多种解决方案,Thanos(https://github.com/thanos-io/thanos或https://thanos.io/)方案是最成熟、广泛使用的。由Improbable发起,于2019年7月捐给了CNCF,正式成为CNCF Sandbox的开源项目,成为与Prometheus无缝集成统一的监控系统,主要实现了全局视图、高可用、不受限制的数据存储等功能。
4.1、Thanos集群架构
- Thanos由一组组件组成,每个组件都扮演着特定的角色:
- Thanos Sidecar:连接Prometheus,将其数据提供给Thanos Query查询,或者将其数据上传到对象存储,以供长期存储。
- Thanos Ruler:对监控数据进行评估和告警,还可以计算出新的监控数据,将这些新数据提供给Thanos Query查询并且/或者上传到对象存储,以供长期存储。
- Thanos Query:实现了Prometheus API,将来自下游组件提供的数据进行聚合最终返回给查询数据的client(如 grafana),类似数据库中间件。
- Thanos Store Gateway:将对象存储的数据暴露给Thanos Query去查询。
- Thanos Compact:将对象存储中的数据进行压缩和降低采样率,加速大时间区间监控数据查询的速度。
- Thanos Receiver:从Prometheus的WAL目录中接收数据,并将数据上传到对象存储。
- Thanos Query Frontend:实现Prometheus的v1 API将其代理给Query,同时缓存响应并可选地按查询日进行分割。
- Thanos有两种模式:
- Sidecar模式:绑定部署在Prometheus 实例上,当进行查询时,由thanos sidecar返回监控数据给Thanos Query对数据进行聚合与去重。最新的监控数据存放于Prometheus本机(适用于Sidecar数量少,prometheus集群查询响应快的场景)
-
- Receive模式:Prometheus实例实时将数据push到Thanos Receiver,最新数据也得以集中起来,然后Thanos Query也不用去所有Sidecar查最新数据了,直接查Thanos Receiver即可(适用于集群规模大,prometheus节点较多,集群查询响应慢的场景)
1、全局视图
- 为了能够在现有的Prometheus集群之上得到全局视图(Global view),需要将中心查询层和所有监控服务器互联。在Prometheus服务器侧运行Thanos Sidecar组件,通过基于gRPC协议的Store API提供Prometheus的本地数据,也允许通过标签和时间段来选择时间序列数据。
- 在中心查询端运行的是一个可以横向扩展并且无状态的Querier组件,Querier、Sidecar以及其他的Thanos组件通过Gossip协议实现相互通信。当Querier收到一个请求时,它会向相关的Store API服务器(这里即是Sidecar)发送请求,并从Prometheus获取数据。它可以聚合不相交的数据,也可以针对Prometheus的高可用组进行数据去重。
2、长期保留数据(Long-term retention)
- 希望保留超出Prometheus常规保留时间外的数据,就需要备份历史数据。现在各云服务商都有提供对象存储且极具成本效益,对象存储已经成为最佳的备份存储方式,且几乎均可以通过S3 API进行操作。
- Prometheus的存储引擎大约每两个小时将最近的内存数据写入磁盘。持久化的数据块包含固定时间范围内的所有数据,且是不可变的。这样Thanos Sidecar就可以通过简单地监听Prometheus数据目录的变化,在新的数据块出现时将它们上传到对象存储桶中。在指标数据块写入磁盘后通过Sidecar上传到对象存储的一个额外好处是可以保持“scraper”(由Prometheus和Thanos Sidecar组成)足够的轻量,简化了系统设计和运维成本。
- 如何再次从对象存储中查询数据呢?时间序列的数据块由一些大文件组成,按需下载它们的话会效率低下,且在本地缓存它们需要巨大的内存和磁盘空间。Thanos Store组件充当了一个对象存储里面数据的数据检索代理,就像Thanos Sidecar那样,加入到Gossip集群里并且实现了Store API。这样现有的Querier就可以把它也当成是类似Sidecar那样访问,不需要任何特殊处理。Store Gateway知道如何处理Prometheus存储引擎的数据格式。通过智能的查询计划并且仅缓存必要索引部分的数据块的方式,它能够将一些复杂查询降级成针对对象存储里的文件最小数量的范围请求,可以在不影响响应时间的同时将请求数量降低四到六个数量级,几乎与本地SSD上的数据查询一样快。
3、压缩和降准采样(compaction&downsampling)
- 经过一段时间后,随着来自单一数据源数据的累积,就会出现索引效率降低。Thanos引入了一个单独的Compactor组件,它会简单地将Prometheus的本地压缩机制应用到对象存储里的历史数据,可以作为一个简单的定时批处理任务执行。Compactor会持续将序列数据聚合。从用户的角度来看,使用Compactor降准采样后的数据不需要做什么特殊配置。
4、记录规则(rules)
- 即便使用了Thanos方案,记录规则依然是监控的重要部分。它们减少了查询的复杂度、延迟和成本,也为用户提供了方便地查看指标数据的快捷方式。Thanos提供了Ruler组件,管理多个告警规则,配置统一管理的问题,将基于Thanos Querier执行规则并作出告警。
4.2、部署thanos的方法
- thanos的原型是Prometheus(或多或少会使用Prometheus功能),Prometheus始终是收集指标和使用本地数据发出警报的基础。
- 注意:thanos由于要使用Prometheus的远程读取,因此强烈建议使用Prometheus v2.13+。
- 请按照Prometheus团队的建议运行Prometheus:
- 把Prometheus在同样的故障域。这意味着监控服务使用相同的网络、相同的数据中心。
- 使用持久磁盘在Prometheus重启过程中持久保存数据。
- 使用局部压缩很久之前的数据。
- 不要更改最小TSDB块持续时间。
- 除非必要,不要向外扩展Prometheus。单一的Prometheus非常高效。
- 当需要扩展的Prometheus时,建议使用Prometheus。
- 使用Sidecar模式部署Thanos:
- thanos通过Sidecar进程与现有的Prometheus服务进行集成,该进程与Prometheus服务运行在同一台机器或同一pod中。
- Sidecar的目的是将Prometheus数据备份到对象存储桶中,并让thanos的其他组件通过gRPC API访问Prometheus指标。
- Sidecar重新加载Prometheus。确保它是通过参数--web.enable-lifecycle启用的。
- 部署参考文档:https://thanos.io/tip/thanos/quick-tutorial.md/
1、部署sidecar
- 每一个Prometheus实例都需要部署一个sidecar。
thanos sidecar \ #sidecar将Prometheus的数据写入到对象存储 --tsdb.path /apps/prometheus/data/ \ #Prometheus的TSDB数据目录 --objstore.config-file bucket_config.yaml \ #将数据上传到对象存储的配置 --prometheus.url "http://localhost:9090" \ #确保sidecar可以使用这个url(prometheus的url) #Sidecar组件公开“Store API的GRPC端点”, --grpc-address 0.0.0.0:19090 \ #用于在Sidecar上收集指标的HTTP端点(被监控端口) --http-address 0.0.0.0:19191 #用于在Sidecar上收集度量的HTTP端点
- 如果您对备份任何数据不感兴趣,可以将--objstore.config-file省略。
- 使用Prometheus operator部署thanos。
- https://github.com/prometheus-operator/prometheus-operator/tree/main/example/thanos
- Prometheus允许给Prometheus实例配置“外部标签”。它们用于全局识别该Prometheus实例。由于thanos的目标是跨所有Prometheus实例聚合数据,提供一组一致的外部标签变得至关重要。
- 每个Prometheus实例都必须有一组全局唯一的标识标签。例如,在Prometheus的配置文件中:
]# vim /apps/prometheus/prometheus.yml global: external_labels: region: eu-west monitor: infrastructure replica: A
- bucket_config.yaml示例:
type: ALIYUNOSS config: endpoint: "oss-cn-beijing.aliyuncs.com" bucket: "promstore" access_key_id: "LTAI******Z9*****9bc8cS" access_key_secret: "6bCKg******xcU******ws******wB"
2、部署Query
- 可以使用Query在Thanos的全局查询层对所有Prometheus实例进行PromQL查询。
- Query是无状态和可以水平可伸缩的,可以使用任意数量的Query。一旦Query连接到Sidecars,它就会自动检测给定的PromQL查询需要联系哪些Prometheus服务器。
thanos query \ #thanos查询器HTTP的端口 --http-address 0.0.0.0:29191 \ #连接到“Store API的GRPC端点”。--store是可重复的,也支持DNS的A和SRV记录 --store 10.1.1.11:19090 \ --store 10.1.1.12:19090 \ #如果是作用于Prometheus HA,可以对Prometheus HA对收集的数据进行重复数据删除 --query.replica-label replica \ #根据标签删除重复数据(external_labels中配置的标签) --query.replica-label replicaX #--query.replica-label可以重复使用
- thanos节点之间唯一需要的通信是thanos查询器要到达的sidecar的gRPC store api。Thanos查询器定期调用Info端点来收集最新的元数据,并检查给定Store API的运行状况。
- 有多种方法可以告诉查询组件它应该从哪些store api中查询数据。最简单的方法是使用已知地址的静态列表。
3、部署Store Gateway
- 由于sidecar会将数据备份到对象存储中,因此可以减少Prometheus的保留期限。然而,需要一种方法来再次查询所有的历史数据。
- 存储网关通过实现与sidecars相同的gRPC data API 来实现这一点,但用它可以在对象存储桶中找到的数据来支持它。
- Store Gateway就像sidecar和query一样也暴露了Store API,需要Thanos Querier发现。
thanos store \ --data-dir /var/thanos/store \ #本地缓存的磁盘空间 --objstore.config-file bucket_config.yaml \ #从对象存储中获取数据 --grpc-address 0.0.0.0:39090 \ #Store API的GRPC端点 #用于在Store Gateway上收集度量的HTTP端点(被监控端口) --http-address 0.0.0.0:39191
- 存储网关占用少量磁盘空间,用于缓存对象存储数据的基本信息。这很少会超过几gb,并用于提高重启时间。它很有用,但在重新启动时保存它不是必需的。
4、部署Compactor
- 本地安装Prometheus会定期压缩旧数据,以提高查询效率。由于sidecar会尽可能快地备份数据,所以我们需要一种方法将相同的过程应用于对象存储中的数据。
- 压缩器组件只是扫描对象存储并在需要的地方处理压缩。同时,它负责创建数据的下采样副本,以加快查询速度。
thanos compact \ --data-dir /var/thanos/compact \ #数据处理的临时工作区 --objstore.config-file bucket_config.yaml \ #桶中应用压缩的位置 --http-address 0.0.0.0:49191 #用于在压缩器上收集度量的HTTP端点(被监控端口)
- 压缩器不在查询或数据备份的关键路径上。它既可以作为定期批处理作业运行,也可以一直运行以尽可能快地压缩数据。建议提供100gb ~ 300gb的本地磁盘空间用于数据处理。
- 注意:压缩器必须作为单例运行,不能在手动修改桶中的数据时运行。
5、Ruler/Rule
- 如果带有thanos侧车的普罗米修斯没有足够的留存率,或者如果你想拥有需要全局视图的警报或记录规则,thanos就有相应的组件:Ruler,它在给定thanos查询器之上执行规则和警报评估。
4.3、实现部署thanos
- 部署环境
- 10.1.1.11:CentOSLinuxrelease7.7.1908(Core),prometheus,thanos-Sidecar
- 10.1.1.12:CentOSLinuxrelease7.7.1908(Core),prometheus,thanos-Sidecar
- 10.1.1.13:CentOSLinuxrelease7.7.1908(Core),thanos-Query
1、部署10.1.1.11
- 部署prometheus
global: scrape_interval: 15s evaluation_interval: 15s external_labels: #必须有,否则thanos-Sidecar启动会报错 region: eu-west monitor: infrastructure replica: A alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "node_exporter" static_configs: - targets: ["10.1.1.12:9100"]
- 部署thanos-Sidecar
./thanos sidecar \ --tsdb.path /apps/prometheus/data/ \ --prometheus.url http://localhost:9090 \ --grpc-address 0.0.0.0:19090 \ --http-address 0.0.0.0:19191
2、部署10.1.1.12
- 部署prometheus
global: scrape_interval: 15s evaluation_interval: 15s external_labels: region: eu-west monitor: infrastructure replica: B alerting: alertmanagers: - static_configs: - targets: # - alertmanager:9093 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] - job_name: "thanos" static_configs: - targets: ["10.1.1.11:19191"]
- 部署thanos-Sidecar
./thanos sidecar \ --tsdb.path /apps/prometheus/data/ \ --prometheus.url http://localhost:9090 \ --grpc-address 0.0.0.0:19090 \ --http-address 0.0.0.0:19191
3、部署10.1.1.13
- 部署thanos-Query
./thanos query \ --http-address 0.0.0.0:29191 \ --store 10.1.1.11:19090 \ --store 10.1.1.12:19090 \ --grpc-address 0.0.0.0:29090
- 查看thanos-Query的UI
5、Alertmanager高可用
- Alertmanager告警处理过程如图14-12所示。
- 为了提升Prometheus的服务可用性,通常用户会部署两个或者两个以上的Prometheus Server,它们具有完全相同的配置,包括Job配置、告警配置等。当某一个Prometheus Server发生故障后可以保障Prometheus持续可用。
- 同时,Alertmanager有告警分组机制,即使不同的Prometheus Sever分别发送相同的告警给Alertmanager,Alertmanager也可以自动将这些告警合并为一个通知向receiver发送。
- 虽然Alertmanager能够同时处理多个相同的Prometheus Server所产生的告警。但是由于部署的是单个Alertmanager,存在明显的单点故障风险,当Alertmanager单点失效后,告警的后续所有业务全部失效。
- 为了解决单点问题可以部署多套Alertmanager。但是多个ALertmanager之间并不了解彼此的存在,因此则会出现告警通知被不同的Alertmanager重复发送多次的问题。
- 为了解决这一问题,Alertmanager引入了Gossip机制,如图14-13所示。Gossip机制为多个Alertmanager之间提供了信息传递的机制。确保及时在多个Alertmanager分别接收到相同告警信息的情况下,也只有一个告警通知被发送给Receiver。
5.1、Gossip机制
- 要理解Gossip机制,需要先了解Alertmanager中的一次告警通知是如何产生的,如图14-14所示,Alertmanager是通过流水线的形式处理告警通知。
- 在第一个阶段Silence中,Alertmanager会判断当前通知是否匹配任何静默规则;如果没有则进入下一个阶段,否则中断流水线不发送通知。
- 在第二个阶段Wait中,Alertmanager会根据当前Alertmanager在集群中所处的顺序(index)等待index×5s的时间。
- 当前Alertmanager等待阶段结束后,进入第三个阶段Dedup,这时会判断在当前Alertmanager数据库中该告警是否已经发送,如果已经发送则中断流水线,不发送告警;否则进入下一阶段Send,对外发送告警通知。
- 告警发送完成后,进入最后一个阶段Gossip,通知其他Alertmanager实例当前告警已经发送。其他实例接收到Gossip消息后,会在自己的数据库中保存该告警已发送的记录。
- Gossip机制有两个关键点:
- Alertmanager各实例之间Silence设置完全相同,这样可以确保设置为静默的告警都不会对外通知。
- Alertmanager通过Gossip机制同步告警通知状态,同时在流水线中定义Wait阶段,确保告警依次被集群中的Alertmanager处理。
- Alertmanager基于Gossip协议实现的集群机制虽然不能保证所有实例上的数据时刻保持一致,但是实现了CAP理论中的AP系统,即可用性和分区容错性。同时对于Prometheus Server而言保持了配置的简单性,Prometheus Server之间不需要任何的状态同步。
5.2、搭建本地集群环境
- 为了能够使Alertmanager节点之间进行通信,需要在Alertmanager启动时设置相应的参数。
- --cluster.listen-address="0.0.0.0:9094":当前alertmanager实例监听的地址(默认是“0.0.0.0:9094”)。设置为空字符串禁用HA模式。
- --cluster.peer=CLUSTER.PEER ...:初始化时关联的其他alertmanager实例的地址。(可能重复)。
- --cluster.advertise-address=CLUSTER.ADVERTISE-ADDRESS:集群广播地址。
- --cluster.peer-timeout=15s:alertmanager之间发送通知的等待时间(默认是“15s”)。
- --cluster.gossip-interval=200ms:发送gossip消息的间隔时间。通过降低该值(更频繁),gossip消息可以更快地在集群中传播,但以增加带宽为代价。(默认是“200ms”)
- --cluster.pushpull-interval=1m0s:gossip状态同步的时间间隔。值越小收敛越快,但消耗的带宽也会增加(默认是“1m0s”)。
- --cluster.tcp-timeout=10s:在与其他alertmanager进行链接、读、写时TCP的超时时间(默认是“10s”)。
- --cluster.probe-timeout=500ms:在判定其他alertmanager不可用之前的等待时间(默认是“500ms”)。
- --cluster.probe-interval=1s:探测其他alertmanager节点的时间间隔(默认是“1s”)。该值越低(更频繁)就可以越快地检测到故障节点,但代价是增加了带宽使用量。
- --cluster.settle-timeout=1m0s:在评估通知之前等待集群连接解决的最大时间。
- --cluster.reconnect-interval=10s:尝试重新连接丢失的alertmanager的时间间隔。
- --cluster.reconnect-timeout=6h0m0s:试图重新连接丢失的alertmanager的时间长度。
示例:
- 定义Alertmanager实例a1,其中Alertmanager的服务运行在9093端口,集群服务地址运行在8001端口。
./alertmanager --web.listen-address=":9093" --cluster.listen-address="127.0.0.1:8001" \ --config.file=./alertmanager.yml --storage.path=/data/alertmanager/
- 定义Alertmanager实例a2,其中主服务运行在9094端口,集群服务运行在8002端口。为了将a1、a2组成集群,a2启动时需要定义--cluster.peer参数并且指向a1实例的集群服务地址:8001。
./alertmanager --web.listen-address=":9094" --cluster.listen-address="127.0.0.1:8002" \ --config.file=./alertmanager.yml --storage.path=/data/alertmanager2/ \ --cluster.peer=127.0.0.1:8001
- 定义多个Prometheus实例与Alertmanager集群关联
- 由于实现了Gossip机制,在Prometheus和Alertmanager实例之间不要使用任何负载均衡,需要确保Prometheus将告警发送到所有的Alertmanager实例中:
]# vim /apps/prometheus/prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: - 127.0.0.1:9093 - 127.0.0.1:9094 rule_files: # - "first_rules.yml" # - "second_rules.yml" scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"]
1
# #