暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Thanos 源码解析(五)- Receive Shipper

栋总侃技术 2021-12-28
1488

上一节我们讲解了Thanos的MultiTSDB是如何借助Prometheus的TSDB实现多租户的管理。这一节将会接着上一节的内容继续看,Thanos怎样将采样数据上传至对象存储的?

upload

在进入upload方法前,我们先看看如果上传对象存储失败了,会做什么处理?


先关注下allowOutOfOrderUploads标识,在上一节我们我们知道这个参数确定是否可以上传重叠的数据,就是当Prometheus的mmap操作后的数据block是否还允许上传,默认是false。

如果这里不允许,然后此时也写对象存储失败了,那么直接返回错误;如果允许,那说明这块block还可以在后续被上传至对象存储,所以写个错误日志记录下就行。

我们着重看下这一节的内容 upload方法。

func (s *Shipper) upload(ctx context.Context, meta *metadata.Meta) error

首先创建一个该block对应的上传目录 …/thanos/upload/{uid},并清空(若已经存在则清空内容)。


将需要上传的指标的chunks链接到对应的upload目录

例如上述示例中的
/var/thanos/receive/default-tenant/01FQXHWHBQ7N7EQ0ZN5T3CB66P/chunks/000001

会被链接到
/var/thanos/receive/thanos/upload/01FQXHWHBQ7N7EQ0ZN5T3CB66P/chunks/000001


然后将该目录下所有的文件(需要上传的chunks),赋值给SegmentFiles,并指定Source类型,这里的Source类型为ReceiveSource(receive)/var/thanos/receive/thanos/upload/01FQXHWHBQ7N7EQ0ZN5T3CB66P/chunks


然后将meta信息写入meta.json

最后使用block的upload方法真正的上传数据。可以看到需要上传 chunks、index、meta.json这几个文件或者文件夹:


上传成功后会将已上传的id写入thanos.shipper.json。

到这里,我们已经了解了Thanos Receive的完整过程。

租户

虽然还没有去了解Thanos其它的组件,但是通过这几篇文章大家应该对Thanos如何实现可水平伸缩扩展的Prometheus有着大概的了解了。

Thanos通过增加租户的概念实现将Prometheus实现的单序列TSDB扩充为多序列。

然后又通过Hash算法将指定的租户的第n个副本数据指定给对应的实例处理,实现相同一个副本的数据一定是在一个时序的TSDB中,确保数据不会乱序。

围绕着多时序数据库,且保证单租户数据的时序性,又对重启、hash变更等异常状况下的数据上传于清理,保证数据的不丢失等方面来健壮整个Thanos的稳定性。

以上就是Thanos的核心理念。

在第一节简单的有提到租户,到这里我觉得详细讲解Thanos Reeive处理多租户与Hashing的逻辑是很有必要的。

tentant

从header中读取该租户的租户名称,为该租户的ID。

读取的key为 命令行参数receive.tentant-header,默认为:THANOS-TENANT。

如果不存在该头,则认为是默认的租户:default-tentant。

Hashing

我们先看一个Hashing的结构:

[
{
"hashring": "tenant-a",
"endpoints": ["tenant-a-1.metrics.local:19291/api/v1/receive", "tenant-a-2.metrics.local:19291/api/v1/receive"],
"tenants": ["tenant-a"]
},
{
"hashring": "tenants-b-c",
"endpoints": ["tenant-b-c-1.metrics.local:19291/api/v1/receive", "tenant-b-c-2.metrics.local:19291/api/v1/receive"],
"tenants": ["tenant-b", "tenant-c"]
},
{
"hashring": "soft-tenants",
"endpoints": ["http://soft-tenants-1.metrics.local:19291/api/v1/receive"]
}
]

个hashring文件表示:

  • tentant-a由tentant-a-1、tentant-a-2两个实例处理;

  • tentant-b和tentant-c由tentant-b-1、tentant-b-2两个实例处理;
    其他的租户由soft-tentants-1实例处理

当某个租户的请求到达Receive时,遍历hashing配置,寻找该tentant租户处理的Receive实例。匹配条件为要么租户名称匹配,没有匹配到时就默认为未指定tentant的实例。

例如 tentant-a将找到tentant-a-1、tentant-a-2;tentant-e由于未匹配到指定的租户,则交给soft-tentants-1实例处理。

那么 如果某条tentant-a的采样数据到底是给tentant-a-1还是tentant-a-2处理呢?

不知道大家还记得我在Thanos 源码解析(三)- Prometheus TSDB的实现的实现这一节中讲的label和series的概念吗。如果不清楚的可以先去复习下。

首先对某个series的label按照key排序,保证一个series的指标不会因为label顺序不同而认为是不同的series。然后根据租户ID与这个series计算出一个hash值。

例如在Thanos 源码解析(三)- Prometheus TSDB的实现中的示例:

node_cpu_seconds_total{cpu="0",mode=“idle”} 5340.12
node_cpu_seconds_total{cpu="0",mode=“iowaite”} 11.13
node_cpu_seconds_total{cpu="1",mode=“idle”} 4740.34
node_cpu_seconds_total{cpu="1",mode=“iowaite”} 12.10

某个租户,这四个seies计算出来的hash值可能会不一样,但是对于 node_cpu_seconds_total{cpu="0",mode=“idle”} 5340.12
这个series不同的时间序列计算出来的hash值肯定是一样的。假设为3

然后该hash值对 处理该租户的实例列表个数取余,例如tentant-a的租户列表是2。

那么这个租户的这个series的采样数据要备份的第n份,会按照公式(3+n)对 2取余 ,来计算给哪个实例处理。

  • 第1份备份的结结果为0,所以交给tentant-a-1处理。

  • 第2份备份的结结果为1,所以交给tentant-a-2处理。

如果需要备份3份,则计算结果还是0,仍然交给tentant-a-1处理。由于一个Receive实例只会根据租户建立时序数据库,对于这种场景第一份和第三份数据都是交给tentant-a-1处理,只是徒劳的增加处理消耗了。这是Thanos不允许的。

当n大于处理该租户的实例列表个数则直接报错。


本系列回顾:

Thanos 源码解析(四)- Receive MultiTSDB

Thanos 源码解析(三)- Prometheus TSDB的实现

Thanos 源码解析(二)- Receive组件

Thanos 源码解析(一)- Receive组件


文章转载自栋总侃技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论