Operate

Load balancing

Spread PostgreSQL clients across the workers of a fleet.

Client-side multi-host connection strings#

The simplest balancer is the client. libpq accepts several hosts and picks one at random:

libpq
psql 'postgresql://app@worker-a:6432,worker-b:6432/app?load_balance_hosts=random&target_session_attrs=any'

The primary builds this string for you from healthy, non-draining workers: GET /api/v1/fleet/lb/connect?database=&user=&group= returns the hosts, a URL and a keyword form. The console shows it in Gateways, Load balancing.

Exports for HAProxy, nginx and DNS#

GET /api/v1/fleet/lb/export?format=haproxy|nginx|dns|json&group=&name= publishes the worker list in the format of your balancer, and the console has a copy button for each:

  • HAProxy: health checks against /readyz on each worker admin port, and drained workers marked disabled.
  • nginx: a stream block.
  • DNS: A, AAAA and SRV records.
  • JSON: a list of targets for your own tooling.

The StreamQL TCP balancer#

Enable fleet.balancer.enabled on the primary to run a TCP balancer (default 0.0.0.0:6433). It reads the PostgreSQL startup packet and routes by rules before choosing a worker.

KeyDefaultMeaning
fleet.balancer.enabledfalseRun the balancer
fleet.balancer.listen0.0.0.0:6433Listen address
fleet.balancer.zoneemptyZone of this balancer, preferred when zone affinity is on
fleet.balancer.tenant_parameterapplication_nameStartup parameter that carries the tenant for rules
fleet.balancer.connect_timeout_ms3000Time allowed to connect to a worker
  • Rules match the database, user or tenant and send the client to a worker group. The first matching rule wins, and a trailing * matches a prefix.
  • Inside the group the strategy is weighted random (default) or least_connections, with optional zone affinity and drain.
  • Clients that start with TLS are relayed untouched, so only rules without conditions apply to them. Cancel requests go to every worker.
  • Edit the policy in Gateways, Load balancing or with PUT /api/v1/fleet/lb.

Kubernetes services#

The Helm chart exposes the gateway through a Service. By default it is ClusterIP on port 6432 with the admin port 9930. For clients outside the cluster, set gateway.service.type to LoadBalancer and use annotations, loadBalancerClass, externalTrafficPolicy and loadBalancerSourceRanges as your cloud requires. A pod disruption budget (maxUnavailable: 1) and zone spreading keep rolling restarts safe, and /readyz removes a pod from the endpoints before it stops.

helm
helm upgrade streamql deploy/helm/streamql \
  --set gateway.replicaCount=3 \
  --set gateway.service.type=LoadBalancer

Several gateways sharing one connection budget is described in Cluster.