Skip to content

CONCEPT Cited by 1 source

ETag conditional polling

Definition

ETag conditional polling is a cache-coherence protocol in which a client on each poll sends its last-seen ETag (an opaque fingerprint of the resource) and the server replies:

  • 304 Not Modified with an empty body if its current ETag matches (no change; client keeps its cached copy), or
  • 200 OK with the full resource and a new ETag header if anything has changed.

The client stores whichever ETag it last saw and includes it on the next poll. The wire cost of an "unchanged" poll is a minimal request + empty-body response, regardless of resource size.

The semantics come from the standard HTTP ETag / 304 headers, used in this pattern as a delta channel rather than a browser cache.

Canonical instance (internal control plane)

Route Server serves Eskip routing tables to all Skipper pods in a Zalando Kubernetes cluster (Source: sources/2025-02-16-zalando-scaling-beyond-limits-harnessing-route-server-for-a-stable-cluster). Each Skipper polls routesrv with its current ETag; when the routing table is unchanged (the common case — the table only changes when someone applies a new Ingress or RouteGroup), routesrv replies 304 and a 20k-route payload is not sent. Only on change does any Skipper see a 200 OK with a full Eskip payload, which it loads and stores along with the new ETag.

Why it works at scale

The data plane has N clients pinging the control plane at interval Δ. The full-payload cost is O(payload_size) per poll; the ETag-matched cost is O(1) per poll. At Zalando's numbers (300 Skippers × 3-second interval = 100 rps) the control plane serves 100 rps of cheap 304s steady-state, punctuated by brief bursts of full payloads when Ingress/RouteGroup churn. Throughput planning is done on the 304-floor, not the payload-ceiling.

Properties

  • Availability-compatible — a client that can't reach the server simply keeps its last cached copy. Pairs naturally with concepts/last-known-good-routing-table.
  • Cheap fan-out — the server's per-client work is a hash-compare + 304. Scales to the hundreds or thousands of clients seen in proxy meshes.
  • Interval is a freshness-budget knobconcepts/polling-interval-as-freshness-budget. Shorter interval = tighter freshness, more (cheap) polls.
  • ETag granularity is an implementation choice — one per resource vs. one per whole table. A single table-wide ETag (Zalando's choice) means any single route change triggers a full-payload fetch by all clients; per-route ETags would narrow that but complicate the server.

Contrast with push-based protocols

Push streams (server-sent events, gRPC streaming, Kubernetes watch, Envoy xDS) avoid the client-side polling loop and can deliver change events with lower latency. Trade-offs:

  • Connection state per client — every client holds an open stream; server process memory and file descriptors grow with N. ETag polling holds no per-client state on the server.
  • Change-event fan-out — a shared change hitting every client at once is thundering herd–shaped for both, but ETag polling is self-jittered by client clocks starting at different moments.
  • Freshness — push wins on median propagation, ETag polling's floor is the interval.

Zalando's Route Server explicitly chose HTTP + ETag over informers / streams for the simplicity and the absence of per-client server state (Source: sources/2025-02-16-zalando-scaling-beyond-limits-harnessing-route-server-for-a-stable-cluster).

See also

Last updated · 501 distilled / 1,218 read