Repeated runtime state persistence can put excessive load on PD/etcd when many changefeeds enter warning
@wk989898 is already working on this.
Since Apr 27, 2026.
- Dominant language
- Go
- Stars
- 56
- Forks
- 63
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 34
Description
Summary
When many changefeeds are stuck and repeatedly report runtime errors, TiCDC repeatedly persists runtime state by rewriting the whole changefeed/info value in etcd. ChangeFeedInfo contains the full replica config and other metadata, so these updates become large OpPut operations. If many changefeeds enter warning at the same time, this creates write amplification and can put excessive load on PD/etcd.
Why this is not only a warning problem
This is not a warning-only bug. The same persistence path is also used for failed, finished, and recovery back to normal, and stale checkpoint GC checks can also trigger it. warning is just the most visible case because it can be generated repeatedly while the checkpoint does not advance.
Root cause
- When
checkpointTsdoes not advance and errors keep being reported,Backoff.CheckStatuskeeps returningchanged=trueandStateWarningfor retryable errors. - The controller wraps the reported error into a new
RunningErrorwithTime: time.Now(). - The coordinator stores
stateanderrorback intoChangeFeedInfo. UpdateChangefeedmarshals and rewrites the entireChangeFeedInfoto etcd withOpPut.- Because
ChangeFeedInfois large, repeated runtime state updates become repeated large etcd writes.
Relevant code paths include coordinator/changefeed/backoff.go, coordinator/controller.go, coordinator/coordinator.go, and coordinator/changefeed/etcd_backend.go.
Impact
- Large etcd value rewrites during warning storms
- Larger txn payloads and write amplification
- Excessive load on PD/etcd when many changefeeds hit the same pattern
Proposed solution
Short term
- Deduplicate runtime state persistence before calling
UpdateChangefeed. - Only persist when the semantic state actually changes.
- Compare
state,error.Code,error.Addr, anderror.Message, but ignoreRunningError.Time. - Keep checkpoint-only updates on the existing lightweight status path.
Optional safeguard
- Add stronger fast-fail rules for clearly unrecoverable errors.
- Optionally fast-fail when the same error signature repeats for a long time and
checkpointTsdoes not move, to put an upper bound on the warning-retry loop. - This can reduce repeated writes, but it is only a mitigation and should not replace deduplication.
Long term
- Split runtime state and runtime error from
ChangeFeedInfo. - Keep static config and metadata in
ChangeFeedInfo, and persist runtime status in a lightweight key or object. - Then
warning/failed/finished/ recovery updates no longer need to rewrite the full metadata object.
Recommendation
The recommended order is:
- Add state persistence deduplication first.
- Add targeted fast-fail rules if needed for long-lived repeated warnings.
- Long term, separate runtime state from
ChangeFeedInfo.
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.
Assessment
This issue has not been assessed yet.