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 } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2022-02-12 Go从入门到精通——数组(固定大小的连续空间)