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

Grafana Tempo源码解读(十一)Querier组件和Ingester组件的查询过程

栋总侃技术 2024-01-04
204

在前面三个章节对Query Frontend组件的代码进行讲解,理清楚了其查询请求的代码逻辑,最终将查询拆分成若干个小的请求发送至Querier组件。本节将带来当查询请求到达Querier组件后,Querier组件是如何完成数据的查找并响应返回的。

initQuerier()

t.store.EnablePolling

在初始化Querier组件的函数内,看到一个熟悉的面孔 t.store.EnablePolling(context.Background(), nil)
,EnablePolling会周期性的加载存储中的Block、CompletedBlock至内存。

Compactor的代码结构和同步Block过程章节中对EnablePolling的过程进行了详细讲解,这里就不详细解读。

与Compactor组件不同的是,在这里不需要对Block进行Compact和Clear,只需要周期性加载Blocks。

middleware

相较于Query Frontend组件,Querier组件封装的middleware就少很多了,只有HTTPAuthMiddleware获取租户ID的过程,就直接到达TraceByIDHandler

TraceByIDHandler

在处理函数中解析TraceID,获取请求参数中的blockStart, blockEnd, queryMode,最后调用Querier的FindTraceByID
函数查找Trace数据。

FindTraceByID

FindTraceByID
中依据QueryMode有两种查询方式,QueryModeIngesters类型和QueryModeBlocks类型。

分别是向Ingester发起请求和直接从依赖的Store中查询Blocks。

QueryModeIngesters

QueryModeIngesters模式通过client tempopb.QuerierClient
向Ingester发起请求,将请求返回的结果通过combiner组合。

其中forIngesterRings会遍历IngesterRing获取所有的Ingester实例的地址封装的client,并发向各Ingester实例发起请求。

最终QueryClient向Ingester发起Grpc请求。

QueryModeBlocks

QueryModeBlocks模式直接在store中查询Block,而在上面介绍EnablePolling
和之前的章节讲解Compactor组件时,了解到Store里维护这一个BlockList和一个CompletedBlocks。那么这里就应该是直接从这两个Blocks的列表中进行查找了。

与Compactor组件一样,在Querier中维护的Store对象都会定时加载存储中的Blocks,所以可以认为Querier中的Store和Compactor的Store里的数据基本上是保持一致的。(存在同步的时间差)

在Compactor章节了解到Store是tempodb.readerWriter
结构定义的对象,我们直接找到其成员函数 Find。

在blocklist和compactedBlocklist中找出所有符合范围条件的Blocks存放至 copiedBlocklist。

并发地从copiedBlocklist中查找符合traceID的Trace数据。

Ingester

Ingester.FindTraceByID

在Grpc的协议文件中可以找到对应的请求路径和handler接口定义。

请求会调用目标服务的FindTraceByID
函数。

在初始化Ingester时将Ingester对象注册至Grpc服务,那么这个请求将会交给Ingester的FindTraceByID
函数处理。

FindTraceByID
函数中会根据查询携带的租户ID,到对应的instance中进行查找(这个过程与Ingester写入的逻辑一致,instance表示一个租户)。

instance.FindTraceByID

instance从completingBlocks
completeBlocks
中查找到对应满足TraceID条件的Block,最后combiner成一个Trace结构返回给Querier组件。

在讲解Ingester写入Block至持久化存储的过程中时,了解到Ingester会将Blocks
转化为completingBlocks
,然后转化为completeBlocks
的两个过程,这里查询的正是还没有被写入存储的数据。

总结

从Query Frontend的查询请求到达Querier组件后,若干个根据BlockID范围的小查询对Querier组件中的Blocks进行查找。这些Blocks是由Querier组件通过store对象定期从存储中同步的Blocks。

从Query Frontend的查询请求中也包含一个Ingester类型的查询,当请求到达Querier组件后,Querier组件会向Ingester组件发送查询请求,Ingester组件将会查询自身维护的completingBlocks
completingBlocks
。这些Blocks为最近接收还未写入到持久化存储的Blocks

到这里就是完成了查询请求完整过程的代码阅读讲解。当在Grafana上发起请求查询后,请求将会经过QueryFrontend组件、Querier组件、Ingester组件。其中QueryFrontend组件中的逻辑处理比较复杂,Querier组件、Ingester组件的代码逻辑就比较直观。

通过对Tempo代码的讲解,现在大家除了对Tempo中各组件提供的功能有所了解外,同时更深入的了解了其原理。以及各组件在运转时依赖的配置项对吞吐量、性能的影响,在后续对Tempo运维的过程中出现瓶颈时,可以通过原理去定位问题能够更快的解决问题。关于Tempo读写主流程的代码介绍就到这里。

本系列回顾

Grafana Tempo源码解读(十)Query Frontend组件最终篇

Grafana Tempo源码解读(九)Query Frontend组件的各MiddleWare加载顺序和作用

Grafana Tempo源码解读(八)Query Frontend组件的MiddleWare使用解读

Grafana Tempo源码解读(七)Compactor将Block进行压缩和删除的过程

Grafana Tempo源码解读(六)Compactor的代码结构和同步Block过程

Grafana Tempo源码解读(五)总结Tempo接收数据的限制以及配置调整

Grafana Tempo源码解读(四)Ingester组件将数据写入持久化存储

Grafana Tempo源码解读(三)Ingester组件接收Trace数据的过程

Grafana Tempo源码解读(二)Distributor对Trace数据的处理和发送至Ingester

Grafana Tempo源码解读(一)Distributor建立监听接收Trace数据


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

评论