Prometheus时序数据库-数据的插入
Prometheus时序数据库-数据的插入
前言
在之前的文章里,笔者详细的阐述了Prometheus时序数据库在内存和磁盘中的存储结构。有了前面的铺垫,笔者就可以在本篇文章阐述下数据的插入过程。
监控数据的插入
在这里,笔者并不会去讨论Promtheus向各个Endpoint抓取数据的过程。而是仅仅围绕着数据是如何插入Prometheus的过程做下阐述。对应方法:
func (a *headAppender) Add(lset labels.Labels, t int64, v float64) (uint64, error) {
......
// 如果lset对应的series没有,则建一个。同时把新建的series放入倒排Posting映射里面
s, created := a.head.getOrCreate(lset.Hash(), lset)
if created { // 如果新创建了一个,则将新建的也放到a.series里面
a.series = append(a.series, record.RefSeries{
Ref: s.ref,
Labels: lset,
})
}
return s.ref, a.AddFast(s.ref, t, v)
}
我们就以下面的add函数调用为例:
app.Add(labels.FromStrings("foo", "bar"), 0, 0)
首先是getOrCreate,顾名思义,不存在则创建一个。创建的过程包含了seriesHashMap/Postings(倒排索引)/LabelIndex的维护。如下图所示:

然后是AddFast方法
func (a *headAppender) AddFast(ref uint64, t int64, v float64) error{
// 拿出对应的memSeries
s := a.head.series.getByID(ref)
......
// 设置为等待提交状态
s.pendingCommit=true
......
// 为了事务概念,放入temp存储,等待真正commit时候再写入memSeries
a.samples = append(a.samples, record.RefSample{Ref: ref,T: t,V: v,})
//
}
Prometheus在add数据点的时候并没有直接add到memSeries(也就是query所用到的结构体里),而是加入到一个临时的samples切片里面。同时还将这个数据点对应的memSeries同步增加到另一个sampleSeries里面。

事务可见性
为什么要这么做呢?就是为了实现commit语义,只有commit过后数据才可见(能被查询到)。否则,无法见到这些数据。而commit的动作主要就是WAL(Write Ahead Log)以及将headerAppender.samples数据写到其对应的memSeries中。这样,查询就可见这些数据了,如下图所示:

WAL
由于Prometheus最近的数据是保存在内存里面的,未防止服务器宕机丢失数据。其在commit之前先写了日志WAL。等服务重启的时候,再从WAL日志里面获取信息并重放。

为了性能,Prometheus了另一个goroutine去做文件的sync操作,所以并不能保证WAL不丢。进而也不能保证监控数据完全不丢。这点也是监控业务的特性决定的。
写入代码为:
commit()
|=>
func (a *headAppender) log() error {
......
// 往WAL写入对应的series信息
if len(a.series) > 0 {
rec = enc.Series(a.series, buf)
buf = rec[:0]
if err := a.head.wal.Log(rec); err != nil {
return errors.Wrap(err, "log series")
}
}
......
// 往WAL写入真正的samples
if len(a.samples) > 0 {
rec = enc.Samples(a.samples, buf)
buf = rec[:0]
if err := a.head.wal.Log(rec); err != nil {
return errors.Wrap(err, "log samples")
}
}
}
对应的WAL日志格式为:
Series records
┌────────────────────────────────────────────┐
│ type = 1 <1b> │
├────────────────────────────────────────────┤
│ ┌─────────┬──────────────────────────────┐ │
│ │ id <8b> │ n = len(labels) <uvarint> │ │
│ ├─────────┴────────────┬─────────────────┤ │
│ │ len(str_1) <uvarint> │ str_1 <bytes> │ │
│ ├──────────────────────┴─────────────────┤ │
│ │ ... │ │
│ ├───────────────────────┬────────────────┤ │
│ │ len(str_2n) <uvarint> │ str_2n <bytes> │ │
│ └───────────────────────┴────────────────┘ │
│ . . . │
└────────────────────────────────────────────┘
Sample records
┌──────────────────────────────────────────────────────────────────┐
│ type = 2 <1b> │
├──────────────────────────────────────────────────────────────────┤
│ ┌────────────────────┬───────────────────────────┐ │
│ │ id <8b> │ timestamp <8b> │ │
│ └────────────────────┴───────────────────────────┘ │
│ ┌────────────────────┬───────────────────────────┬─────────────┐ │
│ │ id_delta <uvarint> │ timestamp_delta <uvarint> │ value <8b> │ │
│ └────────────────────┴───────────────────────────┴─────────────┘ │
│ . . . │
└──────────────────────────────────────────────────────────────────┘
见Prometheus WAL.md
落盘存储
之前描述的所有数据都是写到内存里面。最终落地是通过compator routine将每两个小时的数据打包到一个Blocks里面。

具体可见笔者之前的博客《Prometheus时序数据库-磁盘中的存储结构》
总结
在这篇文章里,笔者详细描述了Prometheus数据的插入过程。在下一篇文章里面,笔者会继续
阐述Prometheus数据的查询过程。

Prometheus时序数据库-数据的插入的更多相关文章
- Prometheus时序数据库-数据的查询
Prometheus时序数据库-数据的查询 前言 在之前的博客里,笔者详细阐述了Prometheus数据的插入过程.但我们最常见的打交道的是数据的查询.Prometheus提供了强大的Promql来满 ...
- Prometheus时序数据库-报警的计算
Prometheus时序数据库-报警的计算 在前面的文章中,笔者详细的阐述了Prometheus的数据插入存储查询等过程.但作为一个监控神器,报警计算功能是必不可少的.自然的Prometheus也提供 ...
- Prometheus时序数据库-内存中的存储结构
Prometheus时序数据库-内存中的存储结构 前言 笔者最近担起了公司监控的重任,而当前监控最流行的数据库即是Prometheus.按照笔者打破砂锅问到底的精神,自然要把这个开源组件源码搞明白才行 ...
- Prometheus时序数据库-磁盘中的存储结构
Prometheus时序数据库-磁盘中的存储结构 前言 之前的文章里,笔者详细描述了监控数据在Prometheus内存中的结构.而其在磁盘中的存储结构,也是非常有意思的,关于这部分内容,将在本篇文章进 ...
- C# 数据库数据动态插入(反射)
/// <summary> /// 提供将MySqlDataReader转成T类型的扩展方法 /// </summary> public static class MySqlD ...
- 时序数据库连载系列:指标届的独角兽Prometheus
简介 Prometheus是SoundCloud公司开发的一站式监控告警平台,依赖少,功能齐全.于2016年加入CNCF,广泛用于 Kubernetes集群的监控系统中,2018.8月成为继K8S之后 ...
- ThinkPHP增加数据库字段后插入数据为空的解决办法
今天用ThinkPHP做了一个简单的商品发布系统,数据库本来只有四个字段id,name,url,image.id是主键,name是商品名称,url是商品链接,image是商品图片,做的差不多了,发现还 ...
- C# 批量插入表SQLSERVER SqlBulkCopy往数据库中批量插入数据
#region 帮助实例:SQL 批量插入数据 多种方法 /// <summary> /// SqlBulkCopy往数据库中批量插入数据 /// </summary> /// ...
- C#中几种数据库的大数据批量插入
C#语言中对SqlServer.Oracle.SQLite和MySql中的数据批量插入是支持的,不过Oracle需要使用Orace.DataAccess驱动. IProvider里有一个用于实现批量插 ...
随机推荐
- c语言中qsort函数的使用、编程中的一些错误
qsort()函数: 功能:相当于c++sort,具有快排的功能,复杂度的话nlog(n)注:C中的qsort()采用的是快排算法,C++的sort()则是改进的快排算法.两者的时间复杂度都是nlog ...
- Codeforces Round #650 (Div. 3) C. Social Distance (前缀和)
题意:有一排座位,要求每人之间隔\(k\)个座位坐,\(1\)代表已做,\(0\)代表空座,问最多能坐几人. 题解:我们分别从前和从后跑个前缀和,将已经有人坐的周围的位置标记,然后遍历求每一段连续的\ ...
- 要想用活Redis,Lua脚本是绕不过去的坎
前言 Redis 当中提供了许多重要的高级特性,比如发布与订阅,Lua 脚本等.Redis 当中也提供了自增的原子命令,但是假如我们需要同时执行好几个命令的同时又想让这些命令保持原子性,该怎么办呢?这 ...
- aop详解与实战
1. 什么是AOP aop:面向切面编程.采用横向机制. oop:面向对象编程.采用纵向机制. AOP,面向切面编程.就是通过某个切入点(比如方法开始.结束)向某个切面(被切的对象)切入环绕通知(需要 ...
- python try异常处理
什么是异常 python异常捕获,在刚开始学的时候,经常会遇到两种报错信息:语法错误和执行的异常. 语法错误在执行的时候就会报错,同时控制端会告诉你错误所在的行: 但即便python程序语法是正确的, ...
- kubernetes实战-交付dubbo服务到k8s集群(二)交付jenkins到k8s集群
首先下载jenkins镜像并上传到我们自己的私有仓库:7-200 # docker pull jenkins/jenkins:2.190.3 # docker tag 22b8b9a84dbe har ...
- Seq2Seq原理详解
一.Seq2Seq简介 seq2seq 是一个Encoder–Decoder 结构的网络,它的输入是一个序列,输出也是一个序列.Encoder 中将一个可变长度的信号序列变为固定长度的向量表达,Dec ...
- 涂颜色的RPG问题
长度为n的方格,刷3种颜色的颜料,相邻的方格颜料颜色不能相同,且首尾方格颜色不能相同.每个方格必须涂色.计算一共有多少种涂色方式. 解题思路:(1)f(1)=3,f(2)=6,f(3)=6 (2)如果 ...
- 【Alpaca】.Net版开源配置中心 - 技术选型 Vue 3.0
是否可以用 Vue 3.0 现有的Vue 2.* 不推荐,坐等Vue 3.0出迁移工具吧,手动改的话工作量还是不小的 新项目 考虑下团队内对Vue + TS + VS Code的熟练程度.过程中你会遇 ...
- AirPods Max 出厂激活是怎么回事
AirPods Max 出厂激活是怎么回事 话说出厂激活是怎么检测出来的 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问! 原创文 ...