Thanos源码专题【左扬精讲】——Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )

Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )

https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/query_frontend.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
 
package main
 
import (
    "net/http"
    "time"
 
    "github.com/NYTimes/gziphandler"
    cortexfrontend "github.com/cortexproject/cortex/pkg/frontend"
    "github.com/cortexproject/cortex/pkg/frontend/transport"
    "github.com/cortexproject/cortex/pkg/querier/queryrange"
    cortexvalidation "github.com/cortexproject/cortex/pkg/util/validation"
    "github.com/go-kit/log"
    "github.com/go-kit/log/level"
    "github.com/oklog/run"
    "github.com/opentracing/opentracing-go"
    "github.com/pkg/errors"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/weaveworks/common/user"
    "gopkg.in/yaml.v2"
 
    extflag "github.com/efficientgo/tools/extkingpin"
 
    "github.com/thanos-io/thanos/pkg/api"
    "github.com/thanos-io/thanos/pkg/component"
    "github.com/thanos-io/thanos/pkg/exthttp"
    "github.com/thanos-io/thanos/pkg/extkingpin"
    "github.com/thanos-io/thanos/pkg/extprom"
    extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http"
    "github.com/thanos-io/thanos/pkg/logging"
    "github.com/thanos-io/thanos/pkg/prober"
    "github.com/thanos-io/thanos/pkg/queryfrontend"
    httpserver "github.com/thanos-io/thanos/pkg/server/http"
    "github.com/thanos-io/thanos/pkg/server/http/middleware"
    "github.com/thanos-io/thanos/pkg/tracing"
)
 
type queryFrontendConfig struct {
    http                 httpConfig // HTTP 服务配置
    webDisableCORS       bool       // 是否禁用CORS
    queryfrontend.Config            // 查询前端配置
    orgIdHeaders         []string   // 组织ID头部
}
 
// registerQueryFrontend 函数用于在 extkingpin 应用中注册查询前端组件的相关配置和命令。
//
// 参数:
// app: extkingpin.App 类型,表示要注册命令的应用实例。
func registerQueryFrontend(app *extkingpin.App) {
    // 定义组件名称
    comp := component.QueryFrontend
    // 添加命令,用于启动查询前端服务。
    cmd := app.Command(comp.String(), "Query frontend command implements a service deployed in front of queriers to improve query parallelization and caching.")
 
    // 定义配置结构体
    cfg := &queryFrontendConfig{
        Config: queryfrontend.Config{
            // 最大请求体大小为10 MiB
            // Max body size is 10 MiB.
            CortexHandlerConfig: &transport.HandlerConfig{
                MaxBodySize: 10 * 1024 * 1024,
            },
            // 查询范围配置
            QueryRangeConfig: queryfrontend.QueryRangeConfig{
                Limits: &cortexvalidation.Limits{},
            },
            // 查询配置
            LabelsConfig: queryfrontend.LabelsConfig{
                Limits: &cortexvalidation.Limits{},
            },
        },
    }
 
    // 注册HTTP相关标志
    cfg.http.registerFlag(cmd)
 
    // --web.disable-cors,无论是否禁用CORS,默认都是允许的。
    cmd.Flag("web.disable-cors", "Whether to disable CORS headers to be set by Thanos. By default Thanos sets CORS headers to be allowed by all.").
        Default("false").BoolVar(&cfg.webDisableCORS)
 
    // Query range tripperware flags.
    // --query-range.align-range-with-step, 默认情况下,会将传入的查询范围与其步长对齐以更好地缓存。注意:Grafana仪表板默认会这样做。
    cmd.Flag("query-range.align-range-with-step", "Mutate incoming queries to align their start and end with their step for better cache-ability. Note: Grafana dashboards do that by default.").
        Default("true").BoolVar(&cfg.QueryRangeConfig.AlignRangeWithStep)
 
    // --query-range.request-downsampled,默认情况下,查询范围请求将请求原始数据,而不是从缓存中获取。如果请求为空或未完成,则将请求下采样数据。
    cmd.Flag("query-range.request-downsampled", "Make additional query for downsampled data in case of empty or incomplete response to range request.").
        Default("true").BoolVar(&cfg.QueryRangeConfig.RequestDownsampled)
 
    // --query-range.split-interval,默认情况下,会将查询范围请求拆分为24小时的间隔并在并行中执行。注意:Grafana仪表板默认会这样做。
    cmd.Flag("query-range.split-interval", "Split query range requests by an interval and execute in parallel, it should be greater than 0 when query-range.response-cache-config is configured.").
        Default("24h").DurationVar(&cfg.QueryRangeConfig.SplitQueriesByInterval)
 
    // --query-range.max-retries,默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。
    cmd.Flag("query-range.max-retries-per-request", "Maximum number of retries for a single query range request; beyond this, the downstream error is returned.").
        Default("5").IntVar(&cfg.QueryRangeConfig.MaxRetries)
 
    // --query-range.max-query-length,默认情况下,查询范围请求的最大时间范围是1天。注册查询范围请求最大时间范围标志
    cmd.Flag("query-range.max-query-length", "Limit the query time range (end - start time) in the query-frontend, 0 disables it.").
        Default("0").DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxQueryLength))
 
    // --query-range.max-query-parallelism, 默认情况下,查询范围请求将并行执行14个。注册查询范围请求并行执行标志
    cmd.Flag("query-range.max-query-parallelism", "Maximum number of query range requests will be scheduled in parallel by the Frontend.").
        Default("14").IntVar(&cfg.QueryRangeConfig.Limits.MaxQueryParallelism)
 
    // --query-range.response-cache-max-freshness, 默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。
    cmd.Flag("query-range.response-cache-max-freshness", "Most recent allowed cacheable result for query range requests, to prevent caching very recent results that might still be in flux.").
        Default("1m").DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxCacheFreshness))
 
    // --query-range.partial-response: 设置查询范围请求的默认部分响应策略。
    // 如果未在请求中指定 partial_response 参数,则启用此策略。
    // 使用 --no-query-range.partial-response 可禁用该策略。
    cmd.Flag("query-range.partial-response", "Enable partial response for query range requests if no partial_response param is specified. Use --no-query-range.partial-response to disable.").
        Default("true").BoolVar(&cfg.QueryRangeConfig.PartialResponseStrategy)
 
    // --query-range.response-cache-config, 注册查询范围请求响应缓存配置标志
    cfg.QueryRangeConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-range.response-cache-config", "YAML file that contains response cache configuration.", extflag.WithEnvSubstitution())
 
    // Labels tripperware flags.
    // --labels.split-interval,注册标签请求的拆分间隔标志,该标志用于将标签请求按间隔拆分并并行执行。
    cmd.Flag("labels.split-interval", "Split labels requests by an interval and execute in parallel, it should be greater than 0 when labels.response-cache-config is configured.").
        Default("24h").DurationVar(&cfg.LabelsConfig.SplitQueriesByInterval)
 
    // --labels.max-retries-per-request, 注册标签请求的最大重试次数标志,默认情况下,标签请求将重试5次。
    cmd.Flag("labels.max-retries-per-request", "Maximum number of retries for a single label/series API request; beyond this, the downstream error is returned.").
        Default("5").IntVar(&cfg.LabelsConfig.MaxRetries)
 
    // --labels.max-query-parallelism,注册标签请求最大并行数标志,默认情况下,标签请求将并行执行14个。
    cmd.Flag("labels.max-query-parallelism", "Maximum number of labels requests will be scheduled in parallel by the Frontend.").
        Default("14").IntVar(&cfg.LabelsConfig.Limits.MaxQueryParallelism)
 
    // --labels.response-cache-max-freshness,注册标签请求的响应缓存最大新鲜度标志,该标志用于防止缓存非常新鲜的结果,这些结果可能仍在变化。
    cmd.Flag("labels.response-cache-max-freshness", "Most recent allowed cacheable result for labels requests, to prevent caching very recent results that might still be in flux.").
        Default("1m").DurationVar((*time.Duration)(&cfg.LabelsConfig.Limits.MaxCacheFreshness))
 
    // --labels.partial-response, 注册标签请求的局部响应标志,默认情况下,标签请求将返回部分响应。使用 --no-labels.partial-response 可禁用该策略。
    cmd.Flag("labels.partial-response", "Enable partial response for labels requests if no partial_response param is specified. --no-labels.partial-response for disabling.").
        Default("true").BoolVar(&cfg.LabelsConfig.PartialResponseStrategy)
 
    // --labels.default-time-range,注册标签请求的默认时间范围标志,该标志用于设置默认的标签请求时间范围。
    cmd.Flag("labels.default-time-range", "The default metadata time range duration for retrieving labels through Labels and Series API when the range parameters are not specified.").
        Default("24h").DurationVar(&cfg.DefaultTimeRange)
 
    // --labels.response-cache-config, 注册标签请求的响应缓存配置标志,该标志用于设置标签请求的响应缓存配置。
    cfg.LabelsConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "labels.response-cache-config", "YAML file that contains response cache configuration.", extflag.WithEnvSubstitution())
 
    // --cache-compression-type,注册缓存压缩类型标志,该标志用于设置在结果缓存中使用的压缩算法。支持的值包括 "snappy" 和 ""(禁用压缩)。
    cmd.Flag("cache-compression-type", "Use compression in results cache. Supported values are: 'snappy' and '' (disable compression).").
        Default("").StringVar(&cfg.CacheCompression)
 
    // --query-frontend.downstream-url,注册查询前端的下游URL标志,该标志用于设置查询前端的下游URL。
    cmd.Flag("query-frontend.downstream-url", "URL of downstream Prometheus Query compatible API.").
        Default("http://localhost:9090").StringVar(&cfg.DownstreamURL)
 
    // --query-frontend.downstream-tripper-config,注册查询前端的下游传输器配置标志,该标志用于设置查询前端的下游传输器配置。YAML文件包含传输器配置。如果下游URL是localhost或127.0.0.1,则强烈建议使用此标志。
    cfg.DownstreamTripperConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-frontend.downstream-tripper-config", "YAML file that contains downstream tripper configuration. If your downstream URL is localhost or 127.0.0.1 then it is highly recommended to increase max_idle_conns_per_host to at least 100.", extflag.WithEnvSubstitution())
 
    // --query-frontend.compress-responses, 注册压缩HTTP响应标志
    cmd.Flag("query-frontend.compress-responses", "Compress HTTP responses.").
        Default("false").BoolVar(&cfg.CompressResponses)
 
    // --query-frontend.log-queries-longer-than, 日志查询持续时间标志,该标志用于设置日志查询持续时间。设置为0将禁用此功能。设置为小于0的值将在所有查询上启用。
    cmd.Flag("query-frontend.log-queries-longer-than", "Log queries that are slower than the specified duration. "+
        "Set to 0 to disable. Set to < 0 to enable on all queries.").Default("0").DurationVar(&cfg.CortexHandlerConfig.LogQueriesLongerThan)
 
    // --query-frontend.org-id-header, 注册组织ID头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头的列表。默认情况下为空。
    cmd.Flag("query-frontend.org-id-header", "Request header names used to identify the source of slow queries (repeated flag). "+
        "The values of the header will be added to the org id field in the slow query log. "+
        "If multiple headers match the request, the first matching arg specified will take precedence. "+
        "If no headers match 'anonymous' will be used.").PlaceHolder("<http-header-name>").StringsVar(&cfg.orgIdHeaders)
 
    // --query-frontend.forward-headers, 注册转发头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头列表。默认情况下为空。
    cmd.Flag("query-frontend.forward-header", "List of headers forwarded by the query-frontend to downstream queriers, default is empty").PlaceHolder("<http-header-name>").StringsVar(&cfg.ForwardHeaders)
 
    // --log.request.decision, 注册请求日志记录决策标志,该标志用于设置查询前端的请求日志记录策略。默认情况下为空。 支持的值为:"LogFinishCall"。 支持的值为:"NoLogCall"、"LogFinishCall"和"LogStartAndFinishCall"。 默认情况下为空。 "NoLogCall": 禁用请求日志记录。"LogFinishCall": 日志请求的完成调用。"LogStartAndFinishCall": 日志请求的开始和结束调用。
    cmd.Flag("log.request.decision", "Deprecation Warning - This flag would be soon deprecated, and replaced with `request.logging-config`. Request Logging for logging the start and end of requests. By default this flag is disabled. LogFinishCall : Logs the finish call of the requests. LogStartAndFinishCall : Logs the start and finish call of the requests. NoLogCall : Disable request logging.").Default("").EnumVar(&cfg.RequestLoggingDecision, "NoLogCall", "LogFinishCall", "LogStartAndFinishCall", "")
 
    // 注册请求日志记录配置
    reqLogConfig := extkingpin.RegisterRequestLoggingFlags(cmd)
 
    // 设置命令执行逻辑
    cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {
        // 解析请求日志记录配置
        httpLogOpts, err := logging.ParseHTTPOptions(cfg.RequestLoggingDecision, reqLogConfig)
        if err != nil {
            return errors.Wrap(err, "error while parsing config for request logging")
        }
 
        // 运行查询前端
        return runQueryFrontend(g, logger, reg, tracer, httpLogOpts, cfg, comp)
    })
}
 
// 定义一个函数parseTransportConfiguration,它接受一个字节切片downstreamTripperConfContentYaml作为输入,并返回一个指向http.Transport的指针和一个error对象。这个函数的作用是解析传输配置。如果downstreamTripperConfContentYaml为空,则直接返回一个默认配置的http.Transport对象。否则,它会尝试将YAML格式的内容解析到tripperConfig结构体中,并使用这个配置创建一个http.Transport对象。如果解析失败,它会返回一个错误。
// parseTransportConfiguration 解析YAML格式的下游传输配置,并返回一个配置好的 http.Transport 对象。
//
// 参数:
//
//  downstreamTripperConfContentYaml: YAML格式的下游传输配置内容
//
// 返回值:
//
//  *http.Transport: 配置好的 http.Transport 对象
//  error: 如果解析过程中出现错误,则返回错误信息
func parseTransportConfiguration(downstreamTripperConfContentYaml []byte) (*http.Transport, error) {
    // 创建一个新的http.Transport实例,这里假设exthttp.NewTransport()是一个封装或扩展了标准http.NewTransport()的函数,可能添加了一些额外的配置或功能。这个新创建的实例被赋值给downstreamTripper变量。
    downstreamTripper := exthttp.NewTransport()
 
    // 检查输入的YAML配置内容是否非空。如果为空,则不应用任何配置,直接返回默认配置的http.Transport实例。
    if len(downstreamTripperConfContentYaml) > 0 {
        // 创建一个queryfrontend.DownstreamTripperConfig类型的实例,这个类型是一个结构体,预期包含了一些用于配置http.Transport的字段。这个实例被赋值给tripperConfig变量。
        tripperConfig := &queryfrontend.DownstreamTripperConfig{}
        // 使用yaml.UnmarshalStrict函数将YAML格式的配置内容解析到tripperConfig结构体中。如果解析过程中发生错误,则返回一个错误。
        if err := yaml.UnmarshalStrict(downstreamTripperConfContentYaml, tripperConfig); err != nil {
            // 如果解析YAML文件时出错,则使用errors.Wrap函数包装错误,并返回nil和错误信息。
            return nil, errors.Wrap(err, "parsing downstream tripper config YAML file")
        }
 
        // 根据tripperConfig中的配置设置downstreamTripper的各项参数
        if tripperConfig.IdleConnTimeout > 0 {
            // 设置空闲连接超时时间
            downstreamTripper.IdleConnTimeout = time.Duration(tripperConfig.IdleConnTimeout)
        }
        if tripperConfig.ResponseHeaderTimeout > 0 {
            // 设置响应头超时时间
            downstreamTripper.ResponseHeaderTimeout = time.Duration(tripperConfig.ResponseHeaderTimeout)
        }
        if tripperConfig.TLSHandshakeTimeout > 0 {
            // 设置TLS握手超时时间
            downstreamTripper.TLSHandshakeTimeout = time.Duration(tripperConfig.TLSHandshakeTimeout)
        }
        if tripperConfig.ExpectContinueTimeout > 0 {
            // 设置期望继续超时时间
            downstreamTripper.ExpectContinueTimeout = time.Duration(tripperConfig.ExpectContinueTimeout)
        }
        if tripperConfig.MaxIdleConns != nil {
            // 设置最大空闲连接数
            downstreamTripper.MaxIdleConns = *tripperConfig.MaxIdleConns
        }
        if tripperConfig.MaxIdleConnsPerHost != nil {
            // 设置每主机最大空闲连接数
            downstreamTripper.MaxIdleConnsPerHost = *tripperConfig.MaxIdleConnsPerHost
        }
        if tripperConfig.MaxConnsPerHost != nil {
            // 设置每主机最大连接数
            downstreamTripper.MaxConnsPerHost = *tripperConfig.MaxConnsPerHost
        }
    }
 
    // 返回配置好的downstreamTripper对象
    return downstreamTripper, nil
}
 
// runQueryFrontend 函数用于启动查询前端服务
func runQueryFrontend(
    g *run.Group, // 运行组,用于管理服务的启动和停止
    logger log.Logger, // 日志记录器,用于记录日志信息
    reg *prometheus.Registry, // Prometheus注册表,用于注册和收集指标数据
    tracer opentracing.Tracer, // 链路追踪器,用于追踪请求的执行过程
    httpLogOpts []logging.Option, // HTTP日志选项,用于配置HTTP请求的日志记录行为
    cfg *queryFrontendConfig, // 查询前端配置,包含各种服务运行所需的参数和选项
    comp component.Component, // 组件,用于管理服务的启动和停止
) error {
    // 获取查询范围缓存配置内容
    queryRangeCacheConfContentYaml, err := cfg.QueryRangeConfig.CachePathOrContent.Content()
    if err != nil {
        return err
        // 如果配置内容不为空,则初始化查询范围缓存配置
    }
    if len(queryRangeCacheConfContentYaml) > 0 {
        // 初始化查询范围缓存配置
        cacheConfig, err := queryfrontend.NewCacheConfig(logger, queryRangeCacheConfContentYaml)
        if err != nil {
            return errors.Wrap(err, "initializing the query range cache config")
        }
        // 设置查询范围缓存配置, cfg.QueryRangeConfig.ResultsCacheConfig 是一个指向 queryrange.ResultsCacheConfig 的指针,它包含了压缩和缓存配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。
        cfg.QueryRangeConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{
            Compression: cfg.CacheCompression,
            CacheConfig: *cacheConfig,
        }
    }
 
    // 获取标签缓存配置内容
    labelsCacheConfContentYaml, err := cfg.LabelsConfig.CachePathOrContent.Content()
    if err != nil {
        return err
    }
    if len(labelsCacheConfContentYaml) > 0 {
        // 初始化标签缓存配置
        cacheConfig, err := queryfrontend.NewCacheConfig(logger, labelsCacheConfContentYaml)
        if err != nil {
            return errors.Wrap(err, "initializing the labels cache config")
        }
        // 设置标签缓存配置, cfg.LabelsConfig 是一个指向 queryfrontend.LabelsConfig 的指针,它包含了标签缓存的配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。
        cfg.LabelsConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{
            Compression: cfg.CacheCompression,
            CacheConfig: *cacheConfig,
        }
    }
 
    // 验证配置
    if err := cfg.Validate(); err != nil {
        return errors.Wrap(err, "error validating the config")
    }
 
    // 初始化tripperware, tripperware 是一个用于处理 HTTP 请求的中间件,它可以将请求传递给下游的 HTTP 服务。这里使用 queryfrontend.NewTripperware 函数初始化 tripperware,传入配置、注册表和日志记录器。这里将 cfg.Config 作为配置参数,reg 和 logger 分别作为注册表和日志记录器的参数。如果初始化失败,则返回错误信息。
    tripperWare, err := queryfrontend.NewTripperware(cfg.Config, reg, logger)
    if err != nil {
        return errors.Wrap(err, "setup tripperwares")
    }
 
    // 获取下游传输配置内容, 获取下游传输配置内容,并将其解析为传输配置。如果解析失败,则返回错误信息。
    downstreamTripperConfContentYaml, err := cfg.DownstreamTripperConfig.CachePathOrContent.Content()
    if err != nil {
        return err
    }
 
    // 解析下游传输配置, 使用 parseTransportConfiguration 函数将下游传输配置内容解析为 http.Transport 对象。如果解析失败,则返回错误信息。如果下游传输配置内容为空,则直接使用默认的 http.Transport 对象。
    downstreamTripper, err := parseTransportConfiguration(downstreamTripperConfContentYaml)
    if err != nil {
        return err
    }
 
    // 创建下游往返器
    roundTripper, err := cortexfrontend.NewDownstreamRoundTripper(cfg.DownstreamURL, downstreamTripper)
    if err != nil {
        return errors.Wrap(err, "setup downstream roundtripper")
    }
 
    // 将下游往返器包装到查询前端Tripperware中
    roundTripper = tripperWare(roundTripper)
 
    // 创建查询前端传输
    handler := transport.NewHandler(*cfg.CortexHandlerConfig, roundTripper, logger, nil)
    if cfg.CompressResponses {
        handler = gziphandler.GzipHandler(handler)
    }
 
    // 创建HTTP探针
    httpProbe := prober.NewHTTP()
    statusProber := prober.Combine(
        httpProbe,
        prober.NewInstrumentation(comp, logger, extprom.WrapRegistererWithPrefix("thanos_", reg)),
    )
 
    // 配置HTTP调用的请求日志记录
    logMiddleware := logging.NewHTTPServerMiddleware(logger, httpLogOpts...)
    ins := extpromhttp.NewInstrumentationMiddleware(reg, nil)
 
    // 启动HTTP服务器以收集指标
    {
        srv := httpserver.New(logger, reg, comp, httpProbe,
            httpserver.WithListen(cfg.http.bindAddress),
            httpserver.WithGracePeriod(time.Duration(cfg.http.gracePeriod)),
            httpserver.WithTLSConfig(cfg.http.tlsConfig),
        )
 
        // 配置HTTP处理函数
        instr := func(f http.HandlerFunc) http.HandlerFunc {
            hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                orgId := extractOrgId(cfg, r)
                name := "query-frontend"
                if !cfg.webDisableCORS {
                    api.SetCORS(w)
                }
                tracing.HTTPMiddleware(
                    tracer,
                    name,
                    logger,
                    ins.NewHandler(
                        name,
                        gziphandler.GzipHandler(
                            middleware.RequestID(
                                logMiddleware.HTTPMiddleware(name, f),
                            ),
                        ),
                    ),
                    // Cortex前端中间件需要orgID
                ).ServeHTTP(w, r.WithContext(user.InjectOrgID(r.Context(), orgId)))
            })
            return hf
        }
        srv.Handle("/", instr(handler.ServeHTTP))
 
        // 添加服务器启动和关闭逻辑到组中
        g.Add(func() error {
            statusProber.Healthy()
 
            return srv.ListenAndServe()
        }, func(err error) {
            statusProber.NotReady(err)
            defer statusProber.NotHealthy(err)
 
            srv.Shutdown(err)
        })
    }
 
    level.Info(logger).Log("msg", "starting query frontend")
    statusProber.Ready()
    return nil
}
 
// extractOrgId 从HTTP请求中提取组织ID
//
// 参数:
//
//  conf *queryFrontendConfig: 配置结构体指针,包含组织ID头部列表
//  r *http.Request: HTTP请求结构体指针
//
// 返回值:
//
//  string: 提取的组织ID字符串,如果未找到则返回"anonymous"
func extractOrgId(conf *queryFrontendConfig, r *http.Request) string {
    // 遍历conf.orgIdHeaders切片中的每个元素。每个元素(这里命名为header)都是一个字符串,代表可能包含组织ID的HTTP请求头名称。
    for _, header := range conf.orgIdHeaders {
        // 通过r.Header.Get(header)方法从HTTP请求r的头部中获取名为header的值,并将这个值存储在变量headerVal中。r.Header是一个http.Header类型的映射,它允许通过键(这里是HTTP请求头的名称)来获取对应的值(这里是HTTP请求头的值)。
        headerVal := r.Header.Get(header)
        // 检查变量headerVal是否不为空字符串。如果不为空,意味着在当前的请求头中找到了一个有效的组织ID值。在这种情况下,直接返回这个值作为组织ID。
        if headerVal != "" {
            return headerVal
        }
    }
    // 如果遍历完conf.orgIdHeaders中列出的所有请求头后,没有找到任何有效的组织ID值,函数返回字符串"anonymous"。这表示请求没有明确指定组织ID,因此默认将其视为匿名请求。
    return "anonymous"
}
posted @   左扬  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
历史上的今天:
2022-02-12 Go从入门到精通——数组(固定大小的连续空间)
levels of contents
点击右上角即可分享
微信分享提示