CX High Availability: Within a Site

EFCX High Availability Within a Site

Overview

This covers how to make a single data center highly available on its own: a multi-node cluster within that one site, sized and configured so that losing a pod, a node, or a host doesn’t take the platform down. This is the foundation. A second site for disaster recovery is a separate, later concern that builds on top of a properly highly-available single site.

High availability within one site works at two layers: the cluster/infrastructure layer underneath everything, and the component layer, how each individual stateful service (database, cache, message broker, object storage) is itself deployed for local redundancy.

Infrastructure layer

Cluster/infrastructure layer: a multi-master control plane with quorum, multiple worker nodes, and a load-balancer pair in front of the cluster, none of which is a single point of failure on its own.

Layer

Pattern

Notes

Control plane

Multiple master nodes (an odd number, three is the tested minimum) with a clustered consensus store for the control plane’s own state

A single master has no quorum to fall back on if it’s lost. At higher workload, master nodes are typically dedicated to control-plane duty only rather than also scheduling application pods.

Worker nodes

Multiple worker nodes (three is the tested minimum)

On a worker loss, pods reschedule to survivors within Kubernetes’ default relocation window (5 to 10 minutes, deliberately not instant, to avoid pods hopping on a transient blip). Workload does not automatically rebalance back once a recovered node rejoins, only new work lands there; evening the load back out needs a deliberate, planned restart of the affected workloads, which itself causes an outage.

External load balancer

A failover pair fronting the cluster, not a single instance

A single load balancer is a documented single point of failure; production sizing calls for a failover cluster of at least two.

Storage under the CSI layer

Storage that is itself replicated across nodes within the site, not tied to a single node

So a node loss doesn’t strand a volume behind it. Earlier on-prem material documents this as an explicit add-on layer (raw block devices pooled into replicated storage) built specifically for platforms that don’t already provide multi-node storage redundancy; a converged, cloud-native platform typically provides that natively through its own CSI driver instead, without needing a separate add-on. Confirm which is actually the case for the platform in use before assuming either.

Component layer

Component layer: each stateful service deployed as its own multi-replica cluster local to the site, with automatic promotion of a surviving replica if the current primary is lost, rather than a single instance per service that has to be rescheduled and reattached to its volume.

Component

Pattern

Tested result

Rough edge found in testing

MongoDB (conversation and customer data)

N-node replica set plus one arbiter for the tie-breaking vote, replica count set per available worker nodes, anti-affinity keeping the replica off the same node as the primary

On primary-pod loss, a surviving replica is automatically promoted

The arbiter ran out of memory under test, and Mongo also attempted to bring the original primary back online on another node some hours later; the documented fix was to drop the arbiter from the connection string once elections had already been proven to work without it in the loop

Redis (session and cache state)

Sentinel-managed replica set, anti-affinity between replicas

On primary-pod loss, a surviving replica is automatically promoted

None recorded

PostgreSQL (License Manager, Keycloak data)

Managed replica set with automated failover, three replicas by default

On primary-pod loss, a surviving replica is automatically promoted; running in asynchronous mode was the documented performance tuning

None recorded beyond the async-mode tuning note

MinIO (attachments, recordings, object storage)

Distributed mode, an even replica count of four or more, one drive per node, anti-affinity

Tested successfully

None recorded

ActiveMQ / Artemis (message bus)

A single pod backed by replicated storage rather than a peer cluster of its own; recovery depends on the storage layer reattaching to a new pod, not on an application-level election

A new pod is created and takes over the replicated storage after the default relocation window

The replacement pod sometimes got stuck in scheduling and needed a forced pod deletion to recover

Keycloak (authentication)

No built-in HA of its own; sits entirely on top of the HA PostgreSQL above

A new pod is created after the relocation window and reconnects to PostgreSQL

Recovery is gated on PostgreSQL’s own recovery completing first, not just on Keycloak’s pod restarting; the same stuck-pod caveat as ActiveMQ applies if the new pod doesn’t schedule cleanly

CX application pods (conversation manager, routing engine, and the rest of core)

Stateless; conversation and routing state lives in MongoDB, Redis, and the message bus rather than in the pod

A fresh pod picks the work back up once rescheduled

Spin-up issues were seen in two components’ init containers after a cross-node move, worked around at the time by disabling those init containers

What this buys

Because every stateful component runs as its own local replica set rather than a single instance, a pod or node loss within the site is absorbed by an already-running local replica, an in-cluster election on the order of seconds, rather than waiting on Kubernetes to reschedule a replacement pod and reattach its volume with nothing local standing by in the meantime.

Trade-offs

  • Standing capacity. Multiple replicas of every stateful component, local to the one site, rather than a single instance each.

  • Per-component configuration, not one platform-level mechanism. Each service needs its own replica count, quorum member (arbiter or Sentinel), and anti-affinity rule configured and tested individually.

  • Its own local quorum. The arbiter/Sentinel/etcd quorum here arbitrates between replicas within the one site. If a second site is added later for disaster recovery, that typically introduces its own separate mechanism for arbitrating between sites, on top of this one, not instead of it.

Sources

Earlier EFCX geographical-deployment and Kubernetes-operations material in the CX Knowledge Base: the geographical-deployment-with-redundancy guide’s HA testing results and component configuration, the multi-node-cluster failover scenarios guide, the control-plane node failover procedure, and the external-load-balancer high-availability guide.