Skip to main content
RunBook Academy

LinuxLVIII · Clustered Service ArchitectureConstraints

Application architecture constraints - the limits of clustering

Advanced⏱ ~10 minbash

What you'll learn

  • Identify application-level constraints on clustering
  • Distinguish clustering-friendly from clustering-hostile designs
  • Recognise common anti-patterns
  • Design for clustering at the application level

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

The cluster is only as good as the application design. An application that is not cluster-friendly cannot be made cluster-friendly by adding nodes. This lesson covers the application-level constraints.

Common anti-patterns

Local file system state

Storing data in /var/lib/myapp ties the state to one host. A cluster that uses this data is not really a cluster.

Fix: externalise to a database, object store, or shared filesystem.

In-memory state

Session state, caches, locks in process memory. A second instance does not share the state.

Fix: external state in Redis or a database. Stateless application.

Hard-coded IPs and hostnames

db_host = "10.0.0.10"   # hard-coded

A second instance points to the same DB. If the DB moves, the app breaks.

Fix: service discovery (DNS, Consul, etcd).

Synchronous cross-host calls

# A calls B, B calls C, B waits for C
result = call_b()
# B is blocked while C is processing

A cluster of these is a cluster of bottlenecks.

Fix: async messaging (Kafka, RabbitMQ, SQS).

Long-running synchronous operations

A 30-second database query blocks the thread. A cluster of these is a cluster of slow requests.

Fix: async processing, pagination, or query optimisation.

Design for clustering

For a cluster-friendly application:

  • Stateless where possible: any instance handles any request.
  • External state: database, cache, or object store.
  • Service discovery: by name, not IP.
  • Async where possible: messaging over synchronous calls.
  • Timeouts everywhere: never wait forever for a dependency.
  • Retries with backoff: failures are expected; design for them.
  • Circuit breakers: stop calling a failing dependency instead of timing out.
  • Bulkheads: isolate failure domains (one slow dependency does not block the whole service).

Twelve-factor app

The 12-factor app methodology captures these patterns:

  1. One codebase, many deploys.
  2. Explicit dependencies.
  3. Config in environment.
  4. Backing services as attached resources.
  5. Build, release, run stages.
  6. Stateless processes.
  7. Port binding.
  8. Concurrency.
  9. Disposability (fast startup, graceful shutdown).
  10. Dev/prod parity.
  11. Logs as event streams.
  12. Admin processes.

A 12-factor app is cluster-friendly by design.

Migration path

For legacy applications:

  1. Externalise the most critical state (database, sessions).
  2. Add service discovery.
  3. Add async messaging where the synchronous calls are painful.
  4. Make the application stateless over time.

This is a multi-quarter project. Each step reduces the clustering pain.

Knowledge check

Knowledge check · 3 questions

  1. Q1. What is the most common application-level anti-pattern for clustering?

  2. Q2. Adding nodes to a cluster fixes a stateful application.

  3. Q3. Which of the following are application-level constraints on clustering? Select all that apply.

Passing score: 75%. Answers are checked in this browser.