fd_pool

package
v1.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 9, 2021 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Go fd pool implementation, providing client side load balancing.

Basic usage is to set it up with NewGoPool, add a node using AddSingle and then use pool.NewConn() to connect.

After you're done using the connection you either use conn.Put() to put it back into the pool of open connections, or conn.Close() to close it.

If you encounter an error and wish to connect to the next node in the pool you call conn.Next() with either sbalance.Fail or sbalannce.TempFail and then keep using the connection as normal, restarting the communication.

Normally pools are setup with multiple nodes from config or SD. For static configuration you can use the ServiceConfig struct or bconf.

Bconf Configuration

The configuration given to AddBconf or stored in Service Discvory have the following keys. Typically either bconf or json is used to encode. The bconf syntax is shown here, while json would have recursive dictionaries. Almost everything is optional, with defaults as mentioned. A host name and port is required for a node to exist.

host.X.name=ip

host.X.port=port

Specifies the location of the daemon(s) to connect to. X is often a number but does not have to be. In SD it's often a UUID.

host.X.keepalive_port=port

Alternative port used by some API users when the keepalive protocol differs from the normal one. Additional ports can be added by any key ending on port.

host.X.cost=number

How expensive it is to connect to this host relatively the other ones. Used to weigh the random connection sequence. Defaults to 1.

strat=random

strat=hash

strat=seq

Changes the order of the connection attempts from sequential to either random or deterministically random based on a value given by the API user (typically the client ip). By default a random strat is used.

Old keys for these are .random_pick=1 resp. .client_hash=1

failcost=number

If a connection attempt fails, the cost of the host is temporarily changed to this number until a successful query is made. Use 0 for no value, defaults to 100.

tempfailcost=number

If the API user indicates a temporary failure (eg. info:goaway), the cost of the host is changed to this number until a successful query is made. Use 0 for no value, which is also default.

connect_timeout=number

Timeout in milliseconds for the connection attempt. Defaults to 5000 (5 seconds). Note that this is per connection attempt. If a connection fails, the next host is tried, and the connection timeout resets.

retries=number

How many times to iterate the whole host array before giving up.

Index

Constants

View Source
const (
	DefaultCost           = 1
	DefaultFailCost       = 100
	DefaultSoftFailCost   = 100
	DefaultRetries        = 1
	DefaultConnectTimeout = 1 * time.Second
	DefaultStrat          = sbalance.StratRandom
	InitialWaitDuration   = 1 * time.Second
)

Variables

View Source
var (
	EmptyConfig   = errors.New("empty config node")
	NoSuchService = errors.New("no such service")
	ConnClosed    = errors.New("Use of closed or put connection")
)
View Source
var PortMap = map[string]string{
	"80":   "http_port",
	"443":  "http_port",
	"8080": "port",
	"8081": "controller_port",
	"8082": "keepalive_port,port",
	"8180": "plog_port",
}

Port map to support numeric ports mapping to port keys. Mostly to support the net/url package which requires numeric ports. You can modify this if needed, but be careful as it's used without locks.

Functions

func Dialer

func Dialer(p FdPool) func(ctx context.Context, nw, addr string) (net.Conn, error)

Simple dial. the nw parameter is currently ignored, the type of connection is determined by the fd pool service.

You can plug this into for example http.Transport like so:

transport.DialContext = fd_pool.Dialer(p)

Note that when using the dialer, the port given in e.g. a URL might have to be chosen carefully. If possible, you should use a textual port key, e.g. "port", but URLs do not strictly allow anything else than numbers in the port specification. Thus we've added a default mapping from numbers to port keys. "80" and "443" will map to "http_port", while "8080" maps to "port". For more mappings see fd_pool.c symbol default_upmap.

If SetDialDomain has been called, then a hostname to service name conversion is done as it specifies.

func DialerFor

func DialerFor(p FdPool, service, portKey, remoteAddr string) func(ctx context.Context, nw, addr string) (net.Conn, error)

Returns a dialer that ignores the argument given to it and always connects to the service specified to this function.

func DialerPutOnClose

func DialerPutOnClose(p FdPool) func(ctx context.Context, nw, addr string) (net.Conn, error)

Simple dialer, but when the conn.Close is called, the connection will be put back into the pool instead of closed.

func DialerRA

func DialerRA(p FdPool, remoteAddr string) func(ctx context.Context, nw, addr string) (net.Conn, error)

Dialer that lets you set the remoteAddr parameter given to NewConn.

func DialerRAPutOnClose

func DialerRAPutOnClose(p FdPool, remoteAddr string) func(ctx context.Context, nw, addr string) (net.Conn, error)

Returns a function that can is compatible with net.Dial, put on close version.

func GetUrl

func GetUrl(p FdPool, scheme, service, portKey string) string

Helper to construct a URL from a service with the dial domain set in the pool

func PortDialer

func PortDialer(p FdPool, portKey, remoteAddr string) func(ctx context.Context, nw, addr string) (net.Conn, error)

Returns a dialer that ignores the port part of addr, instead using the given portKey(s). The host part is converted to a service in the normal manner.

Types

type ErrNoServiceNodes

type ErrNoServiceNodes struct {
	Service, PortKey string
}

Error returned when no more nodes could be found when calling Next or NewConn.

func (*ErrNoServiceNodes) Error

func (e *ErrNoServiceNodes) Error() string

func (*ErrNoServiceNodes) KVError added in v1.3.0

func (e *ErrNoServiceNodes) KVError(m map[string]interface{}, key string)

type FdPool

type FdPool interface {
	Close() error

	SetDialDomain(dom string)
	DialDomain() string

	AddConf(ctx context.Context, conf bconf.Bconf) (string, error)
	AddSingle(ctx context.Context, service, netw, addr string, retries int, connectTimeout time.Duration) error

	NewConn(ctx context.Context, service, portKey, remoteAddr string) (NetConn, error)
}

Interface covering both GoPool and CPool. AddConf is deprected and will be removed in 2.0

type FdPoolConfig added in v1.2.0

type FdPoolConfig interface {
	FdPool

	AddConfig(ctx context.Context, config *ServiceConfig) (string, error)
}

Interface similar to FdPool but containing the new AddConfig function. In 2.0 this will be merged into FdPool.

type GoPool

type GoPool struct {
	// contains filtered or unexported fields
}

The main fd pool struct. Typically long-lived, a single pool is created for an application and used throughout. Services are added as needed.

func NewGoPool

func NewGoPool(sdreg *sdr.Registry) *GoPool

Create a new Go fd pool. Should be preferred over NewCPool if you don't need to interact with C code.

func (*GoPool) AddBconf added in v1.2.0

func (p *GoPool) AddBconf(ctx context.Context, conf bconf.Bconf) (string, error)

Add bconf config based nodes to the pool. Uses default stream socket types.

func (*GoPool) AddBconfNetwork added in v1.2.0

func (p *GoPool) AddBconfNetwork(ctx context.Context, conf bconf.Bconf, ipnetw, unixnetw string) (string, error)

Like AddBconf but allows to specify the network parameter later given to Dial. ipnetw is used for ports and unixnetw is used for paths. Creates a Config and calls AddConfig.

func (*GoPool) AddConf

func (p *GoPool) AddConf(ctx context.Context, conf bconf.Bconf) (string, error)

Add bconf config based nodes to the pool. Uses default stream socket types. Deprecated due to confusing name. AddBconf is the same function.

func (*GoPool) AddConfNetwork

func (p *GoPool) AddConfNetwork(ctx context.Context, conf bconf.Bconf, ipnetw, unixnetw string) (string, error)

Like AddConf but allows to specify the network parameter later given to Dial. ipnetw is used for ports and unixnetw is used for paths. Deprecated due to confusing name. AddBconfNetwork is the same function.

func (*GoPool) AddConfig added in v1.2.0

func (p *GoPool) AddConfig(ctx context.Context, config *ServiceConfig) (string, error)

Add a service based on a configuration struct. The conf values are copied, the struct can be discarded or reused after the call returns.

func (*GoPool) AddSingle

func (p *GoPool) AddSingle(ctx context.Context, service, netw, addr string, retries int, connectTimeout time.Duration) error

Add a single node to the pool. Uses DefaultCost as cost.

func (*GoPool) Close

func (pool *GoPool) Close() error

func (*GoPool) DialDomain

func (pool *GoPool) DialDomain() string

func (*GoPool) GetNodePorts

func (p *GoPool) GetNodePorts(service string) []PortInfo

Fetch the internal node state of the pool. Used for debugging purposes. Returns a list of node keys and ports with their costs and number of stored connections.

func (*GoPool) NewConn

func (pool *GoPool) NewConn(ctx context.Context, service, portKey, remoteAddr string) (NetConn, error)

Create a new conneciton to the given service and port keys. remoteAddr can be given to use as a hash for that sbalance strat. The returned NetConn is ready for use. An error might be returned instead if a connection can't be established. It will be the error from the last Dial attempt made, or ErrNoServiceNodes if no connection attempt were made. NoSuchService might also be returned, as well as errors from connecting to Service Discovery if such is configured.

func (*GoPool) SetDialDomain

func (pool *GoPool) SetDialDomain(dom string)

func (*GoPool) SetDialFunc

func (p *GoPool) SetDialFunc(srvname string, df func(ctx context.Context, nw, addr string) (net.Conn, error)) error

Change the dial function for a specific service. By default a net.Dialer with Timeout set to the configured connect timeout is used. Returns NoSuchService if the service has not been configured.

func (*GoPool) UpdateHosts

func (pool *GoPool) UpdateHosts(ctx context.Context, service string, conf bconf.Bconf) (int, error)

Update the nodes for a service, using a bconf node. Deprecated, same as UpdateHostsBconf.

func (*GoPool) UpdateHostsBconf added in v1.2.0

func (pool *GoPool) UpdateHostsBconf(ctx context.Context, service string, conf bconf.Bconf) (int, error)

Update the nodes for a service, using a bconf node. Creates a ServiceConfig and calls UpdateHostsConfig.

func (*GoPool) UpdateHostsConfig added in v1.2.0

func (pool *GoPool) UpdateHostsConfig(ctx context.Context, service string, hosts map[string]*HostConfig) (int, error)

Update the nodes for a service, e.g. when a new node is detected via Service Discovery. The hosts given replace the old ones for the service. At least one enabled node must be in hosts or the update won't be made, this is to protect from misconfigurations. Returns the number of sb nodes added, i.e. the number of non-disabled IP addresses found. If 0 is returned nothing was changed. Returns NoSuchService if the service given doesn't exist. Might also return errors from DNS lookup and similar.

type HostConfig added in v1.2.0

type HostConfig struct {
	// Name is the dns hostname for this node. If ports only contains a
	// "path" key this can be empty, otherwise it must have a value.
	Name string

	// Ports is a map from portkeys to services (port numbers). The key is checked if it has the suffix "port" or "path". Other entries might be ignored.
	Ports map[string]string

	// Cost is the default cost when successfully using this node. Minimum 1.
	Cost int

	// Disable marks the node as ignored, same as removing it from the slice.
	Disabled bool
}

HostConfig contains a node specific configuration.

type HttpConn

type HttpConn struct {
	Req *http.Request
	Fdc NetConn
	Tls *tls.Conn

	// One of Fdc or Tls, for convenience.
	net.Conn
}

func HttpRequest

func HttpRequest(ctx context.Context, conn NetConn, tlsconf *tls.Config, req *http.Request) (*HttpConn, error)

Send an HTTP request, repeatedly calling conn.Next() as long as they fail. The tls config is required for HTTPS connections.

func (*HttpConn) Close

func (hc *HttpConn) Close() error

func (*HttpConn) ReadResponse

func (hc *HttpConn) ReadResponse(ctx context.Context) (*bufio.Reader, *http.Response, error)

Read the HTTP response. The http package requires a *bufio.Reader so one is created and returned here.

type Logger

type Logger interface {
	Printf(format string, a ...interface{})
}

Logger interface were used to log from this package. It's no longer in use, the slog package is used instead. It will be removed in the 2.0 release.

var (
	DebugLog Logger = defaultLogger(false)
	InfoLog  Logger = defaultLogger(true)
	ErrLog   Logger = defaultLogger(true)
)

type NetConn

type NetConn interface {
	net.Conn

	Put()

	Next(ctx context.Context, status sbalance.ConnStatus) error
	Reset(ctx context.Context) error
	PutReset(ctx context.Context) error

	Peer() string
	PortKey() string
}

Extends net.Conn with functions to move to next node, put back the connection into the pool, and some state extraction.

After you're done using a connection you call either Close or Put. If you chose the latter, the connection will be put back into the pool for later reuse.

If the connection fails for some reason, typically either a timeout or the server giving a "too busy" answer, you can call Next to move the connection to another node in the pool, and then use it again, provided no error was returned. The status should be either sbalance.Fail for a seemingly broken server, or sbalance.TempFail for a more temporary problem. It will return ErrNoServiceNodes if the nodes are depleted and no connection attempt was made. If a connection was attempted but failed the error from the dial function will be returned. After Next any deadlines or other connection specific value set will be removed so you will have to set them again.

Reset can be used to start over from the start. In case of random strat a new node will be chosen. It's rarely used. It will call Close first, while PutReset is the same but calls Put. You must not have called Close or Put if you use these. They have the same return values as Next.

Peer and PortKey gives information about the currently connected to node.

func PutOnClose

func PutOnClose(c NetConn) NetConn

Returns a NetConn that when closed will call Put on the passed conn. Returns nil on nil input.

func PutOnCloseErr

func PutOnCloseErr(c NetConn, err error) (NetConn, error)

PutOnClose version with err passthrough

type PortInfo

type PortInfo struct {
	NodeKey        string `json:"node"`
	Netw           string `json:"network"`
	Addr           string `json:"peer"`
	PortKey        string `json:"port_key"`
	Cost           int    `json:"cost"`
	EffectiveCost  int    `json:"effective_cost"`
	NumStoredConns int    `json:"num_stored_fds"`
}

type ServiceConfig added in v1.2.0

type ServiceConfig struct {
	// Service name, this is used to determine what service to create.
	// Note that if you call AddConfig again with the same Service name
	// it will not update but keep the old values.
	// If empty string a service name will be generated.
	Service string
	// Hosts to add to the service
	Hosts map[string]*HostConfig

	// Connection timeout. If 0 then DefaultConnectTimeout is used.
	ConnectTimeout time.Duration

	// Retries tells sbalance how many times to go through the entire node
	// list.
	Retries int
	// Strat tells sbalance how to select the next node. Defaults to
	// StratSeq. StratRand would probably be a better default but StratSeq
	// is the zero value.
	Strat sbalance.BalanceStrat
	// FailCost is the cost to temporarily set when encountering a hard
	// error (sbalance.Fail)
	FailCost int
	// SoftFailCost is the cost to temporarily set when encountering a soft
	// error (sbalance.SoftFail)
	SoftFailCost int

	// NetNetwork is the network parameter to pass to Dialer for "port"
	// suffix ports. Defaults to "tcp".
	NetNetwork string
	// UnixNetwork is the network parameter to pass to Dialer for "path"
	// suffix ports. Defaults to "unix".
	UnixNetwork string
	// DialContext is used to create new connections. By default a
	// net.Dialer with Timeout set to the configured connect timeout is
	// used.
	// ConnectTimeout will be ignored if this is set.
	DialContext func(ctx context.Context, nw, addr string) (net.Conn, error)

	// Service Discovery configuration, optional.
	// This member is currently experimental and might change even in a minor release.
	// The ambition is to replace it with a similar struct/interface as this one.
	ServiceDiscovery bconf.Bconf
}

func BconfConfig added in v1.2.0

func BconfConfig(conf bconf.Bconf) *ServiceConfig

Converts bconf fd pool configuration to a ServiceConfig struct. The passed conf parameter is stored in the return value in the ServiceDiscovery member.

func (*ServiceConfig) GetConnectTimeout added in v1.2.0

func (c *ServiceConfig) GetConnectTimeout() time.Duration

GetConnectTimeout returns the set ConnectTimeout or DefaultConnectTimeout if unset.

func (*ServiceConfig) GetFailCost added in v1.2.0

func (c *ServiceConfig) GetFailCost() int

GetFailCost returns the set FailCost or DefaultFailCost if unset.

func (*ServiceConfig) GetNetNetwork added in v1.2.0

func (c *ServiceConfig) GetNetNetwork() string

GetNetNetwork returns the set NetNetwork or "tcp" if unset.

func (*ServiceConfig) GetRetries added in v1.2.0

func (c *ServiceConfig) GetRetries() int

GetRetries returns the set Retries or DefaultRetries if unset.

func (*ServiceConfig) GetSoftFailCost added in v1.2.0

func (c *ServiceConfig) GetSoftFailCost() int

GetSoftFailCost returns the set SoftFailCost or DefaultSoftFailCost if unset.

func (*ServiceConfig) GetUnixNetwork added in v1.2.0

func (c *ServiceConfig) GetUnixNetwork() string

GetUnixNetwork returns the set UnixNetwork or "unix" if unset.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL