Followers/learners can't catch up under sustained write — snapshot retention (NumLogFiles>4 × maxNumEntries=30000 ≈ 120k) is hardcoded
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 21.8k
- Forks
- 1.6k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 9
Description
Summary
On a large single-group cluster under sustained write, a restarted follower/learner is forced into repeated full snapshot streams and can effectively never catch up, because WAL retention before a forced snapshot is hardcoded to ~120k entries — only minutes of WAL under load.
Environment
- Dgraph v25.3.0
- Single Raft group: 1 alpha leader + 2 learner read-replicas
- ~500 GiB group data, continuous write ingestion (CDC-style)
What happens
- A learner restarts (or is briefly down).
- Leader streams a full snapshot (~500 GiB) — takes hours (observed ~37 MiB/s ingest despite idle CPU / 800 MiB/s disk / fast network → the stream, not hardware, is the limit).
- Writes continue; the leader force-snapshots + truncates its WAL every ~120k entries (minutes).
- The learner finishes the full snapshot, finds follow-on entries already truncated → re-requests another full snapshot → loops for hours. Never reaches healthy.
Root cause (source, v25.3.0)
worker/draft.go:calculate := raft.IsEmptySnap(snap) || n.Store.NumLogFiles() > 4raftwal/log.go:const maxNumEntries = 30000(per-file, tied to the fixed 1 MB slot region /entrySize=32)
→ ~4 × 30,000 = 120,000 entries. snapshot-after-entries / snapshot-after-duration can't relax it — the NumLogFiles() > 4 backstop is OR'd in independently. etcd/raft delegates snapshot/compaction to the application, so there's no library knob either.
What we tried
--raft snapshot-after-entries=200000; snapshot-after-duration=10m→ no effect past the backstop.- Only reliable workaround: pause writes during bootstrap (keeps
NumLogFiles() <= 4) — but that halts ingestion for the multi-hour snapshot.
Questions
- Any supported way to widen this retention that we've missed?
- Would you accept making the
NumLogFiles() > 4backstop (and/ormaxNumEntries) configurable, so large-cluster followers can catch up under sustained write without pausing ingestion? - Recommended pattern for (re)bootstrapping a follower on a large group under continuous write, other than pausing writes?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading worker/draft.go around the snapshot calculation and raftwal/log.go around maxNumEntries, then trace how snapshot-after-entries and snapshot-after-duration interact with the NumLogFiles() > 4 backstop. Determine whether retention can be configured safely and define completion as allowing a restarted learner to catch up under sustained writes without repeated full snapshots.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- databases, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100