github.com/grafana/pyroscope@v1.18.0/pkg/storegateway/gateway_ring.go (about) 1 package storegateway 2 3 import ( 4 "flag" 5 "net" 6 "strconv" 7 "time" 8 9 "github.com/go-kit/log" 10 "github.com/grafana/dskit/ring" 11 12 "github.com/grafana/pyroscope/pkg/util" 13 ) 14 15 const ( 16 // RingKey is the key under which we store the store gateways ring in the KVStore. 17 RingKey = "store-gateway" 18 19 // RingNameForServer is the name of the ring used by the store gateway server. 20 RingNameForServer = "store-gateway" 21 22 // RingNameForClient is the name of the ring used by the store gateway client (we need 23 // a different name to avoid clashing Prometheus metrics when running in single-binary). 24 RingNameForClient = "store-gateway-client" 25 26 // We use a safe default instead of exposing to config option to the user 27 // in order to simplify the config. 28 RingNumTokens = 512 29 30 // sharedOptionWithRingClient is a message appended to all config options that should be also 31 // set on the components running the store-gateway ring client. 32 sharedOptionWithRingClient = " This option needs be set both on the store-gateway and querier when running in microservices mode." 33 ) 34 35 var ( 36 // BlocksOwnerSync is the operation used to check the authoritative owners of a block 37 // (replicas included). 38 BlocksOwnerSync = ring.NewOp([]ring.InstanceState{ring.JOINING, ring.ACTIVE, ring.LEAVING}, nil) 39 40 // BlocksOwnerRead is the operation used to check the authoritative owners of a block 41 // (replicas included) that are available for queries (a store-gateway is available for 42 // queries only when ACTIVE). 43 BlocksOwnerRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, nil) 44 45 // BlocksRead is the operation run by the querier to query blocks via the store-gateway. 46 BlocksRead = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, func(s ring.InstanceState) bool { 47 // Blocks can only be queried from ACTIVE instances. However, if the block belongs to 48 // a non-active instance, then we should extend the replication set and try to query it 49 // from the next ACTIVE instance in the ring (which is expected to have it because a 50 // store-gateway keeps their previously owned blocks until new owners are ACTIVE). 51 return s != ring.ACTIVE 52 }) 53 ) 54 55 type RingConfig struct { 56 Ring util.CommonRingConfig `yaml:",inline"` 57 ReplicationFactor int `yaml:"replication_factor" category:"advanced"` 58 TokensFilePath string `yaml:"tokens_file_path"` 59 ZoneAwarenessEnabled bool `yaml:"zone_awareness_enabled"` 60 61 // Wait ring stability. 62 WaitStabilityMinDuration time.Duration `yaml:"wait_stability_min_duration" category:"advanced"` 63 WaitStabilityMaxDuration time.Duration `yaml:"wait_stability_max_duration" category:"advanced"` 64 65 // Instance details 66 InstanceZone string `yaml:"instance_availability_zone"` 67 68 UnregisterOnShutdown bool `yaml:"unregister_on_shutdown"` 69 70 // Injected internally 71 RingCheckPeriod time.Duration `yaml:"-"` 72 } 73 74 func (cfg *RingConfig) ToRingConfig() ring.Config { 75 ringCfg := cfg.Ring.ToRingConfig() 76 ringCfg.ReplicationFactor = cfg.ReplicationFactor 77 return ringCfg 78 } 79 80 // RegisterFlags adds the flags required to config this to the given FlagSet 81 func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet, logger log.Logger) { 82 ringFlagsPrefix := "store-gateway.sharding-ring." 83 84 // Ring flags 85 cfg.Ring.RegisterFlags(ringFlagsPrefix, "collectors/", "store-gateways", f, logger) 86 f.IntVar(&cfg.ReplicationFactor, ringFlagsPrefix+"replication-factor", 1, "The replication factor to use when sharding blocks."+sharedOptionWithRingClient) 87 f.StringVar(&cfg.TokensFilePath, ringFlagsPrefix+"tokens-file-path", "", "File path where tokens are stored. If empty, tokens are not stored at shutdown and restored at startup.") 88 f.BoolVar(&cfg.ZoneAwarenessEnabled, ringFlagsPrefix+"zone-awareness-enabled", false, "True to enable zone-awareness and replicate blocks across different availability zones."+sharedOptionWithRingClient) 89 90 // Wait stability flags. 91 f.DurationVar(&cfg.WaitStabilityMinDuration, ringFlagsPrefix+"wait-stability-min-duration", 0, "Minimum time to wait for ring stability at startup, if set to positive value.") 92 f.DurationVar(&cfg.WaitStabilityMaxDuration, ringFlagsPrefix+"wait-stability-max-duration", 5*time.Minute, "Maximum time to wait for ring stability at startup. If the store-gateway ring keeps changing after this period of time, the store-gateway will start anyway.") 93 94 // Instance flags 95 f.StringVar(&cfg.InstanceZone, ringFlagsPrefix+"instance-availability-zone", "", "The availability zone where this instance is running. Required if zone-awareness is enabled.") 96 97 f.BoolVar(&cfg.UnregisterOnShutdown, ringFlagsPrefix+"unregister-on-shutdown", true, "Unregister from the ring upon clean shutdown.") 98 99 // Defaults for internal settings. 100 cfg.RingCheckPeriod = 5 * time.Second 101 } 102 103 func (cfg *RingConfig) ToLifecyclerConfig(logger log.Logger) (ring.BasicLifecyclerConfig, error) { 104 instanceAddr, err := ring.GetInstanceAddr(cfg.Ring.InstanceAddr, cfg.Ring.InstanceInterfaceNames, logger, cfg.Ring.EnableIPv6) 105 if err != nil { 106 return ring.BasicLifecyclerConfig{}, err 107 } 108 109 instancePort := ring.GetInstancePort(cfg.Ring.InstancePort, cfg.Ring.ListenPort) 110 111 return ring.BasicLifecyclerConfig{ 112 ID: cfg.Ring.InstanceID, 113 Addr: net.JoinHostPort(instanceAddr, strconv.Itoa(instancePort)), 114 Zone: cfg.InstanceZone, 115 HeartbeatPeriod: cfg.Ring.HeartbeatPeriod, 116 HeartbeatTimeout: cfg.Ring.HeartbeatTimeout, 117 TokensObservePeriod: 0, 118 NumTokens: RingNumTokens, 119 KeepInstanceInTheRingOnShutdown: !cfg.UnregisterOnShutdown, 120 }, nil 121 }