Archive Retention and Purge: How Much Log Can You Delete?
Your archive volume is filling up and someone wants to delete old cluster-log segments. The archive
API will happily let you. purgeSegments knows about segment boundaries and active recordings — it
knows nothing about whether the bytes you are deleting are the only thing standing between a node and
a rebuild.
This page is the missing check. It gives you the positions to measure, the invariant that decides restart-vs-rebuild, and a purge procedure that fails safe. For what happens after a node fails, see Snapshot Failure and Recovery; for the backup that underwrites the rebuild path, Backups and Disaster Recovery.
The one question this scenario turns on
Section titled “The one question this scenario turns on”Before you delete anything, and before you start a node that has been offline, you are answering a single question: can this node restart normally, or must it be rebuilt?
| Node’s local state | Live source retains log from ≤ its position? | Verdict |
|---|---|---|
| Complete snapshot set + contiguous local log | Yes (L ≤ P) | Normal restart. Local snapshot load → local replay → leader catch-up. |
| Complete snapshot set + contiguous local log | No (L > P) | Rebuild. Catch-up has a gap that no restart will close. |
| No snapshot, local log contiguous from position 0 | Yes | Normal restart, full local replay. Slow but valid. |
| No snapshot, local log starts after 0 | — | Rebuild unless this is a deliberately rebased, tested image. |
| Latest snapshot commits but won’t load | Prior set + its log retained | invalidate-latest-snapshot, then re-test this table. |
| Empty disk (replaced instance) | Live source retains from 0 | Restart works, but usually slower than provisioning a backup. |
| Empty disk | Live source purged past 0 | Rebuild from a verified image. No exceptions. |
Everything below is how to measure L and P, and how to purge without ever pushing a node from row
1 into row 2.
The five positions
Section titled “The five positions”Retention decisions made on age — “keep seven days” — are proxies for the thing that actually matters, which is position. Measure these:
| Term | Meaning | Where to read it |
|---|---|---|
S | Log position of one complete snapshot set | ClusterTool recovery-plan |
A | Earliest position still physically present in the node’s cluster-log recording | ArchiveTool describe |
P | End of log locally available to the restarting node (append position) | ClusterTool recovery-plan / archive descriptor |
L | Earliest position the chosen live source can replay or replicate | ArchiveTool describe on that source |
C | Proposed new recording start after purge (the cutoff) | your purge plan |
A complete snapshot set is one consensus-module snapshot (serviceId = -1) plus one snapshot for
every configured service, all at the same leadership term and log position. A set missing one service
is not a fallback — it is nothing.
Two invariants follow directly.
Local snapshot recovery works when:
A ≤ S ≤ PA stale node can catch up when:
L ≤ PAnd because purge operates on segment boundaries, the usable local cutoff is:
C = greatest valid segment boundary such that C ≤ SNever round C up past S. Local recovery starts its replay at the snapshot position; take the log
at S away and the snapshot you carefully retained becomes unusable.
Pick a retention model, and write it down
Section titled “Pick a retention model, and write it down”The invariants above have a policy consequence that most teams leave implicit until an incident forces it. Choose deliberately:
Model A — any configured member may restart normally. For every member you retain a complete verified snapshot set, its subsequent local log, and enough log on the live source to bridge from that member’s last verified append position. You never purge past an offline member’s recovery position. This caps how aggressively you can reclaim disk, and one long-offline node holds the whole cluster’s retention hostage.
Model B — nodes outside the window are rebuilt. You retain enough for recent restarts, run a
continuously verified ClusterBackup, and let older log go. A node outside the window is reclassified
as a rebuild, not a restart.
Model B is the right default for replaceable cloud instances, and it is the honest one: it makes the backup load-bearing and forces you to test it. Model A quietly promises normal restart for a node nobody has checked in weeks.
Before you start a stale node: the go/no-go gate
Section titled “Before you start a stale node: the go/no-go gate”Starting a node because its files exist is how a 20-minute rebuild becomes a 4-hour outage. Run this first, with the node stopped.
1. Collect the facts
Section titled “1. Collect the facts”AERON_ALL_JAR=/opt/aeron/aeron-all.jarCLUSTER_DIR=/var/lib/my-cluster/clusterARCHIVE_DIR=/var/lib/my-cluster/archiveSERVICE_COUNT=1
java -cp "$AERON_ALL_JAR" io.aeron.cluster.ClusterTool "$CLUSTER_DIR" recording-logjava -cp "$AERON_ALL_JAR" io.aeron.cluster.ClusterTool "$CLUSTER_DIR" recovery-plan "$SERVICE_COUNT"java -cp "$AERON_ALL_JAR" io.aeron.archive.ArchiveTool "$ARCHIVE_DIR" describeRecord S, A, P, L, plus H (current cluster commit position) and B (position of the newest
verified backup image). Then confirm every recording the recovery plan selects actually exists, the
snapshot set covers the consensus module and every service, the local log is contiguous over the range
to be replayed, and member/cluster ID, service count, application version, and endpoints are correct.
2. Cost each valid path
Section titled “2. Cost each valid path”local replay work = P - S (snapshot exists)full local replay work = P - A (no snapshot)leader transfer / catch-up = H - Pbackup image tail catch-up = H - BThese are byte ranges, not times — local service replay is usually CPU/application-bound while archive replication is storage- or network-bound, so you need measured throughput from your own restore drills to convert them. Keep those numbers: replay positions/sec, restore bytes/sec, replication bytes/sec.
The newest base is not automatically the fastest. A node 20 minutes stale whose replay runs at application speed can lose to a backup image that is an hour old but restores at disk speed. Choose the lowest total of preparation + replay + transfer + verification.
3. Reject the normal-start path outright when
Section titled “3. Reject the normal-start path outright when”the selected snapshot recording is unavailableor the local replay range is not contiguousor L > Por no snapshot exists and A does not represent valid initial state4. Set an abort threshold before you start
Section titled “4. Set an abort threshold before you start”Decide the give-up condition in advance, because mid-incident optimism is what consumes the window:
- no recovery-position progress for one configured recovery timeout;
- repeated return to the same election state;
- a requested replay position before the source recording start;
- archive reports an unknown recording or unavailable segment;
- the projected completion estimate exceeds your RTO.
While a recovery is in flight, pause purge jobs, avoid recovering two followers against the same leader archive at once, and don’t throttle the replication path you are depending on.
5. Watch the right signals
Section titled “5. Watch the right signals”Track election state, local replication and replay positions, append position, commit position, the
remaining gap H − local, and archive/cluster error counters — see
Monitoring and Alerting for the counters and alert rules. Success
is FOLLOWER_READY plus position convergence plus application-state validation, not merely a process
that is still alive.
The three follower states you will pass through, in order:
Which stages actually run depends on the node’s positions — a current node may skip straight to catch-up; a stale one does all three.
The safe purge workflow
Section titled “The safe purge workflow”purgeSegments enforces exactly two things, both documented in its own javadoc: the new start position
“must be first byte position of a segment after the existing start position”, and “it is not possible to
detach segments which are active for recording or being replayed.” Neither of those is a recovery
check. The workflow below is.
Phase 1 — establish a recovery point
Section titled “Phase 1 — establish a recovery point”Trigger a cluster snapshot, wait for completion on every member that must support normal local restart,
and verify a complete set on each. Record each snapshot position and recording ID. Then verify the
snapshot recordings can actually be replayed — presence in recording.log is metadata, not proof. Do
the same for the backup and record its position.
Phase 2 — calculate the boundary
Section titled “Phase 2 — calculate the boundary”For each member take the oldest retained complete snapshot position S_member; for each offline member
promised a normal restart, its last verified append position P_member.
C_live ≤ min(P_member for every member promised normal catch-up)C_member ≤ S_memberRound down to a valid segment boundary. If an offline node falls behind the proposed cutoff, make the choice explicitly: postpone the purge, or withdraw the promise of normal restart and mark that node for rebuild. Do not let the arithmetic decide silently.
Phase 3 — dry run
Section titled “Phase 3 — dry run”Produce a purge manifest before touching storage: cluster and member ID, cluster-log recording ID, current start/stop positions, proposed new start, retained snapshot sets, the oldest normal-restart member position, backup position and last successful restore-test date, and the exact segment files expected to become detachable.
Reject the purge if no complete local snapshot set is retained, the cutoff is after S, a protected
stale node sits before C_live, the backup is absent or untested under Model B, any selected recording
is active or being replayed, or the catalog, recording.log, and physical recordings disagree.
Phase 4 — execute conservatively
Section titled “Phase 4 — execute conservatively”Keep quorum available throughout, and go one node at a time:
- stop one follower cleanly;
- back up its cluster metadata and archive catalog;
- detach segments to the calculated boundary;
- validate the archive and the recovery plan;
- delete the detached segments only after validation passes;
- restart the follower and wait for
FOLLOWER_READY; - verify service state and position convergence, then move to the next follower.
Handle the leader last, after leadership has moved or inside a controlled maintenance window.
Never use filesystem deletion as the purge mechanism. Go through the archive APIs so the catalog and the
recording start position stay coherent — rm on segment files leaves the catalog describing data that
is gone.
Phase 5 — prove recovery
Section titled “Phase 5 — prove recovery”Reclaimed disk is not success. Before retiring the previous generation, test: restart of a current node; restart of a node at the oldest supported stale position; fallback to the previous retained snapshot; rebuild of a blank host from backup; and application-state equality after catch-up.
What may actually be deleted
Section titled “What may actually be deleted”| Artifact | Rule |
|---|---|
| Cluster-log segments | Detachable before a calculated safe boundary, subject to the invariants above. Never purge the whole recording while recording.log references it. |
| Snapshot recordings | Only complete generations older than every retained fallback, unreferenced by the intended recovery plan and by any restore procedure. Retain two complete generations where storage allows. Never keep only some services of a generation. |
| Orphaned snapshot recordings | Recordings from a failed snapshot that never reached recording.log are reclaimable once you confirm no recovery metadata references them. |
recording.log | Recovery metadata, not bulk data. Do not purge it alongside segments, and do not hand-edit it. |
Automate on positions, not on disk usage
Section titled “Automate on positions, not on disk usage”A time or free-space policy may propose a cutoff; only the positional checks may approve it:
candidate cutoff = segment boundary constrained by retained local snapshot positions, protected stale member positions, backup / rebuild policy, active recording and replay statusAlongside the cluster counters, track archive recording start and stop positions, the latest two complete snapshot positions per member, backup state and age, projected disk exhaustion, and the date of the last successful blank-node restore test. That last one is the metric that tells you whether Model B is real.
For an EC2 deployment specifically: put archive and cluster state on persistent storage if instance
replacement should preserve local recovery; otherwise declare instances disposable and make backup
provisioning part of bootstrap. Run at least one continuously verified ClusterBackup outside the
cluster’s failure domain. And never reuse a member ID on an empty host unless full-log-from-zero
recovery is intentionally supported or that host has been provisioned first.
How this moves your numbers
Section titled “How this moves your numbers”- RTO is set almost entirely by which recovery base you pick, and that choice is constrained by
what you purged weeks earlier.
P − S(replay distance) is the number you control by snapshotting more often;H − Bis the one you control with backup freshness. - p99 / max latency is touched only indirectly, but the link is real: Phase 1 requires a cluster snapshot, and in OSS every member snapshots at the same log position, so a retention cycle imposes a stop-the-world pause on the hot path. On a busy matching engine that lands on max latency — which is the argument for standby snapshots if you are on Premium, and for scheduling purge windows off-peak if you are not.
- Throughput is unaffected by purge itself, but a recovering follower competes with live traffic for the leader’s archive replay, disk, and network. Recovering two at once is how a recovery becomes a throughput incident.
Sources
Section titled “Sources”- Purge semantics quoted verbatim from
AeronArchive.java—purgeSegments,detachSegments,deleteDetachedSegmentsjavadoc (“must be first byte position of a segment after the existing start position”; “not possible to detach segments which are active for recording or being replayed”), with server-side enforcement inArchiveConductor.purgeSegments(isValidDetach/isDeleteAllowed). - Follower catch-up states from
ElectionState.java(FOLLOWER_LOG_REPLICATION(9),FOLLOWER_REPLAY(10),FOLLOWER_CATCHUP(13),FOLLOWER_READY(16)) andElection.java; startup recovery from local metadata inConsensusModuleAgent.javaand recovery-plan construction/validation inRecordingLog.java. seed-recording-log-from-snapshotrebasing to zero and therecording.log.bakbackup, plus therecording-log/recovery-plan/invalidate-latest-snapshotcommands, fromClusterTool.java. Archive-side tooling (describe,verify,compact,delete-orphaned-segments,mark-invalid) fromArchiveTool.java.- Operational guidance: Cluster Backup and Operating Aeron Cluster.
- Background: The Aeron Files.
This site is not affiliated with, endorsed by, or sponsored by Adaptive Financial Consulting Limited or the Aeron project. Aeron is a registered trademark of Adaptive Financial Consulting Limited.
Aeron is a trademark of Adaptive Financial Consulting Limited in the United Kingdom and other countries.