Automatic Persisted Queries (APQ) hash-cache consistency in distributed clusters
0 reputation · 01 Sept 2020, 19:24 UTC
0 reputation · 01 Sept 2020, 19:24 UTC
Automatic Persisted Queries (APQ) optimize network latency by replacing full query strings with SHA-256 hashes. In a standard Apollo Server configuration, the server maps these hashes to the original query strings in a local cache to avoid the overhead of transmitting large payloads on every request.
When deploying Apollo Server across a distributed cluster of multiple pods or instances without a centralized caching layer, the hash-to-query mapping is stored independently on each node. This creates a scenario where a client may successfully resolve a hash on one node but receive a PersistedQueryNotFound error if a subsequent request is routed to a node that has not yet cached that specific hash.
Given this architecture, what are the recommended strategies for maintaining hash consistency across nodes to prevent repeated two-step handshakes? Is there a native configuration to synchronize these mappings, or is an external cache implementation required for stability?
33275 reputation · 02 Sept 2020, 00:17 UTC
In a multi‑pod deployment the default in‑process APQ cache is per‑process. There is no built‑in cluster‑wide synchronization, so a hash that is cached on one node will be missing on another, leading to the two‑step handshake. The only reliable way to keep hash‑to‑query mappings consistent across all nodes is to store them in a shared cache (Redis, Memcached, Hazelcast, etc.) or to implement a custom PersistedQueryCache that forwards every get and set to that shared store.
PersistedQueryCache interface and delegates to the shared store.
persistedQueries.cache.
persistedQueries.debug to log cache hits and misses; verify that all nodes hit the shared store.
PersistedQueryNotFound errors.
Load‑balancer session affinity can reduce the frequency of handshakes, but it is fragile (IP changes, client reconnections) and does not eliminate the problem in a true round‑robin setup. Use it only as a temporary mitigation until a shared cache is in place.
If you run an Apollo Gateway, configure the gateway itself to use a shared persisted query cache. This centralizes the mapping for all sub‑services and removes duplication across services.
Do you currently use a load balancer that supports sticky sessions? If so, it can reduce the number of two‑step handshakes but is not a substitute for a shared cache.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.