Skip to content

Upstreams and load balancing

Define clusters of upstream endpoints, choose how they are discovered, and pick a load-balancing policy with weights and priorities.

A cluster names a group of upstream endpoints and tells Arion how to reach them: how endpoints are discovered, which protocol to speak, and how to spread load across them. Define one cluster per backend service, then route to it by name.

Define a cluster

clusters:
  - name: api
    type: STATIC
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
    load_assignment:
      endpoints:
        - lb_endpoints:
            - endpoint:
                address:
                  socket_address: { address: 127.0.0.1, port_value: 5678 }
            - endpoint:
                address:
                  socket_address: { address: 127.0.0.1, port_value: 5679 }

Discovery types

typeEndpoints come from
STATICThe inline load_assignment; addresses must be IPs, pipes, or internal
STRICT_DNSThe inline load_assignment, hostnames resolved at connection time
EDSThe control plane over xDS; no inline load_assignment allowed
ORIGINAL_DSTThe connection's original destination, a header, or metadata

ORIGINAL_DST clusters must set lb_policy: CLUSTER_PROVIDED; the target comes from the original destination address by default, or from original_dst_lb_config with use_http_header (default header x-envoy-original-dst-host, or a custom http_header_name) or a metadata_key, optionally overriding the port with upstream_port_override. LOGICAL_DNS is not supported and is refused at startup.

Load-balancing policies

lb_policy accepts ROUND_ROBIN (the default), RANDOM, LEAST_REQUEST, RING_HASH, MAGLEV, and CLUSTER_PROVIDED. Endpoints take a load_balancing_weight (default 1), which every policy respects:

lb_endpoints:
  - endpoint:
      address:
        socket_address: { address: 127.0.0.1, port_value: 5678 }
    load_balancing_weight: 3
  - endpoint:
      address:
        socket_address: { address: 127.0.0.1, port_value: 5679 }
    load_balancing_weight: 1

RING_HASH and MAGLEV are consistent-hashing policies: they need a hash_policy on the route to build the hash from a header, query parameter, or source IP:

route:
  cluster: api
  hash_policy:
    - header: { header_name: x-session-id }
    - connection_properties: { source_ip: true }

Policies apply in order; a matching policy marked terminal: true stops the walk, and if nothing matches the hash is random. The load_balancing_policy extension point accepts the typed equivalents of the same policies plus override_host, which pins the upstream host to the value of a request header and falls back to a standard policy when the header is absent or invalid.

Priorities and failover

Endpoint groups carry a priority (0 is highest; levels must be contiguous from 0). Traffic goes to priority 0 while it is healthy; as its healthy share drops, load spills to the next level following Envoy's priority-levels algorithm with a 1.4 overprovisioning factor:

load_assignment:
  endpoints:
    - priority: 0
      lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 10.0.0.1, port_value: 5678 }
    - priority: 1
      lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 10.1.0.1, port_value: 5678 }

Health comes from active health checks and the endpoint's configured health_status.

Upstream protocol

Arion speaks HTTP/1.1 to upstreams unless the cluster says otherwise through typed_extension_protocol_options:

typed_extension_protocol_options:
  envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
    "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
    explicit_http_config:
      http2_protocol_options: {}

Only explicit configuration is supported (http_protocol_options for HTTP/1.1 with optional enable_trailers, or http2_protocol_options with max_concurrent_streams, initial window sizes, and connection_keepalive); auto-negotiation and use-downstream-protocol are not. common_http_protocol_options.idle_timeout closes idle upstream connections.

Upstream TLS

Add a transport_socket with an UpstreamTlsContext to encrypt traffic to the backend; sni is required:

transport_socket:
  name: envoy.transport_sockets.tls
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
    sni: api.example.com
    common_tls_context:
      validation_context:
        trusted_ca: { filename: ./certs/ca.pem }

Add one tls_certificates entry (or an SDS reference) for mTLS toward the upstream — see TLS and mTLS.

Verify

curl -s http://127.0.0.1:9901/clusters | grep "^api::"
api::127.0.0.1:5678::health_flags::healthy
api::127.0.0.1:5678::weight::3
api::127.0.0.1:5678::priority::0
...

Limits

  • Endpoint locality is not supported — grouping is by priority only, and a config that sets locality is refused.
  • Policy tuning knobs (ring size, Maglev table size, least-request choice count, slow start) are not supported.
  • Outlier detection, subset load balancing, and DNS tuning fields (dns_refresh_rate, respect_dns_ttl) are not supported.
  • One health check and one set of protocol options per cluster.
  • override_host reads a header; metadata as a host source is not yet supported.

The full cluster surface is in the cluster reference, and failure handling continues in health checks and resilience.

Continue

Start typing to search the site.

↑ ↓ to move Enter to open Esc to close