prometheus源码分析:checkpoint
什么是checkpoint?
checkout是wal中一个目录:
# ls -alh
-rw-r--r-- 1 root root 11M 12月 14 17:00 00000999
-rw-r--r-- 1 root root 11M 12月 14 19:00 00001000
-rw-r--r-- 1 root root 2.1M 12月 14 19:22 00001001
drwxr-xr-x 2 root root 22 12月 14 19:00 checkpoint.00000998
# ls -alh checkpoint.00000998/
-rw-r--r-- 1 root root 384K 12月 14 19:00 00000000
prometheus写入指标时,将指标写入内存和wal,然后返回写入成功。wal保证了prometheus crash-free的能力。
prometheus内存中缓存了最近2hour的指标数据,然后2hour的数据被压缩成block,存储在硬盘上;此时这2hour的WAL数据就可以被删除了。
checkpoint就是用来清理wal日志的。
当2hour的内存数据被压缩成block存储至硬盘时:
- 该时间之前的wal日志就可以删除了;因为已经持久化到硬盘了,即使prometheus实例宕掉,也不会丢数据;
- 此时,prometheus生成一个checkpoint,进行wal日志的清理;
checkpoint的整体流程
假设之前checkpoint为checkpoint.m,在segment n处,进行block的存储,此时checkpoint的流程如下:
读取文件:
- checkpoint.m目录下所有文件
- segment m+1~n之间的所有文件
- 遍历文件内容,将block之后的series和samples数据,写入checkpoint.n目录;
checkpoint生成之后,会删除以下文件:
- 删除segment.n之前的segment;
- 删除之前的checkpoint:< n(如checkpoint.m);
checkpoint的代码分析
入口代码:
// tsdb/head.go
// Truncate removes old data before mint from the head.
func (h *Head) Truncate(mint int64) (err error) {
....
// 生成新的checkpoint
wal.Checkpoint(h.logger, h.wal, first, last, keep, mint)
// 将segment.n之前的segment删掉
err := h.wal.Truncate(last + 1)
// 将之前的checkpoint删掉: < last
err := wal.DeleteCheckpoints(h.wal.Dir(), last)
}
checkpoint的过程代码:
// tsdb/wal/checkpoint.go
// from/to:segment id
// keep:用于判断series是否保留
// mint: sample.timestamp >= mint时保留
func Checkpoint(logger log.Logger, w *WAL, from, to int, keep func(id uint64) bool, mint int64) (*CheckpointStats, error) {
var sgmReader io.ReadCloser
{
var sgmRange []SegmentRange
// 读checkpoint.m
dir, idx, err := LastCheckpoint(w.Dir())
last := idx + 1
if err == nil {
from = last
sgmRange = append(sgmRange, SegmentRange{Dir: dir, Last: math.MaxInt32})
}
// 读segment.m+1 ~ n
sgmRange = append(sgmRange, SegmentRange{Dir: w.Dir(), First: from, Last: to})
sgmReader, err = NewSegmentsRangeReader(sgmRange...)
}
r := NewReader(sgmReader)
// 遍历所有的record
for r.Next() {
rec := r.Record()
switch dec.Type(rec) {
case record.Series:
series, err = dec.Series(rec, series)
for _, s := range series {
// series是否保留
if keep(s.Ref) {
repl = append(repl, s)
}
}
// 写入buf
if len(repl) > 0 {
buf = enc.Series(repl, buf)
}
case record.Samples:
samples, err = dec.Samples(rec, samples)
repl := samples[:0]
for _, s := range samples {
// timestamp >= mint需要保留
if s.T >= mint {
repl = append(repl, s)
}
}
// 写入buf
if len(repl) > 0 {
buf = enc.Samples(repl, buf)
}
}
recs = append(recs, buf[start:])
// Flush records in 1 MB increments.
if len(buf) > 1*1024*1024 {
// 写入checkpoint.n目录中
if err := cp.Log(recs...); err != nil {
return nil, errors.Wrap(err, "flush records")
}
buf, recs = buf[:0], recs[:0]
}
}
// Flush remaining records.
err := cp.Log(recs...)
err := cp.Close();
......
}
参考:
38 声望
21 粉丝
推荐阅读
cadvisor采集docker容器的DiskUsage指标--源码分析
一. DiskUsage指标cadvisor采集的docker容器的DiskUsage指标,包含:container_fs_inodes_freecontainer_fs_inodes_totalcontainer_fs_limit_bytescontainer_fs_usage_bytes {代码...} 二. 采集的过程docker容器...
a朋阅读 508
prometheus与exemplar
exemplar最早被用在Google的StackDriver中,后面成为了 OpenMetrics 标准的一部分,即: 可以为metrics额外增加属性。
a朋阅读 1.2k
统一观测丨使用 Prometheus 监控 Nginx Ingress 网关最佳实践
在 Kubernetes 集群中,我们通常使用 “Nginx Ingress” 实现集群南北向流量的代理转发,Nginx Ingress 基于集群内 Ingress 资源配置生成具体的路由规则。Ingress 资源负责对外公开服务的管理,一般这类服务通过 HT...
阿里云云原生阅读 1.1k
prometheus-adapter源码分析
metrics-relist-interval:series的查询间隔,adapter在内存中维护了集群当前的series,并定期查询prometheus进行更新;
a朋阅读 980
Prometheus部署及node-exporter部署方案
准备工作1、创建用户和配置环境参数(1)、创建用户和创建所需目录 {代码...} (2)、下载[链接]部署方案1、部署(1)、关闭防火墙 {代码...} (2)、解压安装包并备份配置文件 {代码...} (3)、创建所需目录 {代码...} 2...
iM唐小龙阅读 818
Prometheus PushGetway部署
准备工作1、创建用户和配置环境参数(1)、创建用户和创建所需目录 {代码...} (2)、下载[链接]部署方案1、部署(1)、关闭防火墙 {代码...} (2)、解压安装包并备份配置文件 {代码...} (3)、创建日志路径 {代码...} 2...
iM唐小龙阅读 811
promethus删除value=""的label
一.概述prometheus拉取exporter中的指标进行解析时,对于labels,若label value="",则会将该label去掉;也就是说,对于label value="",不会存储到tsdb,通过prom API也查询不到该label。二.源码分析1.原理scape...
a朋阅读 606
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。