github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/memberlist/config.go (about)

     1  package memberlist
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"log"
     7  	"net"
     8  	"os"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/hashicorp/go-multierror"
    13  )
    14  
    15  type Config struct {
    16  	// The name of this node. This must be unique in the cluster.
    17  	Name string
    18  
    19  	// Transport is a hook for providing custom code to communicate with
    20  	// other nodes. If this is left nil, then memberlist will by default
    21  	// make a NetTransport using BindAddr and BindPort from this structure.
    22  	Transport Transport
    23  
    24  	// Configuration related to what address to bind to and ports to
    25  	// listen on. The port is used for both UDP and TCP gossip. It is
    26  	// assumed other nodes are running on this port, but they do not need
    27  	// to.
    28  	BindAddr string
    29  	BindPort int
    30  
    31  	// Configuration related to what address to advertise to other
    32  	// cluster members. Used for nat traversal.
    33  	AdvertiseAddr string
    34  	AdvertisePort int
    35  
    36  	// ProtocolVersion is the configured protocol version that we
    37  	// will _speak_. This must be between ProtocolVersionMin and
    38  	// ProtocolVersionMax.
    39  	ProtocolVersion uint8
    40  
    41  	// TCPTimeout is the timeout for establishing a stream connection with
    42  	// a remote node for a full state sync, and for stream read and write
    43  	// operations. This is a legacy name for backwards compatibility, but
    44  	// should really be called StreamTimeout now that we have generalized
    45  	// the transport.
    46  	TCPTimeout time.Duration
    47  
    48  	// IndirectChecks is the number of nodes that will be asked to perform
    49  	// an indirect probe of a node in the case a direct probe fails. Memberlist
    50  	// waits for an ack from any single indirect node, so increasing this
    51  	// number will increase the likelihood that an indirect probe will succeed
    52  	// at the expense of bandwidth.
    53  	IndirectChecks int
    54  
    55  	// RetransmitMult is the multiplier for the number of retransmissions
    56  	// that are attempted for messages broadcasted over gossip. The actual
    57  	// count of retransmissions is calculated using the formula:
    58  	//
    59  	//   Retransmits = RetransmitMult * log(N+1)
    60  	//
    61  	// This allows the retransmits to scale properly with cluster size. The
    62  	// higher the multiplier, the more likely a failed broadcast is to converge
    63  	// at the expense of increased bandwidth.
    64  	RetransmitMult int
    65  
    66  	// SuspicionMult is the multiplier for determining the time an
    67  	// inaccessible node is considered suspect before declaring it dead.
    68  	// The actual timeout is calculated using the formula:
    69  	//
    70  	//   SuspicionTimeout = SuspicionMult * log(N+1) * ProbeInterval
    71  	//
    72  	// This allows the timeout to scale properly with expected propagation
    73  	// delay with a larger cluster size. The higher the multiplier, the longer
    74  	// an inaccessible node is considered part of the cluster before declaring
    75  	// it dead, giving that suspect node more time to refute if it is indeed
    76  	// still alive.
    77  	SuspicionMult int
    78  
    79  	// SuspicionMaxTimeoutMult is the multiplier applied to the
    80  	// SuspicionTimeout used as an upper bound on detection time. This max
    81  	// timeout is calculated using the formula:
    82  	//
    83  	// SuspicionMaxTimeout = SuspicionMaxTimeoutMult * SuspicionTimeout
    84  	//
    85  	// If everything is working properly, confirmations from other nodes will
    86  	// accelerate suspicion timers in a manner which will cause the timeout
    87  	// to reach the base SuspicionTimeout before that elapses, so this value
    88  	// will typically only come into play if a node is experiencing issues
    89  	// communicating with other nodes. It should be set to a something fairly
    90  	// large so that a node having problems will have a lot of chances to
    91  	// recover before falsely declaring other nodes as failed, but short
    92  	// enough for a legitimately isolated node to still make progress marking
    93  	// nodes failed in a reasonable amount of time.
    94  	SuspicionMaxTimeoutMult int
    95  
    96  	// PushPullInterval is the interval between complete state syncs.
    97  	// Complete state syncs are done with a single node over TCP and are
    98  	// quite expensive relative to standard gossiped messages. Setting this
    99  	// to zero will disable state push/pull syncs completely.
   100  	//
   101  	// Setting this interval lower (more frequent) will increase convergence
   102  	// speeds across larger clusters at the expense of increased bandwidth
   103  	// usage.
   104  	PushPullInterval time.Duration
   105  
   106  	// ProbeInterval and ProbeTimeout are used to configure probing
   107  	// behavior for memberlist.
   108  	//
   109  	// ProbeInterval is the interval between random node probes. Setting
   110  	// this lower (more frequent) will cause the memberlist cluster to detect
   111  	// failed nodes more quickly at the expense of increased bandwidth usage.
   112  	//
   113  	// ProbeTimeout is the timeout to wait for an ack from a probed node
   114  	// before assuming it is unhealthy. This should be set to 99-percentile
   115  	// of RTT (round-trip time) on your network.
   116  	ProbeInterval time.Duration
   117  	ProbeTimeout  time.Duration
   118  
   119  	// DisableTcpPings will turn off the fallback TCP pings that are attempted
   120  	// if the direct UDP ping fails. These get pipelined along with the
   121  	// indirect UDP pings.
   122  	DisableTcpPings bool
   123  
   124  	// DisableTcpPingsForNode is like DisableTcpPings, but lets you control
   125  	// whether to perform TCP pings on a node-by-node basis.
   126  	DisableTcpPingsForNode func(nodeName string) bool
   127  
   128  	// AwarenessMaxMultiplier will increase the probe interval if the node
   129  	// becomes aware that it might be degraded and not meeting the soft real
   130  	// time requirements to reliably probe other nodes.
   131  	AwarenessMaxMultiplier int
   132  
   133  	// GossipInterval and GossipNodes are used to configure the gossip
   134  	// behavior of memberlist.
   135  	//
   136  	// GossipInterval is the interval between sending messages that need
   137  	// to be gossiped that haven't been able to piggyback on probing messages.
   138  	// If this is set to zero, non-piggyback gossip is disabled. By lowering
   139  	// this value (more frequent) gossip messages are propagated across
   140  	// the cluster more quickly at the expense of increased bandwidth.
   141  	//
   142  	// GossipNodes is the number of random nodes to send gossip messages to
   143  	// per GossipInterval. Increasing this number causes the gossip messages
   144  	// to propagate across the cluster more quickly at the expense of
   145  	// increased bandwidth.
   146  	//
   147  	// GossipToTheDeadTime is the interval after which a node has died that
   148  	// we will still try to gossip to it. This gives it a chance to refute.
   149  	GossipInterval      time.Duration
   150  	GossipNodes         int
   151  	GossipToTheDeadTime time.Duration
   152  
   153  	// WeightInterval is the interval between calculating local node weight and enqueue a message carrying the result
   154  	// weight is calculated using the formula:
   155  	//
   156  	// Weight = (AwarenessMaxMultiplier - AwarenessScore) * 0.6 + AwarenessMaxMultiplier * CPUIdlePercent * 0.4
   157  	//
   158  	// local node weight messages will be gossiped to remote nodes. Remote nodes will use it to implement smooth
   159  	// weighted round-robin load balance algo for choosing the next service provider
   160  	// By default, this is 0, means not enabled
   161  	WeightInterval time.Duration
   162  
   163  	// GossipVerifyIncoming controls whether to enforce encryption for incoming
   164  	// gossip. It is used for upshifting from unencrypted to encrypted gossip on
   165  	// a running cluster.
   166  	GossipVerifyIncoming bool
   167  
   168  	// GossipVerifyOutgoing controls whether to enforce encryption for outgoing
   169  	// gossip. It is used for upshifting from unencrypted to encrypted gossip on
   170  	// a running cluster.
   171  	GossipVerifyOutgoing bool
   172  
   173  	// EnableCompression is used to control message compression. This can
   174  	// be used to reduce bandwidth usage at the cost of slightly more CPU
   175  	// utilization. This is only available starting at protocol version 1.
   176  	EnableCompression bool
   177  
   178  	// SecretKey is used to initialize the primary encryption key in a keyring.
   179  	// The primary encryption key is the only key used to encrypt messages and
   180  	// the first key used while attempting to decrypt messages. Providing a
   181  	// value for this primary key will enable message-level encryption and
   182  	// verification, and automatically install the key onto the keyring.
   183  	// The value should be either 16, 24, or 32 bytes to select AES-128,
   184  	// AES-192, or AES-256.
   185  	SecretKey []byte
   186  
   187  	// The keyring holds all of the encryption keys used internally. It is
   188  	// automatically initialized using the SecretKey and SecretKeys values.
   189  	Keyring *Keyring
   190  
   191  	// Delegate and Events are delegates for receiving and providing
   192  	// data to memberlist via callback mechanisms. For Delegate, see
   193  	// the Delegate interface. For Events, see the EventDelegate interface.
   194  	//
   195  	// The DelegateProtocolMin/Max are used to guarantee protocol-compatibility
   196  	// for any custom messages that the delegate might do (broadcasts,
   197  	// local/remote state, etc.). If you don't set these, then the protocol
   198  	// versions will just be zero, and version compliance won't be done.
   199  	Delegate                Delegate
   200  	DelegateProtocolVersion uint8
   201  	DelegateProtocolMin     uint8
   202  	DelegateProtocolMax     uint8
   203  	Events                  EventDelegate
   204  	Conflict                ConflictDelegate
   205  	Merge                   MergeDelegate
   206  	Ping                    PingDelegate
   207  	Alive                   AliveDelegate
   208  
   209  	// DNSConfigPath points to the system's DNS config file, usually located
   210  	// at /etc/resolv.conf. It can be overridden via config for easier testing.
   211  	DNSConfigPath string
   212  
   213  	// LogOutput is the writer where logs should be sent. If this is not
   214  	// set, logging will go to stderr by default. You cannot specify both LogOutput
   215  	// and Logger at the same time.
   216  	LogOutput io.Writer
   217  
   218  	// Logger is a custom logger which you provide. If Logger is set, it will use
   219  	// this for the internal logger. If Logger is not set, it will fall back to the
   220  	// behavior for using LogOutput. You cannot specify both LogOutput and Logger
   221  	// at the same time.
   222  	Logger *log.Logger
   223  
   224  	// Size of Memberlist's internal channel which handles UDP messages. The
   225  	// size of this determines the size of the queue which Memberlist will keep
   226  	// while UDP messages are handled.
   227  	HandoffQueueDepth int
   228  
   229  	// Maximum number of bytes that memberlist will put in a packet (this
   230  	// will be for UDP packets by default with a NetTransport). A safe value
   231  	// for this is typically 1400 bytes (which is the default). However,
   232  	// depending on your network's MTU (Maximum Transmission Unit) you may
   233  	// be able to increase this to get more content into each gossip packet.
   234  	// This is a legacy name for backward compatibility but should really be
   235  	// called PacketBufferSize now that we have generalized the transport.
   236  	UDPBufferSize int
   237  
   238  	// DeadNodeReclaimTime controls the time before a dead node's name can be
   239  	// reclaimed by one with a different address or port. By default, this is 0,
   240  	// meaning nodes cannot be reclaimed this way.
   241  	DeadNodeReclaimTime time.Duration
   242  
   243  	// RequireNodeNames controls if the name of a node is required when sending
   244  	// a message to that node.
   245  	RequireNodeNames bool
   246  	// CIDRsAllowed If nil, allow any connection (default), otherwise specify all networks
   247  	// allowed to connect (you must specify IPv6/IPv4 separately)
   248  	// Using [] will block all connections.
   249  	CIDRsAllowed []net.IPNet
   250  }
   251  
   252  // ParseCIDRs return a possible empty list of all Network that have been parsed
   253  // In case of error, it returns successfully parsed CIDRs and the last error found
   254  func ParseCIDRs(v []string) ([]net.IPNet, error) {
   255  	nets := make([]net.IPNet, 0)
   256  	if v == nil {
   257  		return nets, nil
   258  	}
   259  	var errs error
   260  	hasErrors := false
   261  	for _, p := range v {
   262  		_, net, err := net.ParseCIDR(strings.TrimSpace(p))
   263  		if err != nil {
   264  			err = fmt.Errorf("invalid cidr: %s", p)
   265  			errs = multierror.Append(errs, err)
   266  			hasErrors = true
   267  		} else {
   268  			nets = append(nets, *net)
   269  		}
   270  	}
   271  	if !hasErrors {
   272  		errs = nil
   273  	}
   274  	return nets, errs
   275  }
   276  
   277  // DefaultLANConfig returns a sane set of configurations for Memberlist.
   278  // It uses the hostname as the node name, and otherwise sets very conservative
   279  // values that are sane for most LAN environments. The default configuration
   280  // errs on the side of caution, choosing values that are optimized
   281  // for higher convergence at the cost of higher bandwidth usage. Regardless,
   282  // these values are a good starting point when getting started with memberlist.
   283  func DefaultLANConfig() *Config {
   284  	hostname, _ := os.Hostname()
   285  	return &Config{
   286  		Name:                    hostname,
   287  		BindAddr:                "0.0.0.0",
   288  		BindPort:                7946,
   289  		AdvertiseAddr:           "",
   290  		AdvertisePort:           7946,
   291  		ProtocolVersion:         ProtocolVersion2Compatible,
   292  		TCPTimeout:              10 * time.Second,       // Timeout after 10 seconds
   293  		IndirectChecks:          3,                      // Use 3 nodes for the indirect ping
   294  		RetransmitMult:          4,                      // Retransmit a message 4 * log(N+1) nodes
   295  		SuspicionMult:           4,                      // Suspect a node for 4 * log(N+1) * Interval
   296  		SuspicionMaxTimeoutMult: 6,                      // For 10k nodes this will give a max timeout of 120 seconds when SuspicionMult is 5: 6 * suspicionTimeout(5, 10000, time.Second)
   297  		PushPullInterval:        30 * time.Second,       // Low frequency
   298  		ProbeTimeout:            500 * time.Millisecond, // Reasonable RTT time for LAN
   299  		ProbeInterval:           1 * time.Second,        // Failure check every second
   300  		DisableTcpPings:         false,                  // TCP pings are safe, even with mixed versions
   301  		AwarenessMaxMultiplier:  8,                      // Probe interval backs off to 8 seconds
   302  
   303  		GossipNodes:          3,                      // Gossip to 3 nodes
   304  		GossipInterval:       200 * time.Millisecond, // Gossip more rapidly
   305  		GossipToTheDeadTime:  30 * time.Second,       // Same as push/pull
   306  		GossipVerifyIncoming: true,
   307  		GossipVerifyOutgoing: true,
   308  
   309  		EnableCompression: true, // Enable compression by default
   310  
   311  		SecretKey: nil,
   312  		Keyring:   nil,
   313  
   314  		DNSConfigPath: "/etc/resolv.conf",
   315  
   316  		HandoffQueueDepth: 1024,
   317  		UDPBufferSize:     1400,
   318  		CIDRsAllowed:      nil, // same as allow all
   319  	}
   320  }
   321  
   322  // DefaultWANConfig works like DefaultConfig, however it returns a configuration
   323  // that is optimized for most WAN environments. The default configuration is
   324  // still very conservative and errs on the side of caution.
   325  func DefaultWANConfig() *Config {
   326  	conf := DefaultLANConfig()
   327  	conf.TCPTimeout = 30 * time.Second
   328  	conf.SuspicionMult = 6
   329  	conf.PushPullInterval = 60 * time.Second
   330  	conf.ProbeTimeout = 3 * time.Second
   331  	conf.ProbeInterval = 5 * time.Second
   332  	conf.GossipNodes = 4 // Gossip less frequently, but to an additional node
   333  	conf.GossipInterval = 500 * time.Millisecond
   334  	conf.GossipToTheDeadTime = 60 * time.Second
   335  	return conf
   336  }
   337  
   338  // IPMustBeChecked return true if IPAllowed must be called
   339  func (c *Config) IPMustBeChecked() bool {
   340  	return len(c.CIDRsAllowed) > 0
   341  }
   342  
   343  // IPAllowed return an error if access to memberlist is denied
   344  func (c *Config) IPAllowed(ip net.IP) error {
   345  	if !c.IPMustBeChecked() {
   346  		return nil
   347  	}
   348  	for _, n := range c.CIDRsAllowed {
   349  		if n.Contains(ip) {
   350  			return nil
   351  		}
   352  	}
   353  	return fmt.Errorf("%s is not allowed", ip)
   354  }
   355  
   356  var LookupIP = net.LookupIP
   357  
   358  // AddrAllowed return an error if access to memberlist is denied
   359  // addr can either be an ip address or a dns address
   360  func (c *Config) AddrAllowed(addr string) error {
   361  	if !c.IPMustBeChecked() {
   362  		return nil
   363  	}
   364  	ip := net.ParseIP(addr)
   365  	if ip == nil {
   366  		ips, err := LookupIP(addr)
   367  		if err != nil || len(ips) == 0 {
   368  			return fmt.Errorf("%s is not allowed", addr)
   369  		}
   370  		ip = ips[0]
   371  	}
   372  	return c.IPAllowed(ip)
   373  }
   374  
   375  // Returns whether or not encryption is enabled
   376  func (c *Config) EncryptionEnabled() bool {
   377  	return c.Keyring != nil && len(c.Keyring.GetKeys()) > 0
   378  }