loadbalancer

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package loadbalancer is the product-level load balancer model layered on the embedded Caddy reverse_proxy upstream pool (internal/ingress).

Index

Constants

View Source
const (
	AlgoRoundRobin = "round_robin"
	AlgoLeastConn  = "least_conn"
	AlgoIPHash     = "ip_hash"
	AlgoURIHash    = "uri_hash"
	AlgoCookie     = "cookie"
	AlgoWeighted   = "weighted"
)

Algorithms selectable in Config.Algorithm.

View Source
const (
	StateHealthy   = "healthy"
	StateUnhealthy = "unhealthy"
	StateDraining  = "draining"
	StateUnknown   = "unknown"
	StateDisabled  = "disabled"
)

Upstream states reported by BuildStatus.

View Source
const (
	AdminActive   = "active"
	AdminDraining = "draining"
	AdminDisabled = "disabled"
)

Operator-set admin states for one upstream.

View Source
const MaxWeight = 100

MaxWeight caps a per-upstream weight.

Variables

This section is empty.

Functions

func Algorithms

func Algorithms() []string

Algorithms lists every valid algorithm in display order.

func DefaultCheckTimeout

func DefaultCheckTimeout() time.Duration

DefaultCheckTimeout is the probe timeout when no active health check is configured, overridable with APP_LB_CHECK_TIMEOUT.

func EffectiveWeights

func EffectiveWeights(cfg Config, ups []Upstream, firstSeen map[string]time.Time, now time.Time) []int

EffectiveWeights returns one weight per upstream. When slow start is set, an upstream first seen less than SlowStart ago ramps linearly from 1 to its configured weight. Only meaningful for the weighted algorithm.

func ParseDuration

func ParseDuration(s string) time.Duration

ParseDuration parses a validated duration string, returning zero for empty.

func ParseUpstreamReplica

func ParseUpstreamReplica(service, id string) (int, bool)

ParseUpstreamReplica extracts the replica index from an ID built by UpstreamID for service.

func UpstreamID

func UpstreamID(service string, replica int) string

UpstreamID builds the stable ID for a service replica.

func ValidAdminState

func ValidAdminState(s string) bool

ValidAdminState reports whether s is one of the admin states.

Types

type ActiveHealth

type ActiveHealth struct {
	Path         string `yaml:"path" json:"path"`
	Interval     string `yaml:"interval,omitempty" json:"interval,omitempty"`
	Timeout      string `yaml:"timeout,omitempty" json:"timeout,omitempty"`
	Passes       int    `yaml:"passes,omitempty" json:"passes,omitempty"`
	Fails        int    `yaml:"fails,omitempty" json:"fails,omitempty"`
	ExpectStatus int    `yaml:"expect_status,omitempty" json:"expect_status,omitempty"`
}

ActiveHealth probes each upstream on an interval.

type CaddyAdminStats

type CaddyAdminStats struct {
	// Addr is the admin listen address, e.g. "localhost:2019".
	Addr   string
	Client *http.Client
}

CaddyAdminStats reads counters from Caddy's admin /reverse_proxy/upstreams.

func (CaddyAdminStats) UpstreamStats

func (c CaddyAdminStats) UpstreamStats(ctx context.Context) (map[string]Stats, error)

UpstreamStats implements StatsSource.

type CheckGate

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

CheckGate rate limits check-now per service.

func CheckGateFromEnv

func CheckGateFromEnv() *CheckGate

CheckGateFromEnv sizes the gate from APP_LB_CHECK_MIN_INTERVAL (default 2s).

func NewCheckGate

func NewCheckGate(interval time.Duration) *CheckGate

NewCheckGate returns a gate allowing one check per service per min.

func (*CheckGate) Allow

func (g *CheckGate) Allow(service string, now time.Time) (time.Duration, bool)

Allow reports whether service may run a check at now; when not, it returns how long to wait.

type CheckOutcome

type CheckOutcome struct {
	Results []CheckResult
	// Note is set when the balancer has no active health check configured.
	Note   string
	Status Status
}

CheckOutcome is the result of CheckNow.

func CheckNow

func CheckNow(ctx context.Context, reg *Registry, obs Observation, stats map[string]Stats, prober Prober) CheckOutcome

CheckNow probes every running upstream once, in parallel and bounded by the probe timeout, using the configured active health check (or GET / when none is set). It records the results into reg and returns them.

type CheckRecord

type CheckRecord struct {
	At         time.Time `json:"at"`
	OK         bool      `json:"ok"`
	StatusCode int       `json:"status_code"`
	LatencyMs  int64     `json:"latency_ms"`
	Reason     string    `json:"reason"`
}

CheckRecord is one health probe outcome.

type CheckResult

type CheckResult struct {
	ID         string `json:"id"`
	Dial       string `json:"dial"`
	OK         bool   `json:"ok"`
	StatusCode int    `json:"status_code"`
	LatencyMs  int64  `json:"latency_ms"`
	Reason     string `json:"reason"`
}

CheckResult is one upstream's outcome from a check-now run.

type Config

type Config struct {
	Algorithm  string `yaml:"algorithm,omitempty" json:"algorithm,omitempty"`
	CookieName string `yaml:"cookie_name,omitempty" json:"cookie_name,omitempty"`
	// Weights is indexed by replica number; missing entries default to 1.
	Weights        []int          `yaml:"weights,omitempty" json:"weights,omitempty"`
	ActiveHealth   *ActiveHealth  `yaml:"active_health,omitempty" json:"active_health,omitempty"`
	PassiveHealth  *PassiveHealth `yaml:"passive_health,omitempty" json:"passive_health,omitempty"`
	Retries        *Retries       `yaml:"retries,omitempty" json:"retries,omitempty"`
	SlowStart      string         `yaml:"slow_start,omitempty" json:"slow_start,omitempty"`
	DrainTimeout   string         `yaml:"drain_timeout,omitempty" json:"drain_timeout,omitempty"`
	RequestTimeout string         `yaml:"request_timeout,omitempty" json:"request_timeout,omitempty"`
	RateLimit      *RateLimit     `yaml:"rate_limit,omitempty" json:"rate_limit,omitempty"`
	UpstreamTLS    *UpstreamTLS   `yaml:"upstream_tls,omitempty" json:"upstream_tls,omitempty"`
}

Config is one service's load balancer settings. A nil *Config means the service has no load balancer and keeps its single-upstream route.

func (Config) Defaults

func (c Config) Defaults() Config

Defaults returns a copy of c with unset optional fields filled in.

func (*Config) EffectiveAlgorithm

func (c *Config) EffectiveAlgorithm() string

EffectiveAlgorithm returns the configured algorithm or the default.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks c and returns a *ValidationError listing all problems.

type HTTPProber

type HTTPProber struct{}

HTTPProber is the real Prober.

func (HTTPProber) Probe

func (HTTPProber) Probe(ctx context.Context, dial, path string, upstreamTLS *UpstreamTLS, timeout time.Duration) ProbeResult

Probe implements Prober.

type HistoryConfig

type HistoryConfig struct {
	Checks       int
	Transitions  int
	SeriesStep   time.Duration
	SeriesWindow time.Duration
	MaxAge       time.Duration
}

HistoryConfig bounds the in-memory per-upstream history.

func HistoryConfigFromEnv

func HistoryConfigFromEnv() HistoryConfig

HistoryConfigFromEnv reads the history bounds, falling back to defaults.

type Observation

type Observation struct {
	Service    string                `json:"service"`
	Config     Config                `json:"config"`
	Upstreams  []UpstreamObservation `json:"upstreams"`
	Reason     string                `json:"reason"`
	Message    string                `json:"message"`
	Ready      bool                  `json:"ready"`
	ObservedAt time.Time             `json:"observed_at"`
}

Observation is the reconciler's last view of one service's balancer.

type PassiveHealth

type PassiveHealth struct {
	FailDuration string `yaml:"fail_duration,omitempty" json:"fail_duration,omitempty"`
	MaxFails     int    `yaml:"max_fails,omitempty" json:"max_fails,omitempty"`
}

PassiveHealth marks an upstream down after failures seen on live traffic.

type ProbeResult

type ProbeResult struct {
	OK         bool
	StatusCode int
	Latency    time.Duration
	Err        string
	CheckedAt  time.Time
}

ProbeResult is one active health check outcome.

type Prober

type Prober interface {
	Probe(ctx context.Context, dial, path string, tlsCfg *UpstreamTLS, timeout time.Duration) ProbeResult
}

Prober runs an active health check against one upstream.

type RateLimit

type RateLimit struct {
	RPS   int `yaml:"rps" json:"rps"`
	Burst int `yaml:"burst,omitempty" json:"burst,omitempty"`
}

RateLimit caps requests per second per client address.

type Registry

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

Registry shares reconciler observations with the API and telemetry.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry with history sized from the environment.

func NewRegistryWithHistory

func NewRegistryWithHistory(cfg HistoryConfig) *Registry

NewRegistryWithHistory returns an empty Registry with explicit history bounds.

func (*Registry) FirstSeen

func (r *Registry) FirstSeen(service string, ids []string, now time.Time) map[string]time.Time

FirstSeen records the first time each upstream ID was seen for service and forgets IDs no longer present. The first call for a service treats every upstream as long-running so a process restart does not restart slow start.

func (*Registry) Get

func (r *Registry) Get(service string) (Observation, bool)

Get returns the latest observation for service.

func (*Registry) History

func (r *Registry) History(st Status, limit int) []UpstreamHistory

History returns the recorded history for every upstream in st, checks capped to limit (0 means the ring size).

func (*Registry) List

func (r *Registry) List() []Observation

List returns every recorded observation.

func (*Registry) Record

func (r *Registry) Record(o Observation)

Record stores the latest observation for a service.

func (*Registry) RecordStatus

func (r *Registry) RecordStatus(st *Status)

RecordStatus records st into the history (probe results, state transitions, sampled series) and fills each upstream's LastChangedAt. History is in memory and resets when the control plane restarts.

func (*Registry) Retain

func (r *Registry) Retain(keep map[string]bool)

Retain drops state for services not in keep.

type Retries

type Retries struct {
	Count       int    `yaml:"count,omitempty" json:"count,omitempty"`
	TryDuration string `yaml:"try_duration,omitempty" json:"try_duration,omitempty"`
	TryInterval string `yaml:"try_interval,omitempty" json:"try_interval,omitempty"`
}

Retries controls how a failed request is retried on another upstream.

type SeriesPoint

type SeriesPoint struct {
	At    time.Time `json:"at"`
	Value float64   `json:"value"`
}

SeriesPoint is one sampled value.

type SeriesSet

type SeriesSet struct {
	Connections []SeriesPoint `json:"connections"`
	LatencyMs   []SeriesPoint `json:"latency_ms"`
	Fails       []SeriesPoint `json:"fails"`
}

SeriesSet is the short per-upstream sample series.

type Stats

type Stats struct {
	NumRequests int `json:"num_requests"`
	Fails       int `json:"fails"`
}

Stats are live counters for one upstream address from the proxy.

type StatsSource

type StatsSource interface {
	UpstreamStats(ctx context.Context) (map[string]Stats, error)
}

StatsSource reports live proxy counters keyed by dial address.

type Status

type Status struct {
	Service    string           `json:"service"`
	Algorithm  string           `json:"algorithm"`
	Ready      bool             `json:"ready"`
	Reason     string           `json:"reason"`
	Message    string           `json:"message"`
	ObservedAt time.Time        `json:"observed_at"`
	Upstreams  []UpstreamStatus `json:"upstreams"`
}

Status is the API view of one service's load balancer.

func BuildStatus

func BuildStatus(ctx context.Context, obs Observation, stats map[string]Stats, prober Prober) Status

BuildStatus merges an observation with proxy counters and active probes. stats and prober may be nil.

type Transition

type Transition struct {
	At     time.Time `json:"at"`
	From   string    `json:"from"`
	To     string    `json:"to"`
	Reason string    `json:"reason"`
}

Transition is one upstream state change.

type Upstream

type Upstream struct {
	// ID is stable across passes (service name plus replica index), used to
	// track first-seen time for slow start.
	ID      string `json:"id"`
	Dial    string `json:"dial"`
	Replica int    `json:"replica"`
	// NodeID is empty for the control plane's own node.
	NodeID string `json:"node_id,omitempty"`
}

Upstream is one replica endpoint the balancer can send traffic to.

type UpstreamHistory

type UpstreamHistory struct {
	ID          string        `json:"id"`
	Dial        string        `json:"dial"`
	AdminState  string        `json:"admin_state"`
	Checks      []CheckRecord `json:"checks"`
	Transitions []Transition  `json:"transitions"`
	Series      SeriesSet     `json:"series"`
}

UpstreamHistory is the recorded history of one upstream.

type UpstreamObservation

type UpstreamObservation struct {
	Upstream
	Running bool `json:"running"`
	// Draining marks a previous-release container kept in the pool while the
	// new release is not ready yet.
	Draining bool   `json:"draining,omitempty"`
	Weight   int    `json:"weight"`
	Note     string `json:"note,omitempty"`
	// AdminState is the operator's choice; empty means active.
	AdminState string `json:"admin_state,omitempty"`
}

UpstreamObservation is what the reconciler saw for one upstream.

func (UpstreamObservation) InPool

func (u UpstreamObservation) InPool() bool

InPool reports whether the upstream may receive new connections.

type UpstreamStatus

type UpstreamStatus struct {
	ID          string     `json:"id"`
	Dial        string     `json:"dial"`
	NodeID      string     `json:"node_id,omitempty"`
	Replica     int        `json:"replica"`
	Weight      int        `json:"weight"`
	State       string     `json:"state"`
	Healthy     bool       `json:"healthy"`
	ActiveConns int        `json:"active_connections"`
	Fails       int        `json:"fails"`
	LastCheck   *time.Time `json:"last_check,omitempty"`
	LatencyMs   int64      `json:"latency_ms,omitempty"`
	Reason      string     `json:"reason,omitempty"`
	AdminState  string     `json:"admin_state"`
	// LastChangedAt is when State last changed, or when it was first observed.
	LastChangedAt *time.Time `json:"last_changed_at,omitempty"`
	// contains filtered or unexported fields
}

UpstreamStatus is the live view of one upstream.

type UpstreamTLS

type UpstreamTLS struct {
	InsecureSkipVerify bool   `yaml:"insecure_skip_verify,omitempty" json:"insecure_skip_verify,omitempty"`
	ServerName         string `yaml:"server_name,omitempty" json:"server_name,omitempty"`
}

UpstreamTLS makes the proxy speak HTTPS to upstreams.

type ValidationError

type ValidationError struct{ Problems []string }

ValidationError lists every problem found in a Config.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
Package lbexport renders a load balancer config as Terraform, CDK, CloudFormation, Caddyfile or Caddy JSON.
Package lbexport renders a load balancer config as Terraform, CDK, CloudFormation, Caddyfile or Caddy JSON.

Jump to

Keyboard shortcuts

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