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

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

https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/receive.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
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
 
package main
 
import (
    "context"   // context上下文包
    "io/ioutil" // ioutil包用于读写文件
    "os"        // os包提供了一些基本的操作系统功能
    "path"      // path包提供了处理文件路径的实用函数
    "time"      // time包提供了时间的处理
 
    extflag "github.com/efficientgo/tools/extkingpin"                                   // extkingpin包提供了扩展的命令行参数解析功能
    "github.com/go-kit/log"                                                             // log包提供了日志记录的功能
    "github.com/go-kit/log/level"                                                       // level包提供了日志级别的功能
    grpc_logging "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging" // grpc_logging包提供了gRPC日志记录的功能
    "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/tags"                 // tags包提供了gRPC标签记录的功能
    "github.com/oklog/run"                                                              // run包提供了并发执行多个goroutine的功能
    "github.com/opentracing/opentracing-go"                                             // opentracing包提供了分布式追踪的功能
    "github.com/pkg/errors"                                                             // errors包提供了错误处理的功能
    "github.com/prometheus/client_golang/prometheus"                                    // prometheus包提供了Prometheus监控的功能
    "github.com/prometheus/client_golang/prometheus/promauto"                           // promauto包提供了自动注册Prometheus指标的功能
    "github.com/prometheus/common/model"                                                // model包提供了Prometheus数据模型的功能
    "github.com/prometheus/prometheus/model/labels"                                     // labels包提供了Prometheus标签的功能
    "github.com/prometheus/prometheus/tsdb"                                             // tsdb包提供了Prometheus存储库的功能
 
    "github.com/thanos-io/thanos/pkg/block/metadata"         // metadata包提供了Prometheus块元数据的功能
    "github.com/thanos-io/thanos/pkg/component"              // component包提供了组件的功能
    "github.com/thanos-io/thanos/pkg/exemplars"              // exemplars包提供了Prometheus exemplar的功能
    "github.com/thanos-io/thanos/pkg/extgrpc"                // extgrpc包提供了gRPC扩展的功能
    "github.com/thanos-io/thanos/pkg/extkingpin"             // extkingpin包提供了扩展的命令行参数解析功能
    "github.com/thanos-io/thanos/pkg/extprom"                // extprom包提供了Prometheus扩展的功能
    "github.com/thanos-io/thanos/pkg/info"                   // info包提供了Thanos组件的信息功能
    "github.com/thanos-io/thanos/pkg/info/infopb"            // infopb包提供了Thanos组件信息的功能
    "github.com/thanos-io/thanos/pkg/logging"                // logging包提供了日志记录的功能
    "github.com/thanos-io/thanos/pkg/objstore"               // objstore包提供了对象存储的功能
    "github.com/thanos-io/thanos/pkg/objstore/client"        // client包提供了对象存储客户端的功能
    "github.com/thanos-io/thanos/pkg/prober"                 // prober包提供了探针的功能
    "github.com/thanos-io/thanos/pkg/receive"                // receive包提供了Thanos接收器功能
    "github.com/thanos-io/thanos/pkg/runutil"                // runutil包提供了运行时工具的功能
    grpcserver "github.com/thanos-io/thanos/pkg/server/grpc" // grpcserver包提供了gRPC服务器功能
    httpserver "github.com/thanos-io/thanos/pkg/server/http" // httpserver包提供了HTTP服务器功能
    "github.com/thanos-io/thanos/pkg/store"                  // store包提供了Thanos存储功能
    "github.com/thanos-io/thanos/pkg/store/labelpb"          // labelpb包提供了标签协议的功能
    "github.com/thanos-io/thanos/pkg/tls"                    // tls包提供了TLS功能的封装
)
 
// registerReceive 函数用于注册接收命令,以便通过Prometheus的远程写入API接收数据并将其写入本地tsdb。
func registerReceive(app *extkingpin.App) {
    // 创建一个接收命令,接收Prometheus的远程写入API请求并将其写入本地tsdb。
    cmd := app.Command(component.Receive.String(), "Accept Prometheus remote write API requests and write to local tsdb.")
 
    // 初始化接收配置
    conf := &receiveConfig{}
    conf.registerFlag(cmd)
 
    // 设置接收命令的初始化逻辑
    cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {
        // 解析标签字符串
        lset, err := parseFlagLabels(conf.labelStrs)
        if err != nil {
            return errors.Wrap(err, "parse labels")
        }
 
        // 检查租户标签名称格式是否有效
        if !model.LabelName.IsValid(model.LabelName(conf.tenantLabelName)) {
            return errors.Errorf("unsupported format for tenant label name, got %s", conf.tenantLabelName)
        }
        // 检查是否配置了外部标签
        if len(lset) == 0 {
            // 返回错误,提示没有配置外部标签,这对于接收组件来说是必须的。如果需要,请使用`--receive.external-labels`标志配置它们。
            return errors.New("no external labels configured for receive, uniquely identifying external labels must be configured (ideally with `receive_` prefix); see https://thanos.io/tip/thanos/storage.md#external-labels for details.")
        }
 
        // 解析请求日志配置
        tagOpts, grpcLogOpts, err := logging.ParsegRPCOptions("", conf.reqLogConfig)
        if err != nil {
            return errors.Wrap(err, "error while parsing config for request logging")
        }
 
        // 配置TSDB选项
        tsdbOpts := &tsdb.Options{
            MinBlockDuration:       int64(time.Duration(*conf.tsdbMinBlockDuration) / time.Millisecond), // 最小块持续时间
            MaxBlockDuration:       int64(time.Duration(*conf.tsdbMaxBlockDuration) / time.Millisecond), // 最大块持续时间
            RetentionDuration:      int64(time.Duration(*conf.retention) / time.Millisecond),            // 保留持续时间
            NoLockfile:             conf.noLockFile,                                                     // 是否禁用锁文件
            WALCompression:         conf.walCompression,                                                 // WAL压缩是否启用
            AllowOverlappingBlocks: conf.tsdbAllowOverlappingBlocks,                                     // 是否允许重叠块
            MaxExemplars:           conf.tsdbMaxExemplars,                                               // 最大示例数
            EnableExemplarStorage:  true,                                                                // 是否启用示例存储
        }
 
        // 确定运行模式
        // Are we running in IngestorOnly, RouterOnly or RouterIngestor mode?
        receiveMode := conf.determineMode()
 
        // 运行接收逻辑
        return runReceive(
            g,                    // run.Group实例,用于并发执行多个goroutine
            logger,               // 日志记录器
            reg,                  // Prometheus注册表
            tracer,               // opentracing跟踪器
            grpcLogOpts, tagOpts, // gRPC日志选项和标签选项
            tsdbOpts,                         // TSDB选项
            lset,                             // 标签集
            component.Receive,                // 组件名称
            metadata.HashFunc(conf.hashFunc), // 哈希函数
            receiveMode,                      // 接收模式
            conf,                             // 接收配置
        )
    })
}
 
// runReceive 函数用于启动一个接收组件,处理接收到的数据并将其存储到本地TSDB或上传到对象存储中。
//
// 参数:
// - g: run.Group 对象,用于管理生命周期。
// - logger: log.Logger 对象,用于记录日志。
// - reg: prometheus.Registry 对象,用于注册指标。
// - tracer: opentracing.Tracer 对象,用于分布式追踪。
// - grpcLogOpts: grpc_logging.Option 切片,用于配置 gRPC 日志。
// - tagOpts: tags.Option 切片,用于配置标签选项。
// - tsdbOpts: tsdb.Options 对象,用于配置 TSDB 选项。
// - lset: labels.Labels 对象,用于配置标签集。
// - comp: component.SourceStoreAPI 对象,用于访问源存储 API。
// - hashFunc: metadata.HashFunc 对象,用于计算哈希值。
// - receiveMode: receive.ReceiverMode 对象,表示接收模式。
// - conf: *receiveConfig 对象,包含接收组件的配置信息。
//
// 返回值:
// - error: 如果函数执行过程中出现错误,则返回错误信息;否则返回 nil。
func runReceive(
    g *run.Group, // run.Group 对象,用于管理生命周期
    logger log.Logger, // 日志记录器
    reg *prometheus.Registry, // Prometheus 注册表
    tracer opentracing.Tracer, // 分布式追踪器
    grpcLogOpts []grpc_logging.Option, // gRPC 日志选项
    tagOpts []tags.Option, // 标签选项
    tsdbOpts *tsdb.Options, // TSDB 选项
    lset labels.Labels, // 标签集合
    comp component.SourceStoreAPI, // 组件源存储 API
    hashFunc metadata.HashFunc, // 哈希函数
    receiveMode receive.ReceiverMode, // 接收模式
    conf *receiveConfig, // 接收配置对象
) error {
    logger = log.With(logger, "component", "receive") // 添加组件标签到日志记录器
 
    level.Info(logger).Log("mode", receiveMode, "msg", "running receive") // 记录接收模式和运行状态
 
    rwTLSConfig, err := tls.NewServerConfig(log.With(logger, "protocol", "HTTP"), conf.rwServerCert, conf.rwServerKey, conf.rwServerClientCA) // 创建接收器TLS配置
    if err != nil {
        return err
    }
 
    // 创建 dialOpts,用于配置 gRPC 客户端, 包括日志记录器、注册表和追踪器等配置信息。
    dialOpts, err := extgrpc.StoreClientGRPCOpts(
        logger,                   // 日志记录器
        reg,                      // Prometheus 注册表
        tracer,                   // 分布式追踪器
        *conf.grpcCert != "",     // 是否使用 gRPC 证书
        *conf.grpcClientCA == "", // 是否使用 gRPC 客户端 CA
        conf.rwClientCert,        // 客户端证书
        conf.rwClientKey,         // 客户端密钥
        conf.rwClientServerCA,    // 服务器 CA
        conf.rwClientServerName,  // 服务器名称
    )
    if err != nil {
        return err
    }
 
    // 创建对象存储客户端
    var bkt objstore.Bucket
 
    // 创建对象存储客户端配置内容,用于后续创建对象存储客户端实例。
    confContentYaml, err := conf.objStoreConfig.Content()
    if err != nil {
        return err
    }
 
    // Has this thanos receive instance been configured to ingest metrics into a local TSDB?
    // thanos receive 实例是否配置为将指标摄取到本地 TSDB?
    enableIngestion := receiveMode == receive.IngestorOnly || receiveMode == receive.RouterIngestor
 
    // 判断是否启用上传功能,即是否有有效的对象存储配置内容。
    upload := len(confContentYaml) > 0
    // enableIngestion 判断是否启用摄取功能,即是否配置了本地 TSDB 或对象存储。
    if enableIngestion {
        // upload 判断是否启用上传功能,即是否有有效的对象存储配置内容。
        if upload {
            // tsdbOpts.MinBlockDuration 和 tsdbOpts.MaxBlockDuration 必须相等,否则无法启用上传功能。
            if tsdbOpts.MinBlockDuration != tsdbOpts.MaxBlockDuration {
                // conf.ignoreBlockSize 标志用于忽略 min/max block duration 配置不一致的警告。
                if !conf.ignoreBlockSize {
                    // 报错信息,提示 TSDB 的最大时间和最小时间不一致。需要禁用压缩功能(tsdb.min-block-duration = tsdb.max-block-duration)。
                    return errors.Errorf("found that TSDB Max time is %d and Min time is %d. "+
                        "Compaction needs to be disabled (tsdb.min-block-duration = tsdb.max-block-duration)", tsdbOpts.MaxBlockDuration, tsdbOpts.MinBlockDuration)
                }
                // 告警信息,提示 min/max block duration 配置不一致的警告。如果需要忽略此警告,请使用 --ignore-block-size 标志。
                level.Warn(logger).Log("msg", "flag to ignore min/max block duration flags differing is being used. If the upload of a 2h block fails and a tsdb compaction happens that block may be missing from your Thanos bucket storage.")
            }
            // The background shipper continuously scans the data directory and uploads
            // new blocks to object storage service.
            // 后台上传器持续扫描数据目录,并将新块上传到对象存储服务。
            bkt, err = client.NewBucket(logger, confContentYaml, reg, comp.String())
            if err != nil {
                return err
            }
        } else {
            // 如果没有配置支持的存储桶,则禁用上传功能。
            level.Info(logger).Log("msg", "no supported bucket was configured, uploads will be disabled")
        }
    }
 
    // TODO(brancz): remove after a couple of versions
    // Migrate non-multi-tsdb capable storage to multi-tsdb disk layout.
    // migrateLegacyStorage 函数用于迁移旧存储格式到新的多租户磁盘布局。如果迁移失败,则返回错误信息。
    if err := migrateLegacyStorage(logger, conf.dataDir, conf.defaultTenantID); err != nil {
        // 迁移旧存储格式到新的多租户磁盘布局失败,返回错误信息。
        return errors.Wrapf(err, "migrate legacy storage in %v to default tenant %v", conf.dataDir, conf.defaultTenantID)
    }
 
    // receive.NewMultiTSDB 函数创建一个新的 MultiTSDB 实例,用于处理多租户的 TSDB 数据。
    dbs := receive.NewMultiTSDB(
        conf.dataDir,               // 数据目录路径
        logger,                     // 日志记录器
        reg,                        // 注册表
        tsdbOpts,                   // TSDB 配置选项
        lset,                       // 标签集
        conf.tenantLabelName,       // 租户标签名称
        bkt,                        // 存储桶
        conf.allowOutOfOrderUpload, // 是否允许乱序上传
        hashFunc,                   // 哈希函数
    )
    // receive.NewWriter 函数创建一个新的 Writer 实例,用于处理接收到的数据并将其写入到 MultiTSDB 中。
    writer := receive.NewWriter(log.With(logger, "component", "receive-writer"), dbs)
    // receive.NewHandler 函数创建一个新的 Handler 实例,用于处理接收到的数据并将其转发到其他节点。
    webHandler := receive.NewHandler(log.With(logger, "component", "receive-handler"), &receive.Options{
        Writer:            writer,                              // Writer 实例,用于处理接收到的数据并将其写入到 MultiTSDB 中。
        ListenAddress:     conf.rwAddress,                      // ListenAddress 配置项,指定了接收数据的地址。
        Registry:          reg,                                 // 注册表
        Endpoint:          conf.endpoint,                       // Endpoint 配置项,指定了接收数据的端点。
        TenantHeader:      conf.tenantHeader,                   // TenantHeader 配置项,指定了租户的头部信息。
        DefaultTenantID:   conf.defaultTenantID,                // DefaultTenantID 配置项,指定了默认的租户 ID。
        ReplicaHeader:     conf.replicaHeader,                  // ReplicaHeader 配置项,指定了副本的头部信息。
        ReplicationFactor: conf.replicationFactor,              // ReplicationFactor 配置项,指定了副本的数量。
        ReceiverMode:      receiveMode,                         // ReceiverMode 配置项,指定了接收数据的模式。
        Tracer:            tracer,                              // Tracer 配置项,指定了追踪器。
        TLSConfig:         rwTLSConfig,                         // TLSConfig 配置项,指定了 TLS 配置。
        DialOpts:          dialOpts,                            // DialOpts 配置项,指定了拨号选项。
        ForwardTimeout:    time.Duration(*conf.forwardTimeout), // ForwardTimeout 配置项,指定了转发超时时间。
    })
 
    grpcProbe := prober.NewGRPC()   // 创建一个新的 GRPCProbe 实例,用于监控 gRPC 服务器的健康状态。
    httpProbe := prober.NewHTTP()   // 创建一个新的 HTTPProbe 实例,用于监控 HTTP 服务器的健康状态。
    statusProber := prober.Combine( // 创建一个新的 CombineProbe 实例,用于组合多个 Probe 实例。
        httpProbe, // 创建一个新的 HTTPProbe 实例,用于监控 HTTP 服务器的健康状态。
        grpcProbe, // 创建一个新的 GRPCProbe 实例,用于监控 gRPC 服务器的健康状态。
        prober.NewInstrumentation(comp, logger, extprom.WrapRegistererWithPrefix("thanos_", reg)), // 创建一个新的 InstrumentationProbe 实例,用于监控 Prometheus 的指标。
    )
 
    // Start all components while we wait for TSDB to open but only load
    // initial config and mark ourselves as ready after it completed.
 
    // reloadGRPCServer signals when - (1)TSDB is ready and the Store gRPC server can start.
    // (2) The Hashring files have changed if tsdb ingestion is disabled.
    reloadGRPCServer := make(chan struct{}, 1) // reloadGRPCServer 信号用于通知 TSDB 已准备好,并且 Store gRPC 服务器可以启动。
    // hashringChangedChan signals when TSDB needs to be flushed and updated due to hashring config change.
    hashringChangedChan := make(chan struct{}, 1) // hashringChangedChan 信号用于通知 TSDB 需要刷新和更新,因为哈希环配置发生了变化。
    // uploadC signals when new blocks should be uploaded.
    uploadC := make(chan struct{}, 1) // uploadC 信号用于通知新的块应该被上传。
    // uploadDone signals when uploading has finished.
    uploadDone := make(chan struct{}, 1) // uploadDone 信号用于通知上传已完成。
 
    // enableIngestion 当为 true 时,表示启用 TSDB 数据摄取。
    if enableIngestion {
        level.Debug(logger).Log("msg", "setting up tsdb")
        {
            // startTSDBAndUpload 函数用于启动 TSDB 并上传数据。
            if err := startTSDBAndUpload(g, logger, reg, dbs, reloadGRPCServer, uploadC, hashringChangedChan, upload, uploadDone, statusProber, bkt); err != nil {
                return err
            }
        }
    }
    // 启动哈希环的设置。hashringChangedChan 信号用于通知 TSDB 需要刷新和更新,因为哈希环配置发生了变化。
    level.Debug(logger).Log("msg", "setting up hashring")
    {
        // setupHashring 函数用于设置哈希环。
        if err := setupHashring(g, logger, reg, conf, hashringChangedChan, webHandler, statusProber, reloadGRPCServer, enableIngestion); err != nil {
            return err
        }
    }
    // 启动 HTTP 服务器的设置。
    level.Debug(logger).Log("msg", "setting up http server")
    {
        // srv 是一个 HTTPServer 实例,用于监听和服务的启动。
        srv := httpserver.New(
            logger,    // logger 是一个日志记录器,用于记录日志信息。
            reg,       // reg 是一个 Prometheus 注册表,用于注册和收集指标。
            comp,      // comp 是一个组件,用于提供存储和检索数据的功能。
            httpProbe, // httpProbe 是一个 HTTP 探针,用于检查 HTTP 服务器的健康状态。
            httpserver.WithListen(*conf.httpBindAddr),                        // WithListen 用于设置 HTTP 服务器的监听地址。
            httpserver.WithGracePeriod(time.Duration(*conf.httpGracePeriod)), // WithGracePeriod 用于设置优雅关闭的持续时间。
            httpserver.WithTLSConfig(*conf.httpTLSConfig),                    // WithTLSConfig 用于设置 HTTP 服务器的 TLS 配置。
        )
        g.Add(func() error {
            statusProber.Healthy()
 
            return srv.ListenAndServe()
        }, func(err error) {
            statusProber.NotReady(err)
            defer statusProber.NotHealthy(err)
 
            srv.Shutdown(err)
        })
    }
    // 启动 gRPC 服务器的设置。
    level.Debug(logger).Log("msg", "setting up grpc server")
    {
        // setupAndRunGRPCServer 函数用于设置和运行 gRPC 服务器。
        if err := setupAndRunGRPCServer(g, logger, reg, tracer, conf, reloadGRPCServer, comp, dbs, webHandler, grpcLogOpts,
            tagOpts, grpcProbe, httpProbe.IsReady); err != nil {
            return err
        }
    }
 
    // 启动 receive http handler,用于处理 HTTP 请求。
    level.Debug(logger).Log("msg", "setting up receive http handler")
    {
        g.Add(
            func() error {
                return errors.Wrap(webHandler.Run(), "error starting web server")
            },
            func(err error) {
                webHandler.Close()
            },
        )
    }
 
    level.Info(logger).Log("msg", "starting receiver")
    return nil
}
 
// setupAndRunGRPCServer sets up the configuration for the gRPC server.
// It also sets up a handler for reloading the server if tsdb reloads.
// setupAndRunGRPCServer 函数用于设置并运行 gRPC 服务器。
//
// 参数:
// - g *run.Group: 运行组,用于管理协程和错误处理。
// - logger log.Logger: 日志记录器,用于记录日志。
// - reg *prometheus.Registry: Prometheus 注册中心,用于注册和导出 Prometheus 指标。
// - tracer opentracing.Tracer: OpenTracing 追踪器,用于追踪请求。
// - conf *receiveConfig: 接收配置,包含 gRPC 相关的配置。
// - reloadGRPCServer chan struct{}: 通道,当需要重新加载 gRPC 服务器时发送信号。
// - comp component.SourceStoreAPI: SourceStoreAPI 组件,用于处理数据源存储。
// - dbs *receive.MultiTSDB: MultiTSDB 实例,包含多个 TSDB 实例。
// - webHandler *receive.Handler: HTTP 处理器,用于处理 HTTP 请求。
// - grpcLogOpts []grpc_logging.Option: gRPC 日志选项。
// - tagOpts []tags.Option: 标签选项。
// - grpcProbe *prober.GRPCProbe: gRPC 探测器,用于探测 gRPC 服务器的状态。
// - isReady func() bool: 判断服务器是否就绪的函数。
//
// 返回值:
// - error: 如果发生错误,则返回错误信息;否则返回 nil。
func setupAndRunGRPCServer(g *run.Group,
    logger log.Logger, // 日志记录器
    reg *prometheus.Registry, // Prometheus 注册中心
    tracer opentracing.Tracer, // OpenTracing 追踪器,用于追踪请求。
    conf *receiveConfig, // 接收配置,包含 gRPC 相关的配置。
    reloadGRPCServer chan struct{}, //  通道,当需要重新加载 gRPC 服务器时发送信号。
    comp component.SourceStoreAPI, // SourceStoreAPI 组件,用于处理数据源存储。
    dbs *receive.MultiTSDB, // MultiTSDB 实例,包含多个 TSDB 实例。
    webHandler *receive.Handler, // HTTP 处理器,用于处理 HTTP 请求。
    grpcLogOpts []grpc_logging.Option, // gRPC 日志选项。
    tagOpts []tags.Option, // 标签选项。
    grpcProbe *prober.GRPCProbe, // gRPC 探测器,用于探测 gRPC 服务器的状态。
    isReady func() bool, // 判断服务器是否就绪的函数。
) error {
 
    var s *grpcserver.Server
    // startGRPCListening 是一个通道,用于在接收到信号时重新启动 gRPC 服务器。
    // startGRPCListening re-starts the gRPC server once it receives a signal.
    startGRPCListening := make(chan struct{})
 
    g.Add(func() error {
        // 启动 gRPC 服务器。
        defer close(startGRPCListening)
        // 设置 gRPC 服务器的 TLS 配置。
        tlsCfg, err := tls.NewServerConfig(log.With(logger, "protocol", "gRPC"), *conf.grpcCert, *conf.grpcKey, *conf.grpcClientCA)
        if err != nil {
            // 如果设置 TLS 配置失败,则返回错误。
            return errors.Wrap(err, "setup gRPC server")
        }
        // 遍历 reloadGRPCServer 通道,直到收到信号。
        for range reloadGRPCServer {
            // 如果 gRPC 服务器已经启动,则关闭它。
            if s != nil {
                // 关闭 gRPC 服务器的优雅退出。
                s.Shutdown(errors.New("reload hashrings"))
            }
            // 创建一个新的 gRPC 服务器。
            mts := store.NewMultiTSDBStore(
                logger,         // 日志记录器。
                reg,            // 注册表。
                comp,           // 组件。
                dbs.TSDBStores, // TSDB 存储器。
            )
            // store.ReadWriteTSDBStore 实现了 StoreServer 和 WriteableStoreServer 接口。
            rw := store.ReadWriteTSDBStore{
                StoreServer:          mts,        // 实现了 StoreServer 和 WriteableStoreServer 接口的实例。
                WriteableStoreServer: webHandler, // HTTP 处理器,用于处理写入请求。
            }
 
            // info.NewInfoServer 创建一个新的 InfoServer 实例。
            infoSrv := info.NewInfoServer(
                component.Receive.String(), // 组件名称。
                info.WithLabelSetFunc(func() []labelpb.ZLabelSet { return mts.LabelSet() }), // 标签集函数。
                info.WithStoreInfoFunc(func() *infopb.StoreInfo { // 存储信息函数。
                    if isReady() {
                        minTime, maxTime := mts.TimeRange()
                        return &infopb.StoreInfo{
                            MinTime: minTime,
                            MaxTime: maxTime,
                        }
                    }
                    return nil
                }),
                // WithExemplarsInfoFunc 创建一个新的 ExemplarsInfoFunc 实例。
                info.WithExemplarsInfoFunc(),
            )
            // grpcserver.New 创建一个新的 gRPC 服务器。
            s = grpcserver.New(logger, &receive.UnRegisterer{Registerer: reg}, tracer, grpcLogOpts, tagOpts, comp, grpcProbe,
                grpcserver.WithServer(store.RegisterStoreServer(rw)),                                                // 注册 StoreServer。
                grpcserver.WithServer(store.RegisterWritableStoreServer(rw)),                                        // 注册 WritableStoreServer。
                grpcserver.WithServer(exemplars.RegisterExemplarsServer(exemplars.NewMultiTSDB(dbs.TSDBExemplars))), // 注册 ExemplarsServer。
                grpcserver.WithServer(info.RegisterInfoServer(infoSrv)),                                             // 注册 InfoServer。
                grpcserver.WithListen(*conf.grpcBindAddr),                                                           // 监听地址。
                grpcserver.WithGracePeriod(time.Duration(*conf.grpcGracePeriod)),                                    // 优雅关闭时间。
                grpcserver.WithTLSConfig(tlsCfg),                                                                    // TLS 配置。
                grpcserver.WithMaxConnAge(*conf.grpcMaxConnAge),                                                     // 最大连接时间。
            )
            // 启动 gRPC 服务器的优雅关闭。
            startGRPCListening <- struct{}{}
        }
        if s != nil {
            // 在 gRPC 服务器关闭时,我们需要优雅地关闭所有数据库。
            s.Shutdown(err)
        }
        return nil
    }, func(error) {})
 
    // 我们需要在数据库发生变化时能够启动和停止 gRPC 服务器,因此需要为它创建一个独立的运行组。
    // We need to be able to start and stop the gRPC server
    // whenever the DB changes, thus it needs its own run group.
    g.Add(func() error {
        for range startGRPCListening {
            level.Info(logger).Log("msg", "listening for StoreAPI and WritableStoreAPI gRPC", "address", *conf.grpcBindAddr)
            if err := s.ListenAndServe(); err != nil {
                return errors.Wrap(err, "serve gRPC")
            }
        }
        return nil
    }, func(error) {})
 
    return nil
 
}
 
// setupHashring sets up the hashring configuration provided.
// If no hashring is provided, we setup a single node hashring with local endpoint.
// setupHashring 用于设置并初始化 Hashring。
//
// 参数:
//   - g: *run.Group,用于管理运行的任务组。
//   - logger: log.Logger,用于记录日志。
//   - reg: *prometheus.Registry,用于注册 Prometheus 指标。
//   - conf: *receiveConfig,接收配置。
//   - hashringChangedChan: chan struct{},当 Hashring 发生变化时发送信号的通道。
//   - webHandler: *receive.Handler,用于处理 Web 请求的处理器。
//   - statusProber: prober.Probe,用于探测服务状态的探针。
//   - reloadGRPCServer: chan struct{},当 gRPC 服务器需要重新加载时发送信号的通道。
//   - enableIngestion: bool,是否启用数据摄取功能。
//
// 返回值:
//   - error,如果设置过程中发生错误则返回相应的错误信息,否则返回 nil。
func setupHashring(g *run.Group,
    logger log.Logger,
    reg *prometheus.Registry,
    conf *receiveConfig,
    hashringChangedChan chan struct{},
    webHandler *receive.Handler,
    statusProber prober.Probe,
    reloadGRPCServer chan struct{},
    enableIngestion bool,
) error {
    // Note: the hashring configuration watcher
    // is the sender and thus closes the chan.
    // In the single-node case, which has no configuration
    // watcher, we close the chan ourselves.
    updates := make(chan receive.Hashring, 1)
 
    // 配置文件的路径
    // 初始化配置观察者时给定的 Hashrings 配置文件路径
    if conf.hashringsFilePath != "" {
        cw, err := receive.NewConfigWatcher(log.With(logger, "component", "config-watcher"), reg, conf.hashringsFilePath, *conf.refreshInterval)
        if err != nil {
            return errors.Wrap(err, "failed to initialize config watcher")
        }
 
        // 在运行观察者之前检查 hashring 配置
        if err := cw.ValidateConfig(); err != nil {
            cw.Stop()
            close(updates)
            return errors.Wrap(err, "failed to validate hashring configuration file")
        }
 
        ctx, cancel := context.WithCancel(context.Background())
        g.Add(func() error {
            level.Info(logger).Log("msg", "the hashring initialized with config watcher.")
            // 从配置观察者获取 Hashring
            return receive.HashringFromConfigWatcher(ctx, updates, cw)
        }, func(error) {
            cancel()
        })
    } else {
        var (
            ring receive.Hashring
            err  error
        )
        // 通过内容初始化配置
        // The Hashrings config file content given initialize configuration from content.
        if len(conf.hashringsFileContent) > 0 {
            ring, err = receive.HashringFromConfig(conf.hashringsFileContent)
            if err != nil {
                close(updates)
                return errors.Wrap(err, "failed to validate hashring configuration file")
            }
            level.Info(logger).Log("msg", "the hashring initialized directly with the given content through the flag.")
        } else {
            level.Info(logger).Log("msg", "the hashring file is not specified use single node hashring.")
            // 使用单个节点 Hashring
            ring = receive.SingleNodeHashring(conf.endpoint)
        }
 
        cancel := make(chan struct{})
        g.Add(func() error {
            defer close(updates)
            // 将 Hashring 发送到更新通道
            updates <- ring
            <-cancel
            return nil
        }, func(error) {
            close(cancel)
        })
    }
 
    cancel := make(chan struct{})
    g.Add(func() error {
 
        if enableIngestion {
            defer close(hashringChangedChan)
        }
 
        for {
            select {
            case h, ok := <-updates:
                if !ok {
                    return nil
                }
                // 更新 web 处理器的 Hashring
                webHandler.Hashring(h)
                msg := "hashring has changed; server is not ready to receive web requests"
                // 设置状态为未就绪
                statusProber.NotReady(errors.New(msg))
                level.Info(logger).Log("msg", msg)
 
                if enableIngestion {
                    // 发送信号给 tsdb 重新加载,然后重启 gRPC 服务器
                    // send a signal to tsdb to reload, and then restart the gRPC server.
                    hashringChangedChan <- struct{}{}
                } else {
                    // 不需要 tsdb 重新加载,直接重启 gRPC 服务器
                    level.Info(logger).Log("msg", "server has reloaded, ready to start accepting requests")
                    statusProber.Ready()
                    reloadGRPCServer <- struct{}{}
                }
            case <-cancel:
                return nil
            }
        }
    }, func(err error) {
        close(cancel)
    },
    )
    return nil
}
 
// startTSDBAndUpload starts up the multi-tsdb and sets up the rungroup to flush the tsdb and reload on hashring change.
// It also uploads the tsdb to object store if upload is enabled.
// startTSDBAndUpload 函数启动TSDB并上传数据。
//
// 参数:
// - g: 运行组,用于管理并行执行的函数。
// - logger: 日志记录器,用于记录日志信息。
// - reg: Prometheus注册表,用于注册Prometheus指标。
// - dbs: MultiTSDB对象,表示多个TSDB的集合。
// - reloadGRPCServer: 通道,当TSDB重新加载完成时发送信号。
// - uploadC: 通道,当需要上传数据时发送信号。
// - hashringChangedChan: 通道,当hashring变化时发送信号。
// - upload: 布尔值,指示是否需要上传数据。
// - uploadDone: 通道,当上传完成时发送信号。
// - statusProber: 探测器,用于探测服务状态。
// - bkt: 对象存储桶,用于存储上传的数据。
//
// 返回值:
// - error: 如果发生错误,则返回错误信息;否则返回nil。
func startTSDBAndUpload(g *run.Group,
    logger log.Logger,
    reg *prometheus.Registry,
    dbs *receive.MultiTSDB,
    reloadGRPCServer chan struct{},
    uploadC chan struct{},
    hashringChangedChan chan struct{},
    upload bool,
    uploadDone chan struct{},
    statusProber prober.Probe,
    bkt objstore.Bucket,
 
) error {
    // 设置日志组件
    log.With(logger, "component", "storage")
 
    // 创建Prometheus计数器
    dbUpdatesStarted := promauto.With(reg).NewCounter(prometheus.CounterOpts{
        Name: "thanos_receive_multi_db_updates_attempted_total",
        Help: "Number of Multi DB attempted reloads with flush and potential upload due to hashring changes",
    })
    dbUpdatesCompleted := promauto.With(reg).NewCounter(prometheus.CounterOpts{
        Name: "thanos_receive_multi_db_updates_completed_total",
        Help: "Number of Multi DB completed reloads with flush and potential upload due to hashring changes",
    })
 
    // 删除存储锁文件
    level.Debug(logger).Log("msg", "removing storage lock files if any")
    // 删除存储锁文件,如果删除失败则返回错误
    if err := dbs.RemoveLockFilesIfAny(); err != nil {
        return errors.Wrap(err, "remove storage lock files")
    }
 
    // TSDBs 重新加载逻辑,监听hashring变化
    cancel := make(chan struct{})
    g.Add(func() error {
        defer close(reloadGRPCServer)
        defer close(uploadC)
 
        // 在退出前确保WAL被刷新且DBs被关闭
        defer func() {
            level.Info(logger).Log("msg", "shutting down storage")
            if err := dbs.Flush(); err != nil {
                level.Error(logger).Log("err", err, "msg", "failed to flush storage")
            } else {
                level.Info(logger).Log("msg", "storage is flushed successfully")
            }
            if err := dbs.Close(); err != nil {
                level.Error(logger).Log("err", err, "msg", "failed to close storage")
                return
            }
            level.Info(logger).Log("msg", "storage is closed")
        }()
 
        for {
            select {
            case <-cancel:
                return nil
            case _, ok := <-hashringChangedChan:
                if !ok {
                    return nil
                }
                dbUpdatesStarted.Inc()
                level.Info(logger).Log("msg", "updating storage")
 
                if err := dbs.Flush(); err != nil {
                    return errors.Wrap(err, "flushing storage")
                }
                if err := dbs.Open(); err != nil {
                    return errors.Wrap(err, "opening storage")
                }
                if upload {
                    uploadC <- struct{}{}
                    <-uploadDone
                }
                statusProber.Ready()
                level.Info(logger).Log("msg", "storage started, and server is ready to receive web requests")
                dbUpdatesCompleted.Inc()
                reloadGRPCServer <- struct{}{}
            }
        }
    }, func(err error) {
        close(cancel)
    })
 
    // 如果需要上传,则执行上传逻辑
    if upload {
        logger := log.With(logger, "component", "uploader")
        upload := func(ctx context.Context) error {
            level.Debug(logger).Log("msg", "upload phase starting")
            start := time.Now()
 
            uploaded, err := dbs.Sync(ctx)
            if err != nil {
                level.Warn(logger).Log("msg", "upload failed", "elapsed", time.Since(start), "err", err)
                return err
            }
            level.Debug(logger).Log("msg", "upload phase done", "uploaded", uploaded, "elapsed", time.Since(start))
            return nil
        }
        {
            level.Info(logger).Log("msg", "upload enabled, starting initial sync")
            if err := upload(context.Background()); err != nil {
                return errors.Wrap(err, "initial upload failed")
            }
            level.Info(logger).Log("msg", "initial sync done")
        }
        {
            ctx, cancel := context.WithCancel(context.Background())
            g.Add(func() error {
                // 确保我们正确地清理一切
                defer func() {
                    runutil.CloseWithLogOnErr(logger, bkt, "bucket client")
                }()
 
                // 在退出前确保所有块都被上传
                defer func() {
                    <-uploadC // 由存储例程在完成时关闭
                    level.Info(logger).Log("msg", "uploading the final cut block before exiting")
                    ctx, cancel := context.WithCancel(context.Background())
                    uploaded, err := dbs.Sync(ctx)
                    if err != nil {
                        cancel()
                        level.Error(logger).Log("msg", "the final upload failed", "err", err)
                        return
                    }
                    cancel()
                    level.Info(logger).Log("msg", "the final cut block was uploaded", "uploaded", uploaded)
                }()
 
                defer close(uploadDone)
 
                // 在循环中运行上传器
                tick := time.NewTicker(30 * time.Second)
                defer tick.Stop()
 
                for {
                    select {
                    case <-ctx.Done():
                        return nil
                    case <-uploadC:
                        // 按需上传
                        if err := upload(ctx); err != nil {
                            level.Warn(logger).Log("msg", "on demand upload failed", "err", err)
                        }
                        uploadDone <- struct{}{}
                    case <-tick.C:
                        if err := upload(ctx); err != nil {
                            level.Warn(logger).Log("msg", "recurring upload failed", "err", err)
                        }
                    }
                }
            }, func(error) {
                cancel()
            })
        }
    }
 
    return nil
}
 
// migrateLegacyStorage 函数用于将遗留的存储迁移到新的多租户存储布局。
//
// 参数:
//
//  logger log.Logger: 日志记录器,用于记录迁移过程中的信息。
//  dataDir string: 数据目录的路径。
//  defaultTenantID string: 默认租户ID。
//
// 返回值:
//
//  error: 如果迁移过程中发生错误,则返回错误信息;否则返回nil。
func migrateLegacyStorage(logger log.Logger, dataDir, defaultTenantID string) error {
    // 将默认租户的数据目录设置为dataDir和defaultTenantID的拼接
    defaultTenantDataDir := path.Join(dataDir, defaultTenantID)
 
    // 检查默认租户的数据目录是否存在
    if _, err := os.Stat(defaultTenantDataDir); !os.IsNotExist(err) {
        // 如果默认租户的数据目录已经存在,则不进行存储迁移
        level.Info(logger).Log("msg", "default tenant data dir already present, not attempting to migrate storage")
        return nil
    }
 
    // 检查dataDir是否存在
    if _, err := os.Stat(dataDir); os.IsNotExist(err) {
        // 如果dataDir不存在,则不进行数据迁移
        level.Info(logger).Log("msg", "no existing storage found, no data migration attempted")
        return nil
    }
 
    // 输出日志,表示发现了遗留存储,并计划进行迁移
    level.Info(logger).Log("msg", "found legacy storage, migrating to multi-tsdb layout with default tenant", "defaultTenantID", defaultTenantID)
 
    // 读取dataDir目录下的所有文件和目录
    files, err := ioutil.ReadDir(dataDir)
    if err != nil {
        // 如果读取dataDir失败,则包装错误并返回
        return errors.Wrapf(err, "read legacy data dir: %v", dataDir)
    }
 
    // 创建默认租户的数据目录
    if err := os.MkdirAll(defaultTenantDataDir, 0750); err != nil {
        // 如果创建默认租户的数据目录失败,则包装错误并返回
        return errors.Wrapf(err, "create default tenant data dir: %v", defaultTenantDataDir)
    }
 
    // 遍历dataDir目录下的所有文件和目录
    for _, f := range files {
        // 从dataDir移动文件到默认租户的数据目录
        from := path.Join(dataDir, f.Name())
        to := path.Join(defaultTenantDataDir, f.Name())
        if err := os.Rename(from, to); err != nil {
            // 如果移动文件失败,则包装错误并返回
            return errors.Wrapf(err, "migrate file from %v to %v", from, to)
        }
    }
 
    return nil
}
 
type receiveConfig struct {
    httpBindAddr    *string         // 接收请求的HTTP绑定地址
    httpGracePeriod *model.Duration // HTTP优雅关闭的持续时间
    httpTLSConfig   *string         // HTTP TLS配置
 
    grpcBindAddr    *string         // 接收请求的gRPC绑定地址
    grpcGracePeriod *model.Duration // gRPC优雅关闭的持续时间
    grpcCert        *string         // gRPC证书
    grpcKey         *string         // gRPC私钥
    grpcClientCA    *string         // gRPC客户端CA证书
    grpcMaxConnAge  *time.Duration  // gRPC最大连接年龄
 
    rwAddress          string // 接收请求的地址
    rwServerCert       string // 读写服务器证书
    rwServerKey        string // 读写服务器私钥
    rwServerClientCA   string // 读写服务器客户端CA证书
    rwClientCert       string // 读写客户端证书
    rwClientKey        string // 读写客户端私钥
    rwClientServerCA   string // 读写客户端服务器CA证书
    rwClientServerName string // 读写客户端服务器名称
 
    dataDir   string   // 数据目录
    labelStrs []string // 标签字符串
 
    objStoreConfig *extflag.PathOrContent // 对象存储配置
    retention      *model.Duration        // 数据保留时间
 
    hashringsFilePath    string // 哈希环文件路径
    hashringsFileContent string // 哈希环文件内容
 
    refreshInterval   *model.Duration // 刷新间隔
    endpoint          string          // 端点
    tenantHeader      string          // 租户头部信息
    tenantLabelName   string          // 租户标签名称
    defaultTenantID   string          // 默认租户ID
    replicaHeader     string          // 副本头部信息
    replicationFactor uint64          // 复制因子
    forwardTimeout    *model.Duration // 转发超时时间
 
    tsdbMinBlockDuration       *model.Duration // 最小块持续时间
    tsdbMaxBlockDuration       *model.Duration // 最大块持续时间
    tsdbAllowOverlappingBlocks bool            // 允许重叠块
    tsdbMaxExemplars           int64           // 最大示例数
 
    walCompression bool // WAL压缩
    noLockFile     bool // 无锁文件
 
    hashFunc string // 哈希函数
 
    ignoreBlockSize       bool // 忽略块大小
    allowOutOfOrderUpload bool // 允许无序上传
 
    reqLogConfig *extflag.PathOrContent // 请求日志配置
}
 
// registerFlag 方法用于在指定的命令(cmd)上注册多个配置标志位,这些标志位用于配置接收组件的行为。
func (rc *receiveConfig) registerFlag(cmd extkingpin.FlagClause) {
    // 注册HTTP相关标志位
    rc.httpBindAddr, rc.httpGracePeriod, rc.httpTLSConfig = extkingpin.RegisterHTTPFlags(cmd)
    // 注册gRPC相关标志位
    rc.grpcBindAddr, rc.grpcGracePeriod, rc.grpcCert, rc.grpcKey, rc.grpcClientCA, rc.grpcMaxConnAge = extkingpin.RegisterGRPCFlags(cmd)
 
    // 注册远程写入地址标志位
    cmd.Flag("remote-write.address", "远程写入地址").
        Default("0.0.0.0:19291").StringVar(&rc.rwAddress)
 
    // 注册远程写入服务器TLS证书标志位
    cmd.Flag("remote-write.server-tls-cert", "HTTP服务器的TLS证书,留空则禁用TLS").Default("").StringVar(&rc.rwServerCert)
 
    // 注册远程写入服务器TLS密钥标志位
    cmd.Flag("remote-write.server-tls-key", "HTTP服务器的TLS密钥,留空则禁用TLS").Default("").StringVar(&rc.rwServerKey)
 
    // 注册远程写入服务器TLS客户端CA标志位
    cmd.Flag("remote-write.server-tls-client-ca", "TLS CA以验证客户端。如果没有指定客户端CA,则服务器端不进行客户端验证。(tls.NoClientCert)").Default("").StringVar(&rc.rwServerClientCA)
 
    // 注册远程写入客户端TLS证书标志位
    cmd.Flag("remote-write.client-tls-cert", "用于标识此客户端到服务器的TLS证书").Default("").StringVar(&rc.rwClientCert)
 
    // 注册远程写入客户端TLS密钥标志位
    cmd.Flag("remote-write.client-tls-key", "客户端证书的TLS密钥").Default("").StringVar(&rc.rwClientKey)
 
    // 注册远程写入客户端TLS CA证书标志位
    cmd.Flag("remote-write.client-tls-ca", "用于验证服务器的TLS CA证书").Default("").StringVar(&rc.rwClientServerCA)
 
    // 注册远程写入客户端服务器名称标志位
    cmd.Flag("remote-write.client-server-name", "要验证返回的TLS证书上的主机名的服务器名称。请参阅https://tools.ietf.org/html/rfc4366#section-3.1").Default("").StringVar(&rc.rwClientServerName)
 
    // 注册TSDB数据目录标志位
    cmd.Flag("tsdb.path", "TSDB的数据目录").
        Default("./data").StringVar(&rc.dataDir)
 
    // 注册外部标签标志位
    cmd.Flag("label", "要宣布的外部标签。当处理多个tsdb实例时,此标志将在未来被移除").PlaceHolder("key=\"value\"").StringsVar(&rc.labelStrs)
 
    // 注册通用对象存储标志位
    rc.objStoreConfig = extkingpin.RegisterCommonObjStoreFlags(cmd, "", false)
 
    // 注册TSDB保留时间标志位
    rc.retention = extkingpin.ModelDuration(cmd.Flag("tsdb.retention", "在本地存储上保留原始样本的时间。0d - 禁用此保留").Default("15d"))
 
    // 注册哈希环文件路径标志位
    cmd.Flag("receive.hashrings-file", "包含哈希环配置的文件的路径。初始化一个监视器以监视更改并动态更新哈希环").PlaceHolder("<path>").StringVar(&rc.hashringsFilePath)
 
    // 注册哈希环内容标志位
    cmd.Flag("receive.hashrings", "哈希环配置内容的替代文件标志位(优先级较低)").PlaceHolder("<content>").StringVar(&rc.hashringsFileContent)
 
    // 注册哈希环文件刷新间隔标志位
    rc.refreshInterval = extkingpin.ModelDuration(cmd.Flag("receive.hashrings-file-refresh-interval", "重新读取哈希环配置文件的刷新间隔(用作回退)").
        Default("5m"))
 
    // 注册本地接收节点端点标志位
    cmd.Flag("receive.local-endpoint", "本地接收节点的端点。用于在哈希环配置中标识本地节点").StringVar(&rc.endpoint)
 
    // 注册租户HTTP头标志位
    cmd.Flag("receive.tenant-header", "确定写入请求的租户的HTTP头").Default(receive.DefaultTenantHeader).StringVar(&rc.tenantHeader)
 
    // 注册默认租户ID标志位
    cmd.Flag("receive.default-tenant-id", "当没有通过头提供租户时使用的默认租户ID").Default(receive.DefaultTenant).StringVar(&rc.defaultTenantID)
 
    // 注册租户标签名称标志位
    cmd.Flag("receive.tenant-label-name", "租户将通过其声明的标签名称").Default(receive.DefaultTenantLabel).StringVar(&rc.tenantLabelName)
 
    // 注册副本HTTP头标志位
    cmd.Flag("receive.replica-header", "指定写入请求的副本号的HTTP头").Default(receive.DefaultReplicaHeader).StringVar(&rc.replicaHeader)
 
    // 注册复制因子标志位
    cmd.Flag("receive.replication-factor", "要复制多少次传入的写入请求").Default("1").Uint64Var(&rc.replicationFactor)
 
    // 注册转发请求超时标志位
    rc.forwardTimeout = extkingpin.ModelDuration(cmd.Flag("receive-forward-timeout", "每个转发请求的超时时间").Default("5s").Hidden())
 
    // 注册TSDB最小块持续时间标志位
    rc.tsdbMinBlockDuration = extkingpin.ModelDuration(cmd.Flag("tsdb.min-block-duration", "本地TSDB块的最小持续时间").Default("2h").Hidden())
 
    // 注册TSDB最大块持续时间标志位
    rc.tsdbMaxBlockDuration = extkingpin.ModelDuration(cmd.Flag("tsdb.max-block-duration", "本地TSDB块的最大持续时间").Default("2h").Hidden())
 
    // 注册TSDB允许重叠块标志位
    cmd.Flag("tsdb.allow-overlapping-blocks", "允许重叠块,从而启用垂直压缩和垂直查询合并").Default("false").BoolVar(&rc.tsdbAllowOverlappingBlocks)
 
    // 注册TSDB WAL压缩标志位
    cmd.Flag("tsdb.wal-compression", "压缩TSDB WAL").Default("true").BoolVar(&rc.walCompression)
 
    // 注册TSDB无锁文件标志位
    cmd.Flag("tsdb.no-lockfile", "不在TSDB数据目录中创建锁文件。在任何情况下,锁文件都将在下次启动时删除").Default("false").BoolVar(&rc.noLockFile)
 
    // 注册TSDB最大示例标志位
    cmd.Flag("tsdb.max-exemplars",
        "启用对示例的支持并设置每个租户将存储的最大示例数。如果示例存储已满(存储的示例数等于max-exemplars),则摄入新示例将从存储中逐出最旧的示例。此标志的0(或更小)值禁用示例存储").
        Default("0").Int64Var(&rc.tsdbMaxExemplars)
 
    // 注册哈希函数标志位
    cmd.Flag("hash-func", "指定在计算生成文件的哈希值时使用的哈希函数。如果没有指定函数,则不会发生。这允许避免两次下载某些文件,尽管会有一些性能开销。可能的值为: \"\", \"SHA256\"。").
        Default("").EnumVar(&rc.hashFunc, "SHA256", "")
 
    // 注册忽略不等块大小标志位
    cmd.Flag("shipper.ignore-unequal-block-size", "如果为true,则接收不需要将最小和最大块大小标志位设置为相同的值。仅当您希望保持较长的保留时间和压缩启用时,才使用此选项,因为在最坏的情况下,它可能导致Thanos存储桶存储中约2小时的数据丢失。").Default("false").Hidden().BoolVar(&rc.ignoreBlockSize)
 
    // 注册允许无序上传标志位
    cmd.Flag("shipper.allow-out-of-order-uploads",
        "如果为true,则发货方将跳过给定迭代中失败的块上传并在以后重试。这意味着一些较新的块可能比旧块更早地上传。这可能会触发没有这些块的压缩,并因此导致重叠情况。如果启用了垂直压缩并且希望尽快上传块而不关心顺序,请将其设置为true。").
        Default("false").Hidden().BoolVar(&rc.allowOutOfOrderUpload)
 
    // 注册请求日志配置标志位
    rc.reqLogConfig = extkingpin.RegisterRequestLoggingFlags(cmd)
}
 
// determineMode returns the ReceiverMode that this receiver is configured to run in.
// This is used to configure this Receiver's forwarding and ingesting behavior at runtime.
// determineMode 函数用于确定接收器的模式
//
// 参数:
//
//  rc *receiveConfig: 指向receiveConfig结构体的指针,包含接收配置信息
//
// 返回值:
//
//  receive.ReceiverMode: 返回接收器的模式,可以是RouterIngestor、RouterOnly或IngestorOnly
func (rc *receiveConfig) determineMode() receive.ReceiverMode {
    // 用户是否提供了某种哈希环配置?
    // Has the user provided some kind of hashring configuration?
    hashringSpecified := rc.hashringsFileContent != "" || rc.hashringsFilePath != ""
    // 用户是否指定了 --receive.local-endpoint 标志?
    // Has the user specified the --receive.local-endpoint flag?
    localEndpointSpecified := rc.endpoint != ""
 
    switch {
    case hashringSpecified && localEndpointSpecified:
        // 如果用户提供了哈希环配置并指定了本地端点,则返回 RouterIngestor
        // If the user has provided a hashring configuration and specified a local endpoint, return RouterIngestor
        return receive.RouterIngestor
    case hashringSpecified && !localEndpointSpecified:
        // 注意:如果哈希环包含指向自身的地址且未指定本地端点,则会创建无限循环/分叉炸弹
        // Be careful - if the hashring contains an address that routes to itself and does not specify a local
        // endpoint - you've just created an infinite loop / fork bomb :)
        // 如果用户提供了哈希环配置但未指定本地端点,则返回 RouterOnly
        // If the user has provided a hashring configuration but not a local endpoint, return RouterOnly
        return receive.RouterOnly
    default:
        // 未提供哈希环配置,因此我们会在本地接收所有指标
        // hashring configuration has not been provided so we ingest all metrics locally.
        // 如果用户未提供哈希环配置,则返回 IngestorOnly
        // If the user has not provided a hashring configuration, return IngestorOnly
        return receive.IngestorOnly
    }
}
posted @   左扬  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
历史上的今天:
2022-02-12 Go从入门到精通——数组(固定大小的连续空间)
levels of contents
点击右上角即可分享
微信分享提示