prometheus存储架构与高可用:联邦和thanos
本文主要是对官方手册的解读,加上了一点基于实际压测后对方案的感受
https://yunlzheng.gitbook.io/prometheus-book/part-ii-prometheus-jin-jie/readmd/prometheus-local-storage
存储
架构
prometheus 2.x版本以两小时为一个周期,每个周期落盘记录为一个block,block下面有chunk样本数据、metadata元数据、index索引数据
未落盘的数据保存在内存中,如果发生意外导致应用崩溃,恢复的时候会从写入日志(WAL)中读取并重播以恢复数据,在此期间如果发生过删除数据的操作,也会被记录在逻辑文件tombstones
这种以时间段来分段的方式有利于数据的查询以及简化删除过期数据的逻辑
普罗米修斯中单个指标样本约占1-3字节,当然,在其可靠的压缩算法之下能变得更小(按fb的算法能压缩到 1.37 bytes 每个点,我们测在3左右),2.x版本甚至专门对ssd的读写性能和次数进行了优化,感动人心。存储大小的计算公式为
needed_disk_space = retention_time_seconds * ingested_samples_per_second * bytes_per_sample
如果保留时间和指标本身不变动的话,从ingested_samples_per_second(每秒采样总数)想要压缩存储成本就两个方法:
1.延长采样间隔
2.减少指标
prometheus压缩算法参考了fb的Gorilla tsdb,有兴趣可以研究一下
data/
├── 01GCDV01N8T74K4HE9JRD7PNQP #block,命名采用ULID:全局字典可排序ID
│ ├── chunks #样本,单块最大512M
│ │ └── 000001
│ ├── index #索引
│ ├── meta.json #元数据
│ └── tombstones #逻辑
├── 01GCDYC64PDTMA62ZMT73GEX8S
│ ├── chunks
│ │ └── 000001
│ ├── index
│ ├── meta.json
│ └── tombstones
├── chunks_head
│ └── 000002
├── lock
├── queries.active
└── wal #写入日志
├── 00000000
├── 00000001
├── 00000002
└── 00000003
内存中存放的数据,每满三个小时,会被分成2h和1h的一块,2h的那块落盘,1h的那块继续留在内存,数据在写入内存的同时也会被写入wal以确保持久性
内存中的存储结构我们叫其head_block,当获取到新的数据,会写入其中的head_chunk,chunk也是唯一能够被写入的地方。这个chunk每当样本数达到设定的值或者range达到设定的值的时候就会被剪切,然后新增一个新的chunk,旧的chunk被称为“full”,从2.19开始,一个full的chunk会被写入磁盘并通过内存映射引用在内存中,当需要用到的时候可以动态加载进来,当达到上面说的3h时,其中2h的chunk会被压缩成block落盘,wal中的数据也会形成checkpoint截断旧的数据,这个检查点将会检查这些被截断的数据,看看他们是否满足被删除的条件
新版本的普罗米修斯支持wal压缩,这将大大减少磁盘和内存的开销----旧版本可能会出现因为wal数据过多而导致硬盘和内存占用过大,可以参考这篇https://asktug.com/t/topic/512888/2 最最好的解决方法是升级版本
一篇压测文:https://www.percona.com/blog/2018/09/20/prometheus-2-times-series-storage-performance-analyses/
远程存储
虽然prometheus本身就支持本地存储,但是如果想要数据持久化,可以考虑外接influxdb搞个远程存储,只需要调用(remote_write/remote_read)这两个接口就可以实现远程存储的读写
对于远程读取,prometheus会对数据用promQL进行二次处理,另外,因为promtheus只有数据是放数据库的,规则等都是通过配置文件实现的,所以启用远程读设置后,只在数据查询时有效,对于规则文件的处理,以及Metadata API的处理都只基于Prometheus本地存储完成。
开启这两个功能只需要修改普罗米修斯的配置文件就行
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> ]
普罗米修斯现在也支持一些第三方的存储,所以上面说能够influxdb是基于这个原因,至于实现方式看上面的手册,这里不再复制粘贴
高可用:套娃方案
官方给出了三套高可用方案,不过其实本质上就是一套,分成了丐中丐版、丐版、完全版而已
对于大量数据的处理,官方给的方案是这套,用nginx负载均衡来保障可用性,两个大P的数据是一样的,挂了一个还有一个,小p们通过relabel设置分功能去收集或者随便咋分,总之采了数据上交给大P,以此来保证应对大量数据时的采集性能。最后再外挂个远程存储来实现数据持久化存储
所谓联邦集群,本质其实是部署多套普罗米修斯收集数据,最后再用一个普罗米修斯从这些个小p身上汇总数据
以上三部分可以按需选择,各自解决一部分问题
(方案挺不错的,不过我选择prometheus+thanos
https://github.com/thanos-io/thanos/tree/main/
官方的这套联邦方案,看起来很美好,但是实际测试下来性能很差,数据量大不推荐使用,毕竟他下面小弟汇总,再去拉取,这个数据量大了必卡(测下来别说亿级,百万级、大几十万级都会翻白眼直接超时),而且普罗米修斯本身的性能瓶颈也导致了即便是提高机器配置也很难提升多少性能
这就不得不提到另外一个著名的社区方案:thanos。比如布两套一样的普罗米修斯去采集事务再用thanos去查。这个方案和联邦方案的区别在于,单个pod采集上来的数据量本身是比较小的,虽然汇总起来很大,但是对于普罗米修斯来说就等于是在并行处理许多的小任务,这个普罗米修斯完全是可以做到的。而联邦集群的方案会导致大P去拉取小p的数据时,一次性的把小p获取到的所有数据打包拉了上来,等于在并行处理几个超巨大的任务,饭一口一口吃多吃几碗没问题,一口吃一碗会把人给噎死
Thanos
https://github.com/thanos-io/thanos/tree/main/
灭霸,可靠的开源高可用方案(笑
因为买的服务器过期了,所以这里安装就不演示了
thanos能无缝兼容promtheus,并且易于水平横向扩容,翻译成人话就是,要是一对prometheus拉不了所有的数据,可以把数据分组,用多组prometheus分别去拉
简单架构说明:
sidecar和prometheus布一个pod里面,他将prometheus的已落盘的数据上传到对象存储,将grpc的调用转换为http,请求prometheus查询并返回数据,可以像上面一样布两个promtheus去拉一样的数据,起到高可用的作用
query提供查询接口,当在prometheus数据保存期内就从sidecar查,如果超过保质期就去对象存储查,拿到结果后去重返回
object store对象存储,数据在结果compact组件(图上没画)压缩后存入对象存储,提供了数据持久化功能
storegateway提供查询语句转换功能,把promQL转换成对象存储能够理解的语句再发给他
虽然已落盘的数据在pod和obj里面都有,但是除非超过保质期,不然都是从pod里面查而非obj,对象存储的查询性能很差
thanos还有些其他的组件,像rule之类的,这里就不讲了
评论已关闭