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

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

https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/query.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
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
 
package main
 
import (
    "context"
    "fmt"
    "math"
    "net/http"
    "strconv"
    "strings"
    "time"
 
    "github.com/go-kit/log"
    "github.com/go-kit/log/level"
    grpc_logging "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
    "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/tags"
    "github.com/oklog/run"
    "github.com/opentracing/opentracing-go"
    "github.com/pkg/errors"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promauto"
    "github.com/prometheus/common/route"
    "github.com/prometheus/prometheus/discovery/file"
    "github.com/prometheus/prometheus/discovery/targetgroup"
    "github.com/prometheus/prometheus/model/labels"
    "github.com/prometheus/prometheus/promql"
 
    apiv1 "github.com/thanos-io/thanos/pkg/api/query"
    "github.com/thanos-io/thanos/pkg/compact/downsample"
    "github.com/thanos-io/thanos/pkg/component"
    "github.com/thanos-io/thanos/pkg/discovery/cache"
    "github.com/thanos-io/thanos/pkg/discovery/dns"
    "github.com/thanos-io/thanos/pkg/exemplars"
    "github.com/thanos-io/thanos/pkg/extgrpc"
    "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/gate"
    "github.com/thanos-io/thanos/pkg/info"
    "github.com/thanos-io/thanos/pkg/info/infopb"
    "github.com/thanos-io/thanos/pkg/logging"
    "github.com/thanos-io/thanos/pkg/metadata"
    "github.com/thanos-io/thanos/pkg/prober"
    "github.com/thanos-io/thanos/pkg/query"
    "github.com/thanos-io/thanos/pkg/rules"
    "github.com/thanos-io/thanos/pkg/runutil"
    grpcserver "github.com/thanos-io/thanos/pkg/server/grpc"
    httpserver "github.com/thanos-io/thanos/pkg/server/http"
    "github.com/thanos-io/thanos/pkg/store"
    "github.com/thanos-io/thanos/pkg/store/labelpb"
    "github.com/thanos-io/thanos/pkg/targets"
    "github.com/thanos-io/thanos/pkg/tls"
    "github.com/thanos-io/thanos/pkg/ui"
)
 
const (
    promqlNegativeOffset = "promql-negative-offset" // 这个是PromQL查询中负偏移量的配置项,用于指定查询的起始时间点相对于当前时间的偏移量。
    promqlAtModifier     = "promql-at-modifier"     // 这个是PromQL查询中“at”修饰符的配置项,用于指定查询的时间点。
    queryPushdown        = "query-pushdown"         // 这个是查询下推的配置项,用于指定是否启用查询下推功能。
)
 
// registerQuery registers a query command.
// registerQuery 函数用于将Thanos Query组件注册到extkingpin.App中。
// 该函数通过app参数接收一个指向extkingpin.App的指针,并对其进行配置,以支持Thanos Query的相关功能。
/*
这段代码实现了Thanos查询组件的命令行参数注册和配置。具体功能包括:
 
1、初始化命令:
    1.1、创建命令对象cmd,并设置命令描述。
2、注册HTTP和gRPC相关的配置项:
    2.1、注册HTTP绑定地址、优雅关闭时间、TLS配置等。
    2.2、注册gRPC绑定地址、优雅关闭时间、TLS证书、密钥、CA证书、最大连接年龄等。
3、注册查询相关的配置项:
    3.1、包括查询超时时间、最大并发请求数、回溯时间、动态回溯时间、最大并发选择请求数、副本标签、即时查询默认最大源分辨率、元数据默认时间范围等。
4、注册Web相关的配置项:
    4.1、包括路由前缀、外部前缀、前缀头名称、是否禁用CORS等。
5、注册TLS相关的配置项:
    5.1、包括是否启用TLS、是否跳过证书验证、客户端TLS证书、私钥、CA证书、服务器名称等。
6、注册其他高级配置项:
    6.1、包括自动降采样、部分响应(查询、规则、目标、指标元数据、示例)、默认评估间隔、默认范围查询步长、存储响应超时等。
7、解析命令行参数并启动服务:
    7.1、解析命令行参数,设置默认值,进行日志配置,创建文件发现对象,检查路由前缀和外部前缀的一致性,最终调用runQuery函数启动查询服务。
*/
func registerQuery(app *extkingpin.App) {
    comp := component.Query
    cmd := app.Command(comp.String(), "Query node exposing PromQL enabled Query API with data retrieved from multiple store nodes.")
 
    // 注册查询相关的配置项,包括查询超时时间、最大并发请求数等。
    httpBindAddr, httpGracePeriod, httpTLSConfig := extkingpin.RegisterHTTPFlags(cmd)
    // 注册gRPC相关的配置项,包括绑定地址、优雅关闭时间等。
    grpcBindAddr, grpcGracePeriod, grpcCert, grpcKey, grpcClientCA, grpcMaxConnAge := extkingpin.RegisterGRPCFlags(cmd)
 
    // cmd.Flag, 这是Cobra库中用于定义命令行标志的方法。它允许你为命令行应用添加配置选项。
 
    // --grpc-client-tls-secure, 注册查询组件的配置项,包括查询超时时间、最大并发请求数等。
    secure := cmd.Flag("grpc-client-tls-secure", "Use TLS when talking to the gRPC server").Default("false").Bool()
    // --grpc-client-tls-skip-verify, 注册gRPC客户端TLS配置的配置项,包括是否启用TLS、证书验证等。
    skipVerify := cmd.Flag("grpc-client-tls-skip-verify", "Disable TLS certificate verification i.e self signed, signed by fake CA").Default("false").Bool()
    // --grpc-client-tls-cert, 注册gRPC客户端TLS证书和密钥的配置项,包括证书文件路径、私钥文件路径等。
    cert := cmd.Flag("grpc-client-tls-cert", "TLS Certificates to use to identify this client to the server").Default("").String()
    // --grpc-client-tls-key, 注册gRPC客户端TLS密钥的配置项,包括私钥文件路径等。
    key := cmd.Flag("grpc-client-tls-key", "TLS Key for the client's certificate").Default("").String()
    // --"grpc-client-tls-ca, 注册gRPC客户端TLS CA证书的配置项,包括CA证书文件路径等。
    caCert := cmd.Flag("grpc-client-tls-ca", "TLS CA Certificates to use to verify gRPC servers").Default("").String()
    // --grpc-client-server-name, 注册gRPC客户端TLS服务器名称的配置项,包括要验证返回的gRPC证书的主机名的服务器名称。
    serverName := cmd.Flag("grpc-client-server-name", "Server name to verify the hostname on the returned gRPC certificates. See https://tools.ietf.org/html/rfc4366#section-3.1").Default("").String()
 
    // --web.route-prefix, 注册Web外部前缀的配置项,用于设置UI查询web界面中所有HTML链接和重定向URL的静态前缀。实际端点仍然在/或web.route-prefix。这允许Thanos UI在URL子路径后面提供服务。默认值为--web.external-prefix。
    webRoutePrefix := cmd.Flag("web.route-prefix", "Prefix for API and UI endpoints. This allows thanos UI to be served on a sub-path. Defaults to the value of --web.external-prefix. This option is analogous to --web.route-prefix of Prometheus.").Default("").String()
    // --web.external-prefix, 注册Web外部前缀的配置项,用于设置UI查询web界面中所有HTML链接和重定向URL的静态前缀。实际端点仍然在/或web.
    webExternalPrefix := cmd.Flag("web.external-prefix", "Static prefix for all HTML links and redirect URLs in the UI query web interface. Actual endpoints are still served on / or the web.route-prefix. This allows thanos UI to be served behind a reverse proxy that strips a URL sub-path.").Default("").String()
    // --web.prefix-header, 注册Web前缀头名称的配置项,用于设置HTTP请求头的名称,该请求头用于动态地添加UI链接和重定向的前缀。默认情况下,此选项被忽略。
    webPrefixHeaderName := cmd.Flag("web.prefix-header", "Name of HTTP request header used for dynamic prefixing of UI links and redirects. This option is ignored if web.external-prefix argument is set. Security risk: enable this option only if a reverse proxy in front of thanos is resetting the header. The --web.prefix-header=X-Forwarded-Prefix option can be useful, for example, if Thanos UI is served via Traefik reverse proxy with PathPrefixStrip option enabled, which sends the stripped prefix value in X-Forwarded-Prefix header. This allows thanos UI to be served on a sub-path.").Default("").String()
    // --web.disable-cors, 注册Web禁用CORS的配置项,用于设置是否禁用Thanos设置的CORS头部。默认情况下,Thanos会为所有请求设置CORS头部。
    webDisableCORS := 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").Bool()
 
    // --log.request.decision, 注册查询超时的配置项,用于设置查询处理的最大时间。默认值为10分钟。
    reqLogDecision := 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("").Enum("NoLogCall", "LogFinishCall", "LogStartAndFinishCall", "")
 
    // --query.timeout, 注册查询超时的配置项,用于设置查询处理的最大时间。默认值为2分钟。
    queryTimeout := extkingpin.ModelDuration(cmd.Flag("query.timeout", "Maximum time to process query by query node.").
        Default("2m"))
 
    // --query.max-concurrent, 注册查询最大并发数的配置项,用于设置查询节点可以同时处理的查询的最大数量。默认值为20。
    maxConcurrentQueries := cmd.Flag("query.max-concurrent", "Maximum number of queries processed concurrently by query node.").
        Default("20").Int()
 
    // --query.lookback-delta, 注册查询回溯时间的配置项,用于设置在表达式评估期间检索指标的最大时间。默认值为5分钟。
    lookbackDelta := cmd.Flag("query.lookback-delta", "The maximum lookback duration for retrieving metrics during expression evaluations. PromQL always evaluates the query for the certain timestamp (query range timestamps are deduced by step). Since scrape intervals might be different, PromQL looks back for given amount of time to get latest sample. If it exceeds the maximum lookback delta it assumes series is stale and returns none (a gap). This is why lookback delta should be set to at least 2 times of the slowest scrape interval. If unset it will use the promql default of 5m.").Duration()
 
    // --query.dynamic-lookback-delta, 注册查询动态回溯时间的配置项,用于设置是否允许根据分辨率对查询使用更大的回溯时间。默认值为true。
    dynamicLookbackDelta := cmd.Flag("query.dynamic-lookback-delta", "Allow for larger lookback duration for queries based on resolution.").Hidden().Default("true").Bool()
 
    // 注册查询最大并发选择请求数的配置项,用于设置每个查询可以同时发出的选择请求的最大数量。默认值为4。
    maxConcurrentSelects := cmd.Flag("query.max-concurrent-select", "Maximum number of select requests made concurrently per a query.").
        Default("4").Int()
 
    // --query.replica-label, 注册查询副本标签的配置项,用于设置在数据去重时作为副本指示器的标签。默认值为空列表。
    queryReplicaLabels := cmd.Flag("query.replica-label", "Labels to treat as a replica indicator along which data is deduplicated. Still you will be able to query without deduplication using 'dedup=false' parameter. Data includes time series, recording rules, and alerting rules.").
        Strings()
 
    // --query.instant.default.max_source_resolution, 注册查询即时查询默认最大源分辨率的配置项,用于设置在即时查询中使用的最大源数据解析度。默认值为0秒,表示仅考虑原始解析度。
    instantDefaultMaxSourceResolution := extkingpin.ModelDuration(cmd.Flag("query.instant.default.max_source_resolution", "default value for max_source_resolution for instant queries. If not set, defaults to 0s only taking raw resolution into account. 1h can be a good value if you use instant queries over time ranges that incorporate times outside of your raw-retention.").Default("0s").Hidden())
 
    // --query.metadata.default-time-range,它有一个默认值0s,表示当通过Labels和Series API检索标签且未指定时间范围参数时,默认的时间范围是从开始到现在。
    defaultMetadataTimeRange := cmd.Flag("query.metadata.default-time-range", "The default metadata time range duration for retrieving labels through Labels and Series API when the range parameters are not specified. The zero value means range covers the time since the beginning.").Default("0s").Duration()
 
    // --query.selector-label, 注册查询选择器标签的配置项,用于设置在信息端点中公开的查询选择器标签。默认值为空列表。
    selectorLabels := cmd.Flag("selector-label", "Query selector labels that will be exposed in info endpoint (repeated).").
        PlaceHolder("<name>=\"<value>\"").Strings()
    // --endpoint, 注册Thanos API服务器地址的配置项,用于设置静态配置的Thanos API服务器的地址。默认值为空列表。
    endpoints := extkingpin.Addrs(cmd.Flag("endpoint", "Addresses of statically configured Thanos API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect Thanos API servers through respective DNS lookups.").
        PlaceHolder("<endpoint>"))
    // --store, 注册静态配置的存储API服务器地址的配置项,用于设置静态配置的存储API服务器的地址。默认值为空列表。
    stores := extkingpin.Addrs(cmd.Flag("store", "Deprecation Warning - This flag is deprecated and replaced with `endpoint`. Addresses of statically configured store API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect store API servers through respective DNS lookups.").
        PlaceHolder("<store>"))
 
    // TODO(bwplotka): Hidden because we plan to extract discovery to separate API: https://github.com/thanos-io/thanos/issues/2600.
    // --rule, 注册规则API服务器地址的配置项,用于设置静态配置的规则API服务器的地址。默认值为空列表。
    ruleEndpoints := extkingpin.Addrs(cmd.Flag("rule", "Deprecation Warning - This flag is deprecated and replaced with `endpoint`. Experimental: Addresses of statically configured rules API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect rule API servers through respective DNS lookups.").
        Hidden().PlaceHolder("<rule>"))
 
    // --metadata, 注册元数据API服务器地址的配置项,用于设置静态配置的元数据API服务器的地址。默认值为空列表。
    metadataEndpoints := extkingpin.Addrs(cmd.Flag("metadata", "Deprecation Warning - This flag is deprecated and replaced with `endpoint`. Experimental: Addresses of statically configured metadata API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect metadata API servers through respective DNS lookups.").
        Hidden().PlaceHolder("<metadata>"))
    // --exemplar, 注册示例API服务器地址的配置项,用于设置静态配置的示例API服务器的地址。默认值为空列表。
    exemplarEndpoints := extkingpin.Addrs(cmd.Flag("exemplar", "Deprecation Warning - This flag is deprecated and replaced with `endpoint`. Experimental: Addresses of statically configured exemplars API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect exemplars API servers through respective DNS lookups.").
        Hidden().PlaceHolder("<exemplar>"))
 
    // TODO(atunik): Hidden because we plan to extract discovery to separate API: https://github.com/thanos-io/thanos/issues/2600.
    // --target, 注册目标API服务器地址的配置项,用于设置静态配置的目标API服务器的地址。默认值为空列表。
    targetEndpoints := extkingpin.Addrs(cmd.Flag("target", "Deprecation Warning - This flag is deprecated and replaced with `endpoint`. Experimental: Addresses of statically configured target API servers (repeatable). The scheme may be prefixed with 'dns+' or 'dnssrv+' to detect target API servers through respective DNS lookups.").
        Hidden().PlaceHolder("<target>"))
    // --store-strict, 注册严格存储API服务器地址的配置项,用于设置静态配置的仅在健康检查失败时也始终使用的存储API服务器的地址。默认值为空列表。
    strictStores := cmd.Flag("store-strict", "Deprecation Warning - This flag is deprecated and replaced with `endpoint-strict`. Addresses of only statically configured store API servers that are always used, even if the health check fails. Useful if you have a caching layer on top.").
        PlaceHolder("<staticstore>").Strings()
    // --endpoint-strict, 注册严格Thanos API服务器地址的配置项,用于设置静态配置的仅在健康检查失败时也始终使用的Thanos API服务器的地址。默认值为空列表。
    strictEndpoints := cmd.Flag("endpoint-strict", "Addresses of only statically configured Thanos API servers that are always used, even if the health check fails. Useful if you have a caching layer on top.").
        PlaceHolder("<staticendpoint>").Strings()
    // --store.sd-files, 注册存储服务发现文件路径的配置项,用于设置包含存储API服务器地址的文件路径。默认值为空列表。
    fileSDFiles := cmd.Flag("store.sd-files", "Path to files that contain addresses of store API servers. The path can be a glob pattern (repeatable).").
        PlaceHolder("<path>").Strings()
    // --store.sd-interval, 注册存储服务发现文件刷新间隔的配置项,用于设置重新读取包含存储API服务器地址的文件的时间间隔。默认值为"5m"。
    fileSDInterval := extkingpin.ModelDuration(cmd.Flag("store.sd-interval", "Refresh interval to re-read file SD files. It is used as a resync fallback.").
        Default("5m"))
 
    // TODO(bwplotka): Grab this from TTL at some point.
    // --store.sd-dns, 注册存储服务发现DNS配置的配置项,用于设置用于从DNS解析存储API服务器地址的配置。默认值为空列表。
    dnsSDInterval := extkingpin.ModelDuration(cmd.Flag("store.sd-dns-interval", "Interval between DNS resolutions.").
        Default("30s"))
    // --store.sd-dns-resolver, 注册存储服务发现DNS解析器的配置项,用于设置用于从DNS解析存储API服务器地址的解析器。默认值为"miekgdns"。
    dnsSDResolver := cmd.Flag("store.sd-dns-resolver", fmt.Sprintf("Resolver to use. Possible options: [%s, %s]", dns.GolangResolverType, dns.MiekgdnsResolverType)).
        Default(string(dns.MiekgdnsResolverType)).Hidden().String()
    // --store.unhealthy-timeout, 注册存储API服务器不健康超时的配置项,用于设置在从Thanos UI页面清除不健康的存储之前的时间间隔。默认值为"5m"。
    unhealthyStoreTimeout := extkingpin.ModelDuration(cmd.Flag("store.unhealthy-timeout", "Timeout before an unhealthy store is cleaned from the store UI page.").Default("5m"))
    // --query.auto-downsampling, 注册查询自动下采样的配置项,用于启用或禁用在存储网关中根据源数据的最大分辨率参数自动调整使用哪个数据源的功能。默认值为"false"。
    enableAutodownsampling := cmd.Flag("query.auto-downsampling", "Enable automatic adjustment (step / 5) to what source of data should be used in store gateways if no max_source_resolution param is specified.").
        Default("false").Bool()
    // --query.partial-response, 注册查询部分响应的配置项,用于启用或禁用在未指定partial_response参数的情况下对查询进行部分响应的功能。默认值为"true
    enableQueryPartialResponse := cmd.Flag("query.partial-response", "Enable partial response for queries if no partial_response param is specified. --no-query.partial-response for disabling.").
        Default("true").Bool()
    // --rule.partial-response, 注册规则部分响应的配置项,用于启用或禁用在未指定partial_response参数的情况下对规则查询进行部分响应的功能。默认值为"true"。
    enableRulePartialResponse := cmd.Flag("rule.partial-response", "Enable partial response for rules endpoint. --no-rule.partial-response for disabling.").
        Hidden().Default("true").Bool()
    // --target.partial-response, 注册目标部分响应的配置项,用于启用或禁用在未指定partial_response参数的情况下对目标查询进行部分响应的功能。默认值为"true"。
    enableTargetPartialResponse := cmd.Flag("target.partial-response", "Enable partial response for targets endpoint. --no-target.partial-response for disabling.").
        Hidden().Default("true").Bool()
    // --metric-metadata.partial-response, 注册指标元数据部分响应的配置项,用于启用或禁用在未指定partial_response参数的情况下对指标元数据进行部分响应的功能。默认值为"true"。
    enableMetricMetadataPartialResponse := cmd.Flag("metric-metadata.partial-response", "Enable partial response for metric metadata endpoint. --no-metric-metadata.partial-response for disabling.").
        Hidden().Default("true").Bool()
    // --enable-feature, 注册启用功能的配置项,用于启用或禁用实验功能。默认值为空列表。
    featureList := cmd.Flag("enable-feature", "Comma separated experimental feature names to enable.The current list of features is "+queryPushdown+".").Default("").Strings()
    // --examplar.partial-response, 注册示例部分响应的配置项,用于启用或禁用在未指定partial_response参数的情况下对示例查询进行部分响应的功能。默认值为"true"。
    enableExemplarPartialResponse := cmd.Flag("exemplar.partial-response", "Enable partial response for exemplar endpoint. --no-exemplar.partial-response for disabling.").
        Hidden().Default("true").Bool()
    // --query.default-evaluation-interval, 注册查询默认评估间隔的配置项,用于设置子查询的默认评估间隔。默认值为"1m"。
    defaultEvaluationInterval := extkingpin.ModelDuration(cmd.Flag("query.default-evaluation-interval", "Set default evaluation interval for sub queries.").Default("1m"))
    // --query.default-step, 注册查询默认步长的配置项,用于设置范围查询的默认步长。默认值为"1s"。
    defaultRangeQueryStep := extkingpin.ModelDuration(cmd.Flag("query.default-step", "Set default step for range queries. Default step is only used when step is not set in UI. In such cases, Thanos UI will use default step to calculate resolution (resolution = max(rangeSeconds / 250, defaultStep)). This will not work from Grafana, but Grafana has __step variable which can be used.").
        Default("1s"))
    // --store.response-timeout, 注册存储响应超时的配置项,用于设置在忽略未发送任何数据的存储之前的时间间隔。默认值为"0ms"。
    storeResponseTimeout := extkingpin.ModelDuration(cmd.Flag("store.response-timeout", "If a Store doesn't send any data in this specified duration then a Store will be ignored and partial data will be returned if it's enabled. 0 disables timeout.").Default("0ms"))
    reqLogConfig := extkingpin.RegisterRequestLoggingFlags(cmd)
    // --alert.query-url, 注册告警查询URL的配置项,用于设置告警查询的URL。默认值为空字符串。
    alertQueryURL := cmd.Flag("alert.query-url", "The external Thanos Query URL that would be set in all alerts 'Source' field.").String()
 
    // cmd.Setup 注册查询的配置项,用于设置查询的配置项。
    cmd.Setup(
        func(
            g *run.Group, //  g *run.Group类型的参数g,用于管理服务的启动和停止。
            logger log.Logger, // logger log.Logger类型的参数logger,用于记录日志。
            reg *prometheus.Registry, // reg *prometheus.Registry类型的参数reg,用于注册Prometheus指标。
            tracer opentracing.Tracer, // tracer opentracing.Tracer类型的参数tracer,用于追踪请求。
            _ <-chan struct{}, // _ <-chan struct{}类型的参数,用于接收停止信号。
            _ bool) error { //
            selectorLset, err := parseFlagLabels(*selectorLabels) // 将命令行参数中的选择器标签解析为labels.Labels类型。
            if err != nil {
                return errors.Wrap(err, "parse federation labels") // 如果解析失败,则返回错误。
            }
 
            //
            var enableQueryPushdown bool
 
            // 遍历启用的实验性功能列表。
            for _, feature := range *featureList {
                // 如果列表中包含 queryPushdown 功能,则启用该功能。
                if feature == queryPushdown {
                    enableQueryPushdown = true
                }
                // 如果列表中包含promqlAtModifier功能,
                // 则记录警告信息,因为该功能现在已永久启用,无需额外指定。
                if feature == promqlAtModifier {
                    // promqlAtModifier功能现已永久启用,因此无需在 --enable-feature 中指定。
                    level.Warn(logger).Log("msg", "This option for --enable-feature is now permanently enabled and therefore a no-op.", "option", promqlAtModifier)
                }
                // 如果列表中包含负偏移量(promqlNegativeOffset)功能,
                // 则记录警告信息,因为该功能现在已永久启用,无需额外指定。
                if feature == promqlNegativeOffset {
                    // 负偏移量功能现已永久启用,因此无需在 --enable-feature 中指定。
                    level.Warn(logger).Log("msg", "This option for --enable-feature is now permanently enabled and therefore a no-op.", "option", promqlNegativeOffset)
                }
            }
 
            // httpLogOpts HTTP日志选项,用于配置HTTP请求的日志记录选项。
            httpLogOpts, err := logging.ParseHTTPOptions(*reqLogDecision, reqLogConfig)
            if err != nil {
                return errors.Wrap(err, "error while parsing config for request logging")
            }
            // grpcLogOpts gRPC日志选项,用于配置gRPC请求的日志记录选项。 tagOpts tag选项,用于配置gRPC请求的标签。
            tagOpts, grpcLogOpts, err := logging.ParsegRPCOptions(*reqLogDecision, reqLogConfig)
            if err != nil {
                return errors.Wrap(err, "error while parsing config for request logging")
            }
 
            // fileSD file服务发现,用于配置文件服务发现的选项。
            var fileSD *file.Discovery
            // 如果文件服务发现选项不为空,则创建文件服务发现对象。
            if len(*fileSDFiles) > 0 {
                // 初始化文件服务发现的配置。
                conf := &file.SDConfig{
                    Files:           *fileSDFiles,
                    RefreshInterval: *fileSDInterval,
                }
                // 创建文件服务发现对象。
                fileSD = file.NewDiscovery(conf, logger)
            }
 
            // 如果web路由前缀为空,则将其设置为外部前缀。
            if *webRoutePrefix == "" {
                *webRoutePrefix = *webExternalPrefix
            }
 
            // 如果web路由前缀和外部前缀不同,则记录警告信息。
            if *webRoutePrefix != *webExternalPrefix {
                // 记录警告信息,--web.route-prefix and --web.external-prefix 的值不同时,提示用户在没有反向代理的情况下,Web UI可能无法正常工作。
                level.Warn(logger).Log("msg", "different values for --web.route-prefix and --web.external-prefix detected, web UI may not work without a reverse-proxy.")
            }
 
            return runQuery(
                g,                                     // g *run.Group类型的参数g,用于管理服务的启动和停止。
                logger,                                // logger log.Logger类型的参数logger,用于记录日志。
                reg,                                   // reg *prometheus.Registry类型的参数reg,用于注册Prometheus指标。
                tracer,                                // tracer opentracing.Tracer类型的参数tracer,用于追踪请求。
                httpLogOpts,                           // httpLogOpts HTTP日志选项,用于配置HTTP请求的日志记录选项。
                grpcLogOpts,                           //   grpcLogOpts gRPC日志选项,用于配置gRPC请求的日志记录选项。
                tagOpts,                               // tagOpts tag选项,用于配置gRPC请求的标签。
                *grpcBindAddr,                         // *grpcBindAddr string类型的参数,用于指定gRPC服务的绑定地址。
                time.Duration(*grpcGracePeriod),       // grpcGracePeriod time.Duration类型的参数,用于指定gRPC服务的优雅关闭时间。
                *grpcCert,                             // grpcCert string类型的参数,用于指定gRPC服务的证书文件路径。
                *grpcKey,                              // grpcKey string类型的参数,用于指定gRPC服务的密钥文件路径。
                *grpcClientCA,                         // grpcClientCA string类型的参数,用于指定gRPC服务的客户端证书颁发机构文件路径。
                *grpcMaxConnAge,                       // grpcMaxConnAge time.Duration类型的参数,用于指定gRPC服务连接的最大存活时间。
                *secure,                               // secure bool类型的参数,用于指定是否启用HTTPS。
                *skipVerify,                           // skipVerify bool类型的参数,用于指定是否跳过证书验证。
                *cert,                                 // cert string类型的参数,用于指定HTTPS证书文件路径。
                *key,                                  // key string类型的参数,用于指定HTTPS密钥文件路径。
                *caCert,                               // caCert string类型的参数,用于指定HTTPS证书颁发机构文件路径。
                *serverName,                           //   serverName string类型的参数,用于指定HTTPS服务器的名称。
                *httpBindAddr,                         // httpBindAddr string类型的参数,用于指定HTTP服务的绑定地址。
                *httpTLSConfig,                        //   httpTLSConfig string类型的参数,用于指定HTTP服务的TLS配置。
                time.Duration(*httpGracePeriod),       // httpGracePeriod time.Duration类型的参数,用于指定HTTP服务的优雅关闭时间。
                *webRoutePrefix,                       // webRoutePrefix string类型的参数,用于指定Web路由的前缀。
                *webExternalPrefix,                    // webExternalPrefix string类型的参数,用于指定Web路由的外部前缀。
                *webPrefixHeaderName,                  // webPrefixHeaderName string类型的参数,用于指定Web路由的前缀头名称。
                *maxConcurrentQueries,                 // maxConcurrentQueries int类型的参数,用于指定最大并发查询数。
                *maxConcurrentSelects,                 // maxConcurrentSelects int类型的参数,用于指定最大并发查询数。
                time.Duration(*defaultRangeQueryStep), // defaultRangeQueryStep time.Duration类型的参数,用于指定默认范围查询的步长。
                time.Duration(*queryTimeout),          // queryTimeout time.Duration类型的参数,用于指定查询超时时间。
                *lookbackDelta,                        // lookbackDelta time.Duration类型的参数,用于指定查询回溯时间。
                *dynamicLookbackDelta,                 // dynamicLookbackDelta time.Duration类型的参数,用于指定动态查询回溯时间。
                time.Duration(*defaultEvaluationInterval),         // defaultEvaluationInterval time.Duration类型的参数,用于指定默认评估间隔。
                time.Duration(*storeResponseTimeout),              // storeResponseTimeout time.Duration类型的参数,用于指定存储响应超时时间。
                *queryReplicaLabels,                               // queryReplicaLabels string类型的参数,用于指定查询副本标签。
                selectorLset,                                      // selectorLset labels.Labels类型的参数,用于指定选择器标签。
                getFlagsMap(cmd.Flags()),                          // getFlagsMap(cmd.Flags()) AppClause类型的参数,用于获取命令行标志的映射。
                *endpoints,                                        //   endpoints string类型的参数,用于指定查询端点。
                *stores,                                           // stores string类型的参数,用于指定存储节点。
                *ruleEndpoints,                                    // ruleEndpoints string类型的参数,用于指定规则端点。
                *targetEndpoints,                                  // targetEndpoints string类型的参数,用于指定目标端点。
                *metadataEndpoints,                                // metadataEndpoints string类型的参数,用于指定元数据端点。
                *exemplarEndpoints,                                // exemplarEndpoints string类型的参数,用于指定示例端点。
                *enableAutodownsampling,                           // enableAutodownsampling bool类型的参数,用于指定是否启用自动下采样。
                *enableQueryPartialResponse,                       // enableQueryPartialResponse bool类型的参数,用于指定是否启用部分查询响应。
                *enableRulePartialResponse,                        // enableRulePartialResponse bool类型的参数,用于指定是否启用部分规则响应。
                *enableTargetPartialResponse,                      // enableTargetPartialResponse bool类型的参数,用于指定是否启用部分目标响应。
                *enableMetricMetadataPartialResponse,              // enableMetricMetadataPartialResponse bool类型的参数,用于指定是否启用部分元数据响应。
                *enableExemplarPartialResponse,                    // enableExemplarPartialResponse bool类型的参数,用于指定是否启用部分示例响应。
                fileSD,                                            // fileSD *file.Discovery类型的参数,用于指定文件服务发现。
                time.Duration(*dnsSDInterval),                     // dnsSDInterval time.Duration类型的参数,用于指定DNS服务发现的间隔。
                *dnsSDResolver,                                    // dnsSDResolver string类型的参数,用于指定DNS服务发现的解析器。
                time.Duration(*unhealthyStoreTimeout),             // unhealthyStoreTimeout time.Duration类型的参数,用于指定不健康存储的超时时间。
                time.Duration(*instantDefaultMaxSourceResolution), // instantDefaultMaxSourceResolution time.Duration类型的参数,用于指定默认最大源分辨率。
                *defaultMetadataTimeRange,                         // defaultMetadataTimeRange string类型的参数,用于指定默认元数据时间范围。
                *strictStores,                                     // strictStores string类型的参数,用于指定严格存储节点。
                *strictEndpoints,                                  // strictEndpoints string类型的参数,用于指定严格端点。
                *webDisableCORS,                                   // webDisableCORS bool类型的参数,用于指定是否禁用Web跨源资源共享。
                enableQueryPushdown,                               // enableQueryPushdown bool类型的参数,用于指定是否启用查询下推。
                *alertQueryURL,                                    // alertQueryURL string类型的参数,用于指定警报查询URL。
                component.Query,                                   // component.Query AppClause类型的参数,用于查询组件。
            )
        })
}
 
// runQuery starts a server that exposes PromQL Query API. It is responsible for querying configured
// store nodes, merging and duplicating the data to satisfy user query.
// runQuery 函数启动一个服务器,该服务器暴露PromQL查询API。它负责查询配置的存储节点,合并和去重数据以满足用户查询需求。
func runQuery(
    g *run.Group, // g 是 run.Group 类型的参数,用于管理服务的启动和停止。
    logger log.Logger, // logger 是 log.Logger 类型的参数,用于记录日志。
    reg *prometheus.Registry, // reg 是 prometheus.Registry 类型的参数,用于注册Prometheus指标。
    tracer opentracing.Tracer, // tracer 是 opentracing.Tracer 类型的参数,用于追踪请求。
    httpLogOpts []logging.Option, // httpLogOpts 是 logging.Option 类型的切片,用于配置HTTP请求日志。
    grpcLogOpts []grpc_logging.Option, // grpcLogOpts 是 grpc_logging.Option 类型的切片,用于配置gRPC请求日志。
    tagOpts []tags.Option, // tagOpts 是 tags.Option 类型的切片,用于配置gRPC标签。
    grpcBindAddr string, // grpcBindAddr 是 gRPC 服务器的绑定地址。
    grpcGracePeriod time.Duration, // grpcGracePeriod 是 gRPC 服务器的优雅关闭时间。
    grpcCert string, // grpcCert 是 gRPC 服务器的TLS证书文件路径。
    grpcKey string, // grpcKey 是 gRPC 服务器的TLS密钥文件路径。
    grpcClientCA string, // grpcClientCA 是 gRPC 客户端的CA证书文件路径。
    grpcMaxConnAge time.Duration, // grpcMaxConnAge 是 gRPC 连接的最大存活时间。
    secure bool, // secure 表示是否启用gRPC服务器的TLS。
    skipVerify bool, // skipVerify 表示是否跳过gRPC客户端的TLS证书验证。
    cert string, // cert 是 gRPC 客户端的TLS证书文件路径。
    key string, // key 是 gRPC 客户端的TLS密钥文件路径。
    caCert string, // caCert 是 gRPC 客户端的CA证书文件路径。
    serverName string, // serverName 是 gRPC 服务器的主机名,用于TLS证书验证。
    httpBindAddr string, // httpBindAddr 是 HTTP 服务器的绑定地址。
    httpTLSConfig string, // httpTLSConfig 是 HTTP 服务器的TLS配置文件路径。
    httpGracePeriod time.Duration, // httpGracePeriod 是 HTTP 服务器的优雅关闭时间。
    webRoutePrefix string, // webRoutePrefix 是API和UI端点的路由前缀。
    webExternalPrefix string, // webExternalPrefix 是UI中所有HTML链接和重定向URL的静态前缀。
    webPrefixHeaderName string, // webPrefixHeaderName 是用于动态前缀的HTTP请求头名称。
    maxConcurrentQueries int, // maxConcurrentQueries 是查询节点可以同时处理的查询最大数量。
    maxConcurrentSelects int, // maxConcurrentSelects 是每个查询可以同时发出的选择请求的最大数量。
    defaultRangeQueryStep time.Duration, // defaultRangeQueryStep 是范围查询的默认步长。
    queryTimeout time.Duration, // queryTimeout 是查询处理的最大时间。
    lookbackDelta time.Duration, // lookbackDelta 是检索指标时的最大回溯时间。
    dynamicLookbackDelta bool, // dynamicLookbackDelta 表示是否允许根据分辨率动态调整回溯时间。
    defaultEvaluationInterval time.Duration, // defaultEvaluationInterval 是子查询的默认评估间隔。
    storeResponseTimeout time.Duration, // storeResponseTimeout 是忽略未发送任何数据的存储的时间间隔。
    queryReplicaLabels []string, // queryReplicaLabels 是用于数据去重的副本标签列表。
    selectorLset labels.Labels, // selectorLset 是查询选择器标签集。
    flagsMap map[string]string, // flagsMap 是命令行标志的映射。
    endpointAddrs []string, // endpointAddrs 是静态配置的Thanos API服务器地址列表。
    storeAddrs []string, // storeAddrs 是静态配置的存储API服务器地址列表。
    ruleAddrs []string, // ruleAddrs 是静态配置的规则API服务器地址列表。
    targetAddrs []string, // targetAddrs 是静态配置的目标API服务器地址列表。
    metadataAddrs []string, // metadataAddrs 是静态配置的元数据API服务器地址列表。
    exemplarAddrs []string, // exemplarAddrs 是静态配置的示例API服务器地址列表。
    enableAutodownsampling bool, // enableAutodownsampling 表示是否启用自动降采样。
    enableQueryPartialResponse bool, // enableQueryPartialResponse 表示是否启用查询部分响应。
    enableRulePartialResponse bool, // enableRulePartialResponse 表示是否启用规则部分响应。
    enableTargetPartialResponse bool, // enableTargetPartialResponse 表示是否启用目标部分响应。
    enableMetricMetadataPartialResponse bool, // enableMetricMetadataPartialResponse 表示是否启用指标元数据部分响应。
    enableExemplarPartialResponse bool, // enableExemplarPartialResponse 表示是否启用示例部分响应。
    fileSD *file.Discovery, // fileSD 是文件服务发现对象。
    dnsSDInterval time.Duration, // dnsSDInterval 是DNS服务发现的刷新间隔。
    dnsSDResolver string, // dnsSDResolver 是DNS服务发现的解析器类型。
    unhealthyStoreTimeout time.Duration, // unhealthyStoreTimeout 是存储不健康超时时间。
    instantDefaultMaxSourceResolution time.Duration, // instantDefaultMaxSourceResolution 是即时查询的默认最大源分辨率。
    defaultMetadataTimeRange time.Duration, // defaultMetadataTimeRange 是检索标签时的默认元数据时间范围。
    strictStores []string, // strictStores 是仅在健康检查失败时也始终使用的存储API服务器地址列表。
    strictEndpoints []string, // strictEndpoints 是仅在健康检查失败时也始终使用的Thanos API服务器地址列表。
    disableCORS bool, // disableCORS 表示是否禁用CORS头部。
    enableQueryPushdown bool, // enableQueryPushdown 表示是否启用查询下推功能。
    alertQueryURL string, // alertQueryURL 是告警查询的URL。
    comp component.Component, // comp 是组件类型,表示这是一个查询组件。
) error {
    // alertQueryURL 是告警查询的URL,用于在PromQL查询中引用。如果未设置,则默认为本地地址和端口。
    if alertQueryURL == "" {
        // lastColon 查找最后一个冒号的位置,以便从httpBindAddr中提取端口。如果存在冒号,则使用该端口构建alertQueryURL。
        lastColon := strings.LastIndex(httpBindAddr, ":")
        if lastColon != -1 {
            // 如果存在冒号,则从httpBindAddr中提取端口并构建alertQueryURL。
            alertQueryURL = fmt.Sprintf("http://localhost:%s", httpBindAddr[lastColon+1:])
        }
        // NOTE(GiedriusS): default is set in config.ts.
    }
    // TODO(bplotka in PR #513 review): Move arguments into struct.
    // duplicatedStores 是一个Prometheus指标,用于记录在查询过程中从不同配置中检测到的重复存储地址的总数。
    // 这个指标可以帮助我们监控和调试Thanos查询组件,确保没有因为配置错误而导致数据查询问题。
    duplicatedStores := promauto.With(reg).NewCounter(prometheus.CounterOpts{
        // 指标名称,用于在Prometheus中唯一标识这个指标。
        Name: "thanos_query_duplicated_store_addresses_total",
        // 指标的帮助信息,描述了这个指标的作用和含义。
        Help: "The number of times a duplicated store addresses is detected from the different configs in query",
    })
 
    // dialOpts 是一个切片,包含了用于建立gRPC客户端连接的选项。这些选项包括日志记录器、注册器、追踪器等配置项。
    dialOpts, err := extgrpc.StoreClientGRPCOpts(logger, reg, tracer, secure, skipVerify, cert, key, caCert, serverName)
    if err != nil {
        return errors.Wrap(err, "building gRPC client")
    }
 
    // fileSDCache 是一个缓存对象,用于存储从文件服务发现中解析出的目标组信息。它可以帮助减少重复的解析操作,提高查询效率。
    fileSDCache := cache.New()
    // dnsStoreProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析存储API的地址。它可以帮助Thanos查询组件自动发现和更新后端存储服务的地址列表。
    dnsStoreProvider := dns.NewProvider(
        logger, // logger 是用于记录日志的日志记录器。
        extprom.WrapRegistererWithPrefix("thanos_query_store_apis_", reg), // extprom.WrapRegistererWithPrefix 是一个函数,用于在注册器(reg)上添加前缀("thanos_query_store_apis_"),并返回一个新的注册器。这个新的注册器将用于记录与DNS服务发现相关的指标。
        dns.ResolverType(dnsSDResolver),                                   // dns.ResolverType 是一个函数,用于设置DNS解析器的类型。这里传入的是 dnsSDResolver 的值,它决定了使用哪种类型的DNS解析器来发现存储API的地址。
    )
 
    // strictStores 是一个字符串切片,包含了在严格模式下始终使用的存储API服务器地址列表。这些地址在严格模式下不会被动态服务发现覆盖,即使它们出现在DNS记录中。
    for _, store := range strictStores {
        // dns.IsDynamicNode 是一个函数,用于检查给定的存储地址是否是通过DNS动态解析的。如果是的话,它会返回true;否则返回false。
        if dns.IsDynamicNode(store) {
            // 如果在严格模式下检测到动态指定的存储地址,则返回一个错误。这是因为严格模式不允许使用DNS服务发现来自动解析存储地址。
            return errors.Errorf("%s is a dynamically specified store i.e. it uses SD and that is not permitted under strict mode. Use --store for this", store)
        }
    }
 
    // strictEndpoints 是一个字符串切片,包含了在严格模式下始终使用的Thanos API服务器地址列表。这些地址在严格模式下不会被动态服务发现覆盖,即使它们出现在DNS记录中。
    for _, endpoint := range strictEndpoints {
        // dns.IsDynamicNode 是一个函数,用于检查给定的Thanos API服务器地址是否是通过DNS动态解析的。如果是的话,它会返回true;否则返回false。
        if dns.IsDynamicNode(endpoint) {
            // 如果在严格模式下检测到动态指定的Thanos API服务器地址,则返回一个错误。这是因为严格模式不允许使用DNS服务发现来自动解析Thanos API的地址。
            return errors.Errorf("%s is a dynamically specified endpoint i.e. it uses SD and that is not permitted under strict mode. Use --endpoint for this", endpoint)
        }
    }
 
    // dnsEndpointProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析Thanos API的地址。它可以帮助Thanos查询组件自动发现和更新后端API服务的地址列表。
    dnsEndpointProvider := dns.NewProvider(
        logger,
        extprom.WrapRegistererWithPrefix("thanos_query_endpoints_", reg),
        dns.ResolverType(dnsSDResolver),
    )
 
    // dnsRuleProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析规则API的地址。它可以帮助Thanos查询组件自动发现和更新后端规则服务的地址列表。
    dnsRuleProvider := dns.NewProvider(
        logger,
        extprom.WrapRegistererWithPrefix("thanos_query_rule_apis_", reg),
        dns.ResolverType(dnsSDResolver),
    )
 
    // dnsTargetProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析目标API的地址。它可以帮助Thanos查询组件自动发现和更新后端目标服务的地址列表
    dnsTargetProvider := dns.NewProvider(
        logger,
        extprom.WrapRegistererWithPrefix("thanos_query_target_apis_", reg),
        dns.ResolverType(dnsSDResolver),
    )
 
    // dnsMetadataProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析元数据API的地址。它可以帮助Thanos查询组件自动发现和更新后端元数据服务的地址列表。
    dnsMetadataProvider := dns.NewProvider(
        logger,
        extprom.WrapRegistererWithPrefix("thanos_query_metadata_apis_", reg),
        dns.ResolverType(dnsSDResolver),
    )
 
    // dnsExemplarProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析示例API的地址。它可以帮助Thanos查询组件自动发现和更新后端示例服务的地址
    dnsExemplarProvider := dns.NewProvider(
        logger,
        extprom.WrapRegistererWithPrefix("thanos_query_exemplar_apis_", reg),
        dns.ResolverType(dnsSDResolver),
    )
 
    var (
        // query.NewEndpointSet 创建一个新的查询端点集,用于管理Thanos查询组件的后端存储、API和规则服务的地址列表。
        endpoints = query.NewEndpointSet(
            logger,
            reg,
            func() (specs []*query.GRPCEndpointSpec) {
                // Add strict & static nodes.
                // strictStores 包含了在严格模式下始终使用的存储API服务器地址列表。对于每个这样的地址,我们创建一个新的GRPCEndpointSpec对象,并将其加入specs切片中。
                for _, addr := range strictStores {
                    // NewGRPCEndpointSpec 创建一个新的GRPCEndpointSpec对象,该对象包含了存储API服务器的地址和是否为严格模式的信息。
                    // specs 是一个切片,用于存储创建的GRPCEndpointSpec对象。对于每个地址,我们创建一个新的GRPCEndpointSpec对象,并将其加入specs切片中。
                    specs = append(specs, query.NewGRPCEndpointSpec(addr, true))
                }
                // strictEndpoints 包含了在严格模式下始终使用的Thanos API服务器地址列表。对于每个这样的地址,我们创建一个新的GRPCEndpointSpec对象,并将其加入specs切片中。
                for _, addr := range strictEndpoints {
                    // specs 是一个切片,用于存储创建的GRPCEndpointSpec对象。对于每个地址,我们创建一个新的GRPCEndpointSpec对象,并将其加入specs切片中。
                    specs = append(specs, query.NewGRPCEndpointSpec(addr, true))
                }
                // 从DNS服务发现提供者中获取地址,并为每个地址创建一个新的GRPCEndpointSpec对象。然后,将这些对象加入specs切片中。为什么呢?
                // 这是因为DNS服务发现提供者可以帮助Thanos查询组件自动从DNS服务器动态解析存储、API和规则服务的地址列表。通过这种方式,我们可以确保Thanos查询组件能够根据后端服务的地址列表动态更新。
                for _, dnsProvider := range []*dns.Provider{
                    dnsStoreProvider,    // dnsStoreProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析存储API的地址。
                    dnsRuleProvider,     // dnsRuleProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析规则API的地址。
                    dnsExemplarProvider, // dnsExemplarProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析示例API的地址。
                    dnsMetadataProvider, // dnsMetadataProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析元数据API的地址。
                    dnsTargetProvider,   // dnsTargetProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析目标API的地址。
                    dnsEndpointProvider, // dnsEndpointProvider 是一个DNS服务发现提供者,用于从DNS服务器动态解析Thanos API的地址。
                } {
                    // []*query.GRPCEndpointSpec 是一个切片,用于存储创建的GRPCEndpointSpec对象。
                    var tmpSpecs []*query.GRPCEndpointSpec
                    // dnsProvider.Addresses 是一个函数,用于从DNS服务发现提供者中获取地址列表。这里我们调用它来获取所有通过该提供者解析出的地址。
                    for _, addr := range dnsProvider.Addresses() {
                        tmpSpecs = append(tmpSpecs, query.NewGRPCEndpointSpec(addr, false))
                    }
                    // removeDuplicateEndpointSpecs 是一个函数,用于从给定的GRPCEndpointSpec切片中移除重复的地址。它可以帮助我们确保Thanos查询组件不会因为配置错误而导致数据查询问题。
                    tmpSpecs = removeDuplicateEndpointSpecs(logger, duplicatedStores, tmpSpecs)
                    specs = append(specs, tmpSpecs...)
                }
 
                return specs
            },
            dialOpts,              // dialOpts 是一个切片,包含了用于建立gRPC客户端连接的选项。这些选项包括日志记录器、注册器、追踪器等配置项。
            unhealthyStoreTimeout, // unhealthyStoreTimeout 是一个持续时间,用于设置在认为存储API服务器不健康之前等待的时间。如果在这个时间内没有收到来自该服务器的响应,则将其视为不健康状态。
        )
        // proxy 是一个代理存储对象,用于将查询请求转发到后端存储API服务器。它可以帮助Thanos查询组件实现负载均衡和故障转移等功能。
        proxy = store.NewProxyStore(logger, reg, endpoints.GetStoreClients, component.Query, selectorLset, storeResponseTimeout)
        // rulesProxy 是一个代理规则对象,用于将查询请求转发到后端规则API服务器。它可以帮助Thanos查询组件实现负载均衡和故障转移等功能。
        rulesProxy = rules.NewProxy(logger, endpoints.GetRulesClients)
        // targetsProxy 是一个代理目标对象,用于将查询请求转发到后端目标API服务器。它可以帮助Thanos查询组件实现负载均衡和故障转移等功能。
        targetsProxy = targets.NewProxy(logger, endpoints.GetTargetsClients)
        // metadataProxy 是一个代理元数据对象,用于将查询请求转发到后端元数据API服务器。它可以帮助Thanos查询组件实现负载均衡和故障转移等功能。
        metadataProxy = metadata.NewProxy(logger, endpoints.GetMetricMetadataClients)
        // exemplarsProxy 是一个代理示例对象,用于将查询请求转发到后端示例API服务器。它可以帮助Thanos查询组件实现负载均衡和故障转移等功能。
        exemplarsProxy = exemplars.NewProxy(logger, endpoints.GetExemplarsStores, selectorLset)
        // queryableCreator 是一个查询创建器对象,用于根据给定的参数创建一个新的查询实例。它可以帮助Thanos查询组件实现灵活的查询功能。
        queryableCreator = query.NewQueryableCreator(
            logger, // logger 是一个日志记录器对象,用于记录查询相关的日志信息。它可以帮助我们记录查询过程中的关键信息,如请求的发起、响应的处理等。
            extprom.WrapRegistererWithPrefix("thanos_query_", reg), // extprom.WrapRegistererWithPrefix 是一个函数,用于在注册器上添加前缀。这里我们使用它来为Thanos查询组件的指标添加统一的命名空间和前缀。
            proxy,                // proxy 是一个代理存储对象,用于将查询请求转发到后端存储API服务器。
            maxConcurrentSelects, // maxConcurrentSelects 是一个整数,用于设置同时执行的选择查询的最大数量。这可以帮助Thanos查询组件控制并发度,避免过多的资源竞争和性能问题。
            queryTimeout,         // queryTimeout 是一个持续时间,用于设置查询请求的超时时间。如果在这个时间内没有得到响应,则认为该请求失败。
        )
        // engineOpts 是一个查询引擎选项对象,用于配置PromQL查询引擎的行为。它可以帮助Thanos查询组件实现灵活的查询功能,如设置超时时间、最大样本数等
        engineOpts = promql.EngineOpts{
            Logger: logger, // logger 是一个日志记录器对象,用于记录查询相关的日志信息。
            Reg:    reg,    // reg 是一个注册器对象,用于收集和暴露指标。它可以帮助我们监控Thanos查询组件的运行状态、性能等关键信息。
            // TODO(bwplotka): Expose this as a flag: https://github.com/thanos-io/thanos/issues/703.
            MaxSamples:    math.MaxInt32, // maxSamples 是一个整数,用于设置查询结果中允许的最大样本数。这可以帮助我们控制内存使用和性能开销。
            Timeout:       queryTimeout,  // timeout 是一个持续时间,用于设置查询请求的超时时间。如果在这个时间内没有得到响应,则认为该请求失败。
            LookbackDelta: lookbackDelta, // lookbackDelta 是一个持续时间,用于设置查询请求的回溯时间。这可以帮助我们获取历史数据或进行实时监控等操作。
            // noStepSubqueryIntervalFn 是一个函数,用于设置在没有步长子查询的情况下使用的间隔时间。这可以帮助我们控制查询的精度和性能开销。
            NoStepSubqueryIntervalFn: func(int64) int64 {
                // defaultEvaluationInterval.Milliseconds() 返回默认评估间隔时间的毫秒数。这可以帮助我们控制查询的精度和性能开销。
                return defaultEvaluationInterval.Milliseconds()
            },
            EnableNegativeOffset: true, // EnableNegativeOffset 是一个布尔值,用于设置是否允许使用负偏移量。这可以帮助我们实现一些特殊的查询需求,如查询过去一段时间的数据。
            EnableAtModifier:     true, // EnableAtModifier 是一个布尔值,用于设置是否允许使用at修饰符。这可以帮助我们实现一些特殊的查询需求,如获取特定时间点的数据。
        }
    )
 
    // Periodically update the store set with the addresses we see in our cluster.
    // 定期更新存储集,以便我们可以获取最新的后端存储API服务器地址列表。这对于确保Thanos查询组件能够实时发现和连接新的服务实例非常重要。
    {
        // context.WithCancel 创建一个可取消的上下文对象。这里我们使用它来控制定期更新存储集的操作,以便我们可以随时停止这个操作
        ctx, cancel := context.WithCancel(context.Background())
        // g.Add 是一个函数,用于将一个goroutine添加到组中。这里我们使用它来启动定期更新存储集的操作。这样,我们就可以在需要时随时停止这个操作了。
        g.Add(func() error {
            // runutil.Repeat 是一个函数,用于重复执行一个操作。这里我们使用它来定期更新存储集的操作。这样,我们可以确保Thanos查询组件能够实时发现和连接新的服务实例。
            return runutil.Repeat(5*time.Second, ctx.Done(), func() error {
                // endpoints.Update 是一个函数,用于更新存储集。这里我们使用它来定期获取最新的后端存储API服务器地址列表,以便我们可以实时发现和连接新的服务实例。
                endpoints.Update(ctx)
                return nil
            })
        }, func(error) {
            cancel()          // cancel 是一个函数,用于取消可取消的上下文对象。用来停止定期更新存储集的操作。
            endpoints.Close() // Close 是一个函数,用于关闭存储集。用来确保定期更新存储集的操作在停止时能够正确地清理资源
        })
    }
 
    // Run File Service Discovery and update the store set when the files are modified.
    // 运行文件服务发现,并定期更新存储集。当文件被修改时,这可以确保Thanos查询组件能够实时发现和连接新的服务实例。
    if fileSD != nil {
        // fileSDUpdates 是一个通道,用于接收文件服务发现的更新。这些更新包含最新的后端存储API服务器地址列表。
        var fileSDUpdates chan []*targetgroup.Group
        // ctxRun, cancelRun 是一个可取消的上下文对象,用于控制文件服务发现的运行。这允许我们在需要时停止文件服务发现。
        ctxRun, cancelRun := context.WithCancel(context.Background())
 
        // 初始化 fileSDUpdates 通道,用于接收来自文件服务发现的更新。
        fileSDUpdates = make(chan []*targetgroup.Group)
 
        // 将文件服务发现的运行任务添加到运行组中。
        g.Add(func() error {
            // fileSD.Run 是一个函数,用于启动文件服务发现,并通过 fileSDUpdates 通道定期发送更新。
            fileSD.Run(ctxRun, fileSDUpdates)
            return nil
        }, func(error) {
            cancelRun() // // 在文件服务发现任务出错或需要停止时,调用 cancelRun 取消上下文。
        })
 
        // ctxUpdate, cancelUpdate 是另一个可取消的上下文对象,用于控制存储集的更新。
        ctxUpdate, cancelUpdate := context.WithCancel(context.Background())
        // 将存储集更新任务添加到运行组中。
        g.Add(func() error {
            for {
                select {
                case update := <-fileSDUpdates:
                    // Discoverers sometimes send nil updates so need to check for it to avoid panics.
                    // 检查更新是否为 nil,以避免 panic。
                    if update == nil {
                        continue
                    }
                    // 使用最新的更新来更新文件服务发现缓存。
                    fileSDCache.Update(update)
                    // 使用更新后的缓存来更新存储集。
                    endpoints.Update(ctxUpdate)
 
                    // 尝试解析并更新存储API服务器的地址,包括来自文件服务发现缓存和静态配置的地址。
                    if err := dnsStoreProvider.Resolve(ctxUpdate, append(fileSDCache.Addresses(), storeAddrs...)); err != nil {
                        // 如果解析失败,记录错误日志。
                        level.Error(logger).Log("msg", "failed to resolve addresses for storeAPIs", "err", err)
                    }
 
                    // Rules apis do not support file service discovery as of now.
                    // 注意:目前规则API不支持文件服务发现。因此,这里我们只更新了存储API服务器的地址。
                case <-ctxUpdate.Done():
                    // 如果 ctxUpdate 被取消,则退出循环。
                    return nil
                }
            }
        }, func(error) {
            // 在存储集更新任务出错或需要停止时,调用 cancelUpdate 取消上下文。
            cancelUpdate()
        })
    }
    // Periodically update the addresses from static flags and file SD by resolving them using DNS SD if necessary.
    // 定期更新地址,通过解析静态标志和文件服务发现中的地址,并在必要时使用DNS服务发现进行解析。
    {
        ctx, cancel := context.WithCancel(context.Background())
        // 将地址更新任务添加到运行组中。
        g.Add(func() error {
            return runutil.Repeat(dnsSDInterval, ctx.Done(), func() error {
                // resolveCtx, resolveCancel 是一个带超时的上下文对象,用于控制DNS解析的时间。这里我们使用它来限制DNS解析的时间,避免长时间阻塞。
                resolveCtx, resolveCancel := context.WithTimeout(ctx, dnsSDInterval)
                defer resolveCancel() // 确保在函数返回前调用 resolveCancel 以释放资源。
 
                // 尝试解析并更新存储API服务器的地址。
                if err := dnsStoreProvider.Resolve(resolveCtx, append(fileSDCache.Addresses(), storeAddrs...)); err != nil {
                    // 如果解析失败,记录错误日志。msg:无法解析 storeAPIs 服务器的地址。
                    level.Error(logger).Log("msg", "failed to resolve addresses for storeAPIs", "err", err)
                }
                // 尝试解析并更新规则API服务器的地址。
                if err := dnsRuleProvider.Resolve(resolveCtx, ruleAddrs); err != nil {
                    // 如果解析失败,记录错误日志。msg:无法解析 rulesAPIs 服务器的地址。
                    level.Error(logger).Log("msg", "failed to resolve addresses for rulesAPIs", "err", err)
                }
                // 尝试解析并更新目标API服务器的地址。
                if err := dnsTargetProvider.Resolve(ctx, targetAddrs); err != nil {
                    // 如果解析失败,记录错误日志。msg:无法解析 targetsAPIs 服务器的地址。
                    level.Error(logger).Log("msg", "failed to resolve addresses for targetsAPIs", "err", err)
                }
                // 尝试解析并更新元数据API服务器的地址。
                if err := dnsMetadataProvider.Resolve(resolveCtx, metadataAddrs); err != nil {
                    // 如果解析失败,记录错误日志。msg:无法解析 metadataAPIs 服务器的地址。
                    level.Error(logger).Log("msg", "failed to resolve addresses for metadataAPIs", "err", err)
                }
                // 尝试解析并更新示例API服务器的地址。
                if err := dnsExemplarProvider.Resolve(resolveCtx, exemplarAddrs); err != nil {
                    // 如果解析失败,记录错误日志。msg:无法解析 exemplarsAPI 服务器的地址。
                    level.Error(logger).Log("msg", "failed to resolve addresses for exemplarsAPI", "err", err)
                }
                // 尝试解析并更新Thanos API服务器的地址。
                if err := dnsEndpointProvider.Resolve(resolveCtx, endpointAddrs); err != nil {
                    // 如果解析失败,记录错误日志。注释:无法解析使用endpoint flag 传递的地址
                    level.Error(logger).Log("msg", "failed to resolve addresses passed using endpoint flag", "err", err)
 
                }
                return nil
            })
        }, func(error) {
            // 在地址更新任务出错或需要停止时,调用 cancel 取消上下文。
            cancel()
        })
    }
 
    // Start gRPC server, 初始化一个gRPC探测器,用于检查gRPC服务的可用性。
    grpcProbe := prober.NewGRPC()
    // Start HTTP server, 初始化一个HTTP探测器,用于检查HTTP服务的可用性。
    httpProbe := prober.NewHTTP()
    // 创建一个组合探测器,它将同时检查HTTP和gRPC服务的可用性。
    // 它还包含一个用于监控的仪器组件(Instrumentation),该组件将注册度量指标到Prometheus。
    statusProber := prober.Combine(
        httpProbe, // 将HTTP探测器添加到组合探测器中,以监控HTTP服务的可用性。
        grpcProbe, // 将gRPC探测器添加到组合探测器中,以监控gRPC服务的可用性。
        prober.NewInstrumentation(comp, logger, extprom.WrapRegistererWithPrefix("thanos_", reg)), // 注册度量指标到Prometheus。
    )
    // engineCreator 是一个函数,用于创建查询引擎实例。
    // 它接收一个创建新PromQL Engine的函数、引擎配置选项和一个动态查找时间差(dynamicLookbackDelta),并返回一个新的查询引擎。
    // 这个函数允许根据查询的需求动态选择适当的PromQL引擎。
    engineCreator := engineFactory(promql.NewEngine, engineOpts, dynamicLookbackDelta)
 
    // Start query API + UI HTTP server.
    // 初始化HTTP服务器以提供查询API和UI。
    {
        // 创建一个新的路由对象,用于定义HTTP请求的路由。
        router := route.New()
 
        // RoutePrefix must always start with '/'.
        // RoutePrefix 必须以 '/' 开头。
        // 如果用户指定的 webRoutePrefix 不以 '/' 开头,则添加 '/'。
        webRoutePrefix = "/" + strings.Trim(webRoutePrefix, "/")
 
        // Redirect from / to /webRoutePrefix.
        // 这允许用户通过根路径访问Thanos UI。
        if webRoutePrefix != "/" {
            // 将根路径 ('/') 重定向到 webRoutePrefix+"/graph"。
            router.Get("/", func(w http.ResponseWriter, r *http.Request) {
                http.Redirect(w, r, webRoutePrefix+"/graph", http.StatusFound)
            })
            // 将 webRoutePrefix 重定向到 webRoutePrefix+"/graph"。
            router.Get(webRoutePrefix, func(w http.ResponseWriter, r *http.Request) {
                http.Redirect(w, r, webRoutePrefix+"/graph", http.StatusFound)
            })
            // 为整个路由添加前缀,以便所有路由都基于这个前缀。
            router = router.WithPrefix(webRoutePrefix)
        }
 
        // Configure Request Logging for HTTP calls.
        // 创建一个中间件,用于记录HTTP请求的日志。
        logMiddleware := logging.NewHTTPServerMiddleware(logger, httpLogOpts...)
 
        // 创建一个中间件,用于将HTTP请求的指标暴露给Prometheus。
        ins := extpromhttp.NewInstrumentationMiddleware(reg, nil)
        // TODO(bplotka in PR #513 review): pass all flags, not only the flags needed by prefix rewriting.
        // 目前只传递了前缀重写所需的flags。
        ui.NewQueryUI(logger, endpoints, webExternalPrefix, webPrefixHeaderName, alertQueryURL).Register(router, ins)
 
        api := apiv1.NewQueryAPI(
            logger,
            endpoints.GetEndpointStatus, // 获取端点状态的函数。
            engineCreator,               // 创建查询引擎的函数。
            queryableCreator,            // 创建查询代理的函数。
            // NOTE: Will share the same replica label as the query for now.
            // 注意:目前规则API将使用与查询相同的副本标签。
            rules.NewGRPCClientWithDedup(rulesProxy, queryReplicaLabels),         // 创建规则API客户端,用于去重后的规则查询。
            targets.NewGRPCClientWithDedup(targetsProxy, queryReplicaLabels),     // 创建目标API客户端,用于去重后的目标查询。
            metadata.NewGRPCClient(metadataProxy),                                // 创建元数据API客户端。
            exemplars.NewGRPCClientWithDedup(exemplarsProxy, queryReplicaLabels), // 创建示例API客户端,用于去重后的示例查询。
            enableAutodownsampling,              // 是否启用自动降采样。
            enableQueryPartialResponse,          // 是否启用查询部分响应。
            enableRulePartialResponse,           // 是否启用规则部分响应。
            enableTargetPartialResponse,         // 是否启用目标部分响应。
            enableMetricMetadataPartialResponse, // 是否启用指标元数据部分响应。
            enableExemplarPartialResponse,       // 是否启用示例部分响应。
            enableQueryPushdown,                 // 是否启用查询下推。
            queryReplicaLabels,                  // 用于去重的副本标签列表。
            flagsMap,                            // 命令行标志的映射。
            defaultRangeQueryStep,               // 范围查询的默认步长。
            instantDefaultMaxSourceResolution,   // 即时查询的默认最大源分辨率。
            defaultMetadataTimeRange,            // 检索标签时的默认元数据时间范围。
            disableCORS,                         // 是否禁用CORS头部。
            gate.New(
                extprom.WrapRegistererWithPrefix("thanos_query_concurrent_", reg), // 创建一个并发控制组件,用于限制并发查询的数量。
                maxConcurrentQueries, // 最大并发查询数量。
            ),
            reg, // Prometheus注册器,用于注册指标。
        )
 
        // 将查询API注册到路由中,并应用中间件。
        api.Register(router.WithPrefix("/api/v1"), tracer, logger, ins, logMiddleware)
 
        srv := httpserver.New(logger, reg, comp, httpProbe,
            httpserver.WithListen(httpBindAddr),         // HTTP服务器的监听地址。
            httpserver.WithGracePeriod(httpGracePeriod), // HTTP服务器的优雅关闭时间。
            httpserver.WithTLSConfig(httpTLSConfig),     // HTTP服务器的TLS配置。
        )
        srv.Handle("/", router) // 将路由处理器设置为HTTP服务器的主处理器。
 
        g.Add(func() error {
            statusProber.Healthy() // 标记服务为健康状态。
 
            return srv.ListenAndServe() // 启动HTTP服务器。
        }, func(err error) {
            statusProber.NotReady(err)         // 如果服务未准备好,标记为非就绪状态。
            defer statusProber.NotHealthy(err) // 如果服务出错,标记为非健康状态。
 
            srv.Shutdown(err) // 关闭HTTP服务器。
        })
    }
    // Start query (proxy) gRPC StoreAPI.
    // 初始化gRPC服务器以提供查询(代理)StoreAPI。
    {
        // 创建gRPC服务器的TLS配置。
        tlsCfg, err := tls.NewServerConfig(log.With(logger, "protocol", "gRPC"), grpcCert, grpcKey, grpcClientCA)
        // 如果创建TLS配置失败,返回错误。
        if err != nil {
            return errors.Wrap(err, "setup gRPC server")
        }
 
        // 创建StoreAPI的代理实例,它将转发查询请求到后端存储。
        infoSrv := info.NewInfoServer(
            component.Query.String(), // 组件类型,表示这是一个查询组件。
            info.WithLabelSetFunc(func() []labelpb.ZLabelSet { return proxy.LabelSet() }), // 获取标签集的函数。
            info.WithStoreInfoFunc(func() *infopb.StoreInfo { // 获取存储信息的函数。
                if httpProbe.IsReady() { // 如果HTTP服务已准备好,则获取存储信息。
                    mint, maxt := proxy.TimeRange() // 获取时间范围。
                    return &infopb.StoreInfo{       // 返回存储信息,包括最小时间和最大时间。
                        MinTime: mint, // 最小时间
                        MaxTime: maxt, // 最大时间
                    }
                }
                return nil // 如果HTTP服务未准备好,则返回nil。
            }),
            info.WithExemplarsInfoFunc(),      // 提供一个函数,返回示例信息。
            info.WithRulesInfoFunc(),          // 提供一个函数,返回规则信息。
            info.WithMetricMetadataInfoFunc(), // 提供一个函数,返回指标元数据信息。
            info.WithTargetsInfoFunc(),        // 提供一个函数,返回目标信息。
            info.WithQueryAPIInfoFunc(),       // 提供一个函数,返回查询API信息
        )
 
        grpcAPI := apiv1.NewGRPCAPI(time.Now, queryableCreator, engineCreator, instantDefaultMaxSourceResolution) // 创建gRPC API实例。
        s := grpcserver.New(logger, reg, tracer, grpcLogOpts, tagOpts, comp, grpcProbe,
            grpcserver.WithServer(apiv1.RegisterQueryServer(grpcAPI)),                // 注册查询服务器。
            grpcserver.WithServer(store.RegisterStoreServer(proxy)),                  // 注册存储服务器。
            grpcserver.WithServer(rules.RegisterRulesServer(rulesProxy)),             // 注册规则服务器。
            grpcserver.WithServer(targets.RegisterTargetsServer(targetsProxy)),       // 注册目标服务器。
            grpcserver.WithServer(metadata.RegisterMetadataServer(metadataProxy)),    // 注册元数据服务器。
            grpcserver.WithServer(exemplars.RegisterExemplarsServer(exemplarsProxy)), // 注册示例服务器。
            grpcserver.WithServer(info.RegisterInfoServer(infoSrv)),                  // 注册信息服务器。
            grpcserver.WithListen(grpcBindAddr),                                      // gRPC服务器的监听地址。
            grpcserver.WithGracePeriod(grpcGracePeriod),                              // gRPC服务器的优雅关闭时间。
            grpcserver.WithTLSConfig(tlsCfg),                                         // gRPC服务器的TLS配置。
            grpcserver.WithMaxConnAge(grpcMaxConnAge),                                // gRPC连接的最大存活时间。
        )
 
        g.Add(func() error {
            statusProber.Ready()      // 标记服务为就绪状态。
            return s.ListenAndServe() // 启动gRPC服务器。
        }, func(error) {
            statusProber.NotReady(err) // 如果服务未准备好,标记为非就绪状态。
            s.Shutdown(err)            // 关闭gRPC服务器。
        })
    }
 
    // 记录日志,表示 Query 节点正在启动。
    level.Info(logger).Log("msg", "starting query node")
    // 函数执行成功,返回nil。
    return nil
}
 
// removeDuplicateEndpointSpecs 函数用于移除GRPCEndpointSpec切片中的重复地址
//
// 参数:
//
//  logger: 日志记录器,用于记录警告信息
//  duplicatedStores: Prometheus计数器,用于统计重复地址的数量
//  specs: GRPCEndpointSpec切片,需要去除重复地址
//
// 返回值:
//
//  返回去除重复地址后的GRPCEndpointSpec切片
func removeDuplicateEndpointSpecs(logger log.Logger, // log.Logger类型的日志记录器
    duplicatedStores prometheus.Counter, // prometheus.Counter类型的计数器用于记录发现的重复项数量
    specs []*query.GRPCEndpointSpec, // *query.GRPCEndpointSpec类型的切片,其中包含了需要处理的GRPCEndpointSpec对象
) []*query.GRPCEndpointSpec {
    // 创建一个map,键为字符串类型(存储地址),值为*query.GRPCEndpointSpec类型(指向GRPCEndpointSpec对象的指针)。这个map用于存储唯一的地址及其对应的GRPCEndpointSpec对象。
    set := make(map[string]*query.GRPCEndpointSpec)
 
    // 遍历specs数组
    for _, spec := range specs {
        // 获取地址
        addr := spec.Addr()
        // 如果map中已经存在该地址,则记录警告并增加duplicatedStores计数
        if _, ok := set[addr]; ok {
            level.Warn(logger).Log("msg", "Duplicate store address is provided", "addr", addr)
            duplicatedStores.Inc()
        }
        // 将地址和对应的GRPCEndpointSpec存入map中
        set[addr] = spec
    }
 
    // 创建一个空数组用于存储去重后的specs
    deduplicated := make([]*query.GRPCEndpointSpec, 0, len(set))
 
    // 遍历map,将去重后的specs添加到deduplicated数组中
    for _, value := range set {
        deduplicated = append(deduplicated, value)
    }
 
    // 返回去重后的specs数组
    return deduplicated
}
 
// engineFactory creates from 1 to 3 promql.Engines depending on
// dynamicLookbackDelta and eo.LookbackDelta and returns a function
// that returns appropriate engine for given maxSourceResolutionMillis.
//
// TODO: it seems like a good idea to tweak Prometheus itself
// instead of creating several Engines here.
// 根据提供的参数动态创建并返回一个根据数据源分辨率选择PromQL Engine的函数
func engineFactory(
    newEngine func(promql.EngineOpts) *promql.Engine, // 创建新的PromQL引擎的函数,这是一个函数,接受promql.EngineOpts结构体作为参数,返回一个指向promql.Engine的指针。这个函数用于创建新的PromQL Engine实例;
    eo promql.EngineOpts, // promql.EngineOpts结构体实例,包含了创建PromQL引擎所需的各种配置选项;
    dynamicLookbackDelta bool, // 动态查找间隔的布尔值,如果为true,则会在创建引擎时考虑不同的分辨率级别;
) func(int64) *promql.Engine { // 返回一个函数,该函数的参数是int64类型的maxSourceResolutionMillis(数据源的最大分辨率毫秒数),返回值是指向promql.Engine的指针。这个函数根据给定的数据源最大分辨率毫秒数,返回一个合适的PromQL Engine。
    // 定义分辨率数组
    resolutions := []int64{downsample.ResLevel0}
    // 如果dynamicLookbackDelta为true,则添加更多的分辨率
    if dynamicLookbackDelta {
        resolutions = []int64{downsample.ResLevel0, downsample.ResLevel1, downsample.ResLevel2}
    }
    // 初始化engines数组和ld变量
    var (
        engines = make([]*promql.Engine, len(resolutions))
        ld      = eo.LookbackDelta.Milliseconds()
    )
    // 定义wrapReg函数,用于包装prometheus注册器
    wrapReg := func(engineNum int) prometheus.Registerer {
        return extprom.WrapRegistererWith(map[string]string{"engine": strconv.Itoa(engineNum)}, eo.Reg)
    }
 
    // 根据eo.LookbackDelta的毫秒数初始化lookbackDelta变量,并根据分辨率调整lookbackDelta的值。
    lookbackDelta := eo.LookbackDelta
    // 遍历resolutions数组,为每个分辨率创建promql引擎
    for i, r := range resolutions {
        if ld < r {
            lookbackDelta = time.Duration(r) * time.Millisecond
        }
        engines[i] = newEngine(promql.EngineOpts{
            Logger:                   eo.Logger,                   // 日志记录器
            Reg:                      wrapReg(i),                  // 注册器,用于将指标暴露给Prometheus
            MaxSamples:               eo.MaxSamples,               // 最大样本数,用于限制查询结果的样本数量
            Timeout:                  eo.Timeout,                  // 超时时间,用于限制查询操作的执行时间
            ActiveQueryTracker:       eo.ActiveQueryTracker,       // 活动查询跟踪器,用于跟踪当前正在运行的查询
            LookbackDelta:            lookbackDelta,               // 查找间隔,用于限制查询的时间范围
            NoStepSubqueryIntervalFn: eo.NoStepSubqueryIntervalFn, // 无步长子查询间隔函数,用于处理某些特殊的PromQL表达式
            EnableAtModifier:         eo.EnableAtModifier,         // 启用at修饰符,用于处理PromQL中的@修饰符
            EnableNegativeOffset:     eo.EnableNegativeOffset,     // 启用负偏移量,用于处理PromQL中的负时间偏移
        })
    }
    // 返回一个函数,根据maxSourceResolutionMillis返回对应的promql引擎
    return func(maxSourceResolutionMillis int64) *promql.Engine {
        // 从最高分辨率开始向下遍历
        for i := len(resolutions) - 1; i >= 1; i-- {
            left := resolutions[i-1]
            if resolutions[i-1] < ld {
                left = ld
            }
            // 如果当前分辨率小于maxSourceResolutionMillis,则返回对应的promql引擎
            if left < maxSourceResolutionMillis {
                return engines[i]
            }
        }
        // 否则返回最低分辨率的promql引擎
        return engines[0]
    }
}
posted @   左扬  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2023-02-03 vuejs3.0 从入门到精通——单文件组件(SFC)
2023-02-03 vuejs3.0 从入门到精通——多个应用实例
2023-02-03 vuejs3.0 从入门到精通——应用配置
2023-02-03 vuejs3.0 从入门到精通——根组件
2023-02-03 vuejs3.0 从入门到精通——DOM 中的根组件模板
2023-02-03 vuejs3.0 从入门到精通——Visual Studio Code 使用 Vite 安装 TypeScript+Vue3 项目
levels of contents
点击右上角即可分享
微信分享提示