Akka Cluster Sharding: remember-entities vs passivation-only for sub-second recovery SLO
0 reputation · 19 Oct 2022, 13:11 UTC
0 reputation · 19 Oct 2022, 13:11 UTC
We operate a 6-node Akka 2.9 cluster (Scala 3.3) hosting roughly 120,000 sharded entities of a single type. Each entity holds ~5 KB of event-sourced state. Our SLO requires p99 entity availability within 800 ms after a node loss or shard rebalance.
The rememberEntities flag is entity-type global and immutable without a full rolling restart. Enabling it persists shard-to-entity mappings to our Cassandra journal, guaranteeing automatic restart but adding journal read + event replay latency (observed 1.2–3 s per entity in staging). Passivation-only avoids this latency but drops passivated entities on rebalance; recovery then depends on external traffic rehydrating each entity via its command handler, which is non-deterministic and can exceed the SLO during burst rebalances.
No built-in hybrid mode exists (e.g., TTL-backed persistence for recently active entities only). We could split the workload into two entity types—one with rememberEntities=true for hot entities, one without for cold—but that introduces routing complexity and duplicate sharding infrastructure.
What is the recommended pattern to meet a sub-second recovery SLO for a large, mixed-temperature entity population without operating two separate sharding topologies? Can the journal read path be optimized (e.g., Cassandra local reads, snapshot frequency) to bring rememberEntities recovery under 800 ms at this scale? Are there documented cases of using Akka Distributed Data or a custom ShardAllocationStrategy to approximate hybrid behavior?
33775 reputation · 19 Oct 2022, 19:18 UTC
For a single entity type with roughly 120,000 entities on Akka 2.9, the recommended pattern is to enable rememberEntities = true and tune the persistence path to bring replay under 800 ms. Passivation-only recovery depends on external traffic and cannot guarantee a strict p99 SLO during burst rebalances. Splitting into hot and cold entity types is the only hybrid mode Akka core supports, but you do not need two full sharding topologies if the journal replay is fast enough.
rememberEntities is an entity-type-level flag; there is no runtime toggle in the 2.9.x line. Changing it requires a rolling restart or a blue/green entity-type migration.ShardAllocationStrategy controls shard placement only; it cannot influence whether an entity is restarted.StartEntity messages and adds operational risk.The observed latency most likely comes from cross-datacenter Cassandra reads or missing snapshots rather than inherent Akka overhead. With ~5 KB of state per entity, snapshotting every 50–100 events typically reduces replay to a few hundred milliseconds when reads stay in the local datacenter.
read-consistency = LOCAL_ONE (or LOCAL_QUORUM if stale entity IDs are unacceptable) and ensure journal and snapshot tables use NetworkTopologyStrategy with local-DC replication only.snapshot-after to 50–100 events and set snapshot-isolation = off for the Cassandra plugin to avoid lightweight-transaction overhead. Provision Cassandra write capacity for 2–3× the current event rate.passivate-idle-entity-after exceeds the expected rebalance window; otherwise hot entities passivate mid-rebalance and defeat rememberEntities.akka.persistence.cassandra.journal.replay-filter.mode = off to skip filter overhead.Trace a single journal read to confirm local-DC latency:
cqlsh> TRACING ON;
cqlsh> SELECT * FROM journal WHERE persistence_id = 'entity-123';
Run a staged rebalance with rememberEntities = true, 600 shards, and the snapshot settings above. Capture p99 recovery from ClusterSharding metrics (shard-started, entity-started) and confirm the snapshot store uses the same local DC with write-consistency = LOCAL_QUORUM. Because plugin defaults can shift across patch releases, validate every config key against your exact Akka and Cassandra plugin version before production rollout.
Is your Cassandra deployment single-DC or multi-DC, and are the journal and snapshot tables restricted to local-DC replication? If cross-DC reads are unavoidable, the tuning above may still miss the 800 ms target and you should evaluate a local read replica or a local snapshot cache before increasing snapshot frequency further.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 19 Oct 2022, 14:44 UTC
While tuning Cassandra and snapshot frequency can lower individual entity recovery time, enabling rememberEntities for 120,000 entities introduces a systemic risk: the thundering herd effect during node recovery.
When a node fails, the ShardCoordinator attempts to restart all remembered entities assigned to that node simultaneously. Even if individual replay is under 800ms, the aggregate pressure on the journal and the JVM heap can cause cascading timeouts or GC pauses that push p99 availability well beyond the SLO.
OutOfMemoryError if the entity state is larger than expected.