github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/ruler/base/ruler_ring.go (about) 1 package base 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/go-kit/log" 10 "github.com/grafana/dskit/flagext" 11 "github.com/grafana/dskit/kv" 12 "github.com/grafana/dskit/netutil" 13 "github.com/grafana/dskit/ring" 14 15 util_log "github.com/grafana/loki/pkg/util/log" 16 ) 17 18 const ( 19 // If a ruler is unable to heartbeat the ring, its better to quickly remove it and resume 20 // the evaluation of all rules since the worst case scenario is that some rulers will 21 // receive duplicate/out-of-order sample errors. 22 ringAutoForgetUnhealthyPeriods = 2 23 ) 24 25 // RingOp is the operation used for distributing rule groups between rulers. 26 var RingOp = ring.NewOp([]ring.InstanceState{ring.ACTIVE}, func(s ring.InstanceState) bool { 27 // Only ACTIVE rulers get any rule groups. If instance is not ACTIVE, we need to find another ruler. 28 return s != ring.ACTIVE 29 }) 30 31 // RingConfig masks the ring lifecycler config which contains 32 // many options not really required by the rulers ring. This config 33 // is used to strip down the config to the minimum, and avoid confusion 34 // to the user. 35 type RingConfig struct { 36 KVStore kv.Config `yaml:"kvstore"` 37 HeartbeatPeriod time.Duration `yaml:"heartbeat_period"` 38 HeartbeatTimeout time.Duration `yaml:"heartbeat_timeout"` 39 40 // Instance details 41 InstanceID string `yaml:"instance_id" doc:"hidden"` 42 InstanceInterfaceNames []string `yaml:"instance_interface_names" doc:"default=[<private network interfaces>]"` 43 InstancePort int `yaml:"instance_port" doc:"hidden"` 44 InstanceAddr string `yaml:"instance_addr" doc:"hidden"` 45 NumTokens int `yaml:"num_tokens"` 46 47 // Injected internally 48 ListenPort int `yaml:"-"` 49 50 // Used for testing 51 SkipUnregister bool `yaml:"-"` 52 } 53 54 // RegisterFlags adds the flags required to config this to the given FlagSet 55 func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { 56 hostname, err := os.Hostname() 57 if err != nil { 58 panic(fmt.Errorf("failed to get hostname, %w", err)) 59 } 60 61 // Ring flags 62 cfg.KVStore.RegisterFlagsWithPrefix("ruler.ring.", "rulers/", f) 63 f.DurationVar(&cfg.HeartbeatPeriod, "ruler.ring.heartbeat-period", 5*time.Second, "Period at which to heartbeat to the ring. 0 = disabled.") 64 f.DurationVar(&cfg.HeartbeatTimeout, "ruler.ring.heartbeat-timeout", time.Minute, "The heartbeat timeout after which rulers are considered unhealthy within the ring. 0 = never (timeout disabled).") 65 66 // Instance flags 67 cfg.InstanceInterfaceNames = netutil.PrivateNetworkInterfacesWithFallback([]string{"eth0", "en0"}, util_log.Logger) 68 f.Var((*flagext.StringSlice)(&cfg.InstanceInterfaceNames), "ruler.ring.instance-interface-names", "Name of network interface to read address from.") 69 f.StringVar(&cfg.InstanceAddr, "ruler.ring.instance-addr", "", "IP address to advertise in the ring.") 70 f.IntVar(&cfg.InstancePort, "ruler.ring.instance-port", 0, "Port to advertise in the ring (defaults to server.grpc-listen-port).") 71 f.StringVar(&cfg.InstanceID, "ruler.ring.instance-id", hostname, "Instance ID to register in the ring.") 72 f.IntVar(&cfg.NumTokens, "ruler.ring.num-tokens", 128, "Number of tokens for each ruler.") 73 } 74 75 // ToLifecyclerConfig returns a LifecyclerConfig based on the ruler 76 // ring config. 77 func (cfg *RingConfig) ToLifecyclerConfig(logger log.Logger) (ring.BasicLifecyclerConfig, error) { 78 instanceAddr, err := ring.GetInstanceAddr(cfg.InstanceAddr, cfg.InstanceInterfaceNames, logger) 79 if err != nil { 80 return ring.BasicLifecyclerConfig{}, err 81 } 82 83 instancePort := ring.GetInstancePort(cfg.InstancePort, cfg.ListenPort) 84 85 return ring.BasicLifecyclerConfig{ 86 ID: cfg.InstanceID, 87 Addr: fmt.Sprintf("%s:%d", instanceAddr, instancePort), 88 HeartbeatPeriod: cfg.HeartbeatPeriod, 89 TokensObservePeriod: 0, 90 NumTokens: cfg.NumTokens, 91 }, nil 92 } 93 94 func (cfg *RingConfig) ToRingConfig() ring.Config { 95 rc := ring.Config{} 96 flagext.DefaultValues(&rc) 97 98 rc.KVStore = cfg.KVStore 99 rc.HeartbeatTimeout = cfg.HeartbeatTimeout 100 rc.SubringCacheDisabled = true 101 102 // Each rule group is loaded to *exactly* one ruler. 103 rc.ReplicationFactor = 1 104 105 return rc 106 }