Choosing between in‑memory and Redis‑backed caching in Moleculer for latency‑critical services
0 reputation · 15 Nov 2023, 10:12 UTC
0 reputation · 15 Nov 2023, 10:12 UTC
Goal: select a caching mechanism that meets the latency budget of a production API while ensuring cached data survives process restarts and is consistent across multiple instances.
Constraints: the native in‑memory cache delivers sub‑millisecond read times but is lost on restart and does not share state between nodes; the moleculer‑cache plugin with Redis adds network round‑trip latency, introduces dependency on Redis availability, and may exhibit different TTL expiration semantics depending on the plugin version and Redis configuration.
Uncertainty: how the combined latency of a Redis round‑trip compares to the latency budget under peak load, and whether occasional Redis connectivity glitches will cause cache misses or errors that affect SLA.
What is the acceptable latency increase when using Redis‑backed caching for a typical request path?
How should TTL and invalidation policies be aligned between the two stores to avoid stale data after a restart?
What fallback behavior should be configured for the moleculer‑cache plugin when Redis is temporarily unreachable?
31775 reputation · 15 Nov 2023, 10:45 UTC
If your data must survive restarts and stay consistent across multiple service instances, use the Redis-backed cacher — but only after measuring whether the added round-trip fits your latency budget. For single-instance services or data that can be safely recomputed, the built-in memory cacher is the right default. The two are not interchangeable: they answer different consistency requirements, so the decision should be driven by your staleness tolerance, not by latency alone.
There is no universal number — the acceptable increase is whatever remains in your per-request latency budget after the downstream work. The overhead comes from three places: network round-trip time to Redis, serialization/deserialization of cached values, and connection handling. On a same-host or same-AZ Redis with small payloads, a cache read commonly lands in the low single-digit millisecond range, versus effectively sub-millisecond for in-memory. Whether that is acceptable depends entirely on your p99 target.
The only reliable way to decide is to measure in staging:
If the Redis read pushes you over budget, a two-tier pattern is worth considering: a short-TTL in-memory layer in front of Redis, which absorbs hot reads while Redis remains the shared source of truth. This adds invalidation complexity, so adopt it only when measurements justify it.
The stale-data risk after a restart comes from asymmetry: memory cache dies with the process, Redis does not. To keep behavior predictable:
redis-cli monitor or TTL <key> in staging, because expiration semantics can differ between cacher versions and Redis configurations — treat this as a verify-before-deploy item.clean on specific keys or patterns triggered by domain events). This is what makes cross-instance consistency work: an update on node A invalidates the shared Redis entry, so node B never serves the old value. With pure in-memory caching, node B has no way to know.A Redis outage must degrade to a cache miss, not a request failure. Concretely:
Simulate the failure before you ship: stop Redis in staging under load and confirm requests degrade to slower-but-successful responses within SLA, then recover cleanly when Redis returns.
Multi-instance deployment or restart-survival requirement → Redis cacher with event-based invalidation, fail-fast client settings, and miss-on-error fallback. Single instance, recomputable data, tightest possible latency → memory cacher. If latency measurements rule out Redis for the hottest path, layer a short-TTL memory cache in front of Redis rather than abandoning shared state entirely. The one detail that could change this recommendation is your measured p99 budget per request — if it is under ~5 ms end-to-end, the two-tier design stops being optional.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.