Skip to content

*: add low-latency performance mode - #5749

Open
asddongmen wants to merge 19 commits into
pingcap:masterfrom
asddongmen:agent/simplify-low-latency-mode
Open

*: add low-latency performance mode#5749
asddongmen wants to merge 19 commits into
pingcap:masterfrom
asddongmen:agent/simplify-low-latency-mode

Conversation

@asddongmen

@asddongmen asddongmen commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: close #5705

Timestamp batching adds avoidable latency to changefeeds with many dispatchers
or Regions.

What is changed and how it works?

Add opt-in performance-mode = "low-latency" for eager LogPuller advancement,
watermark reporting, checkpoint calculation, and no-DML/DDL EventBroker
notifications. Throughput remains the default; scan recovery is
low-latency-only.

Three-capture, 10-minute results; values are low-latency/throughput/master.
Resolved is maintainer resolved-ts lag; CPU and RSS are aggregate.

Tables (~20MB/s) Checkpoint s Resolved s CPU cores RSS GB Low vs throughput
50k .419/1.394/1.180 .373/.677/.692 14.7/11.0/11.0 18.8/18.8/18.6 checkpoint -69.9%, resolved -44.9%
100k .569/1.496/1.386 .525/.813/.815 24.5/19.2/19.7 20.7/21.0/20.8 checkpoint -62.0%, resolved -35.5%
200k 1.079/1.978/1.880 1.018/1.343/1.318 29.9/24.2/24.2 26.9/26.0/25.9 checkpoint -45.4%, resolved -24.1%
32 tables, 199,936 Regions (~30MB/s) Checkpoint s Resolved s CPU RSS GB
Low latency .584 .485 2.62 11.80
Throughput 1.620 .946 2.54 12.09
Master bootstrap blocked by #5748

This reduces checkpoint/resolved lag by 64.0%/48.7% with +3.0% CPU and -2.4%
RSS. Table-scale latency gains cost 23-34% CPU; RSS stays within 4%.

Check List

Tests

  • Unit test
  • Manual test (large table/Region matrices above)

Questions

Will it cause performance regression or break compatibility?

No compatibility change. Throughput remains default; its CPU/RSS stayed within
2.2% of master.

Do you need to update user documentation, design documentation or monitoring documentation?

Yes, document the mode and resource trade-off.

Release note

Add an opt-in low-latency performance mode for faster resolved-ts and checkpoint propagation.

Summary by CodeRabbit

  • New Features

    • Added configurable throughput vs low-latency performance modes to tune heartbeat, checkpoint advancement, and scan behavior for lower end-to-end latency.
    • Improved scan handling with automatic schema-blocked retry/rescheduling.
    • Added a Prometheus counter for dropped scan tasks when queues are full.
  • Bug Fixes

    • Refined changefeed metric reporting to update at the right times and compute lag more accurately across nodes.
    • Improved scan scheduling and notification ordering under load, including faster recovery after interruptions.

Keep the low-latency mode focused on setting the logpuller advance interval to zero. Remove the additional batched heap update path and its helper after the 10k-region E2E test showed comparable mean and p95 latency without it.
Replace the periodic schema-capped scan retry with applied SchemaStore notifications. Serialize dispatcher scan scheduling with a short-lock state machine and coalesce worker continuations without dropping queued work.
Keep no-DML/no-DDL resolved notifications out of the scan worker queue while preserving dispatcher scan ownership. Gate continuation and schema-blocked recovery on low-latency mode, and cover queue-full recovery with a dropped-task metric.
@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Jul 25, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 25, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign nongfushanquan for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c7baa2f-4774-4a3d-96cc-a8199fb91f2a

📥 Commits

Reviewing files that changed from the base of the PR and between 52a0082 and b3b74f3.

📒 Files selected for processing (7)
  • downstreamadapter/dispatchermanager/task.go
  • logservice/eventstore/event_store.go
  • pkg/config/server_config_test.go
  • pkg/eventservice/dispatcher_stat.go
  • pkg/eventservice/event_broker.go
  • pkg/eventservice/event_broker_test.go
  • pkg/metrics/event_service.go

📝 Walkthrough

Walkthrough

The PR adds throughput and low-latency server modes, event-driven checkpoint propagation, reporting-round-aware coordinator metrics, and cursor-aware dispatcher scan scheduling with explicit lifecycle, retry, and cleanup handling.

Changes

Low-latency performance mode

Layer / File(s) Summary
Performance mode and timing
pkg/config/server.go, pkg/config/server_config_test.go, downstreamadapter/dispatchermanager/*, maintainer/maintainer_manager.go, logservice/eventstore/event_store.go
Adds validated performance modes and selects mode-specific heartbeat, manager, and resolved-ts timing.
Checkpoint and coordinator propagation
maintainer/*, logservice/coordinator/*
Adds event-driven checkpoint recalculation, change-aware watermark updates, complete reporting-round tracking, and timestamp-based metric refreshes.
Dispatcher scan state machine
logservice/eventstore/event_store.go, pkg/eventservice/*, pkg/metrics/event_service.go
Adds cursor-aware scan requests, explicit scan states, schema-blocked rescheduling, queue recovery, active-scan cancellation, large-transaction cleanup retries, and dropped-task metrics.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DispatcherManager
  participant Maintainer
  participant EventBroker
  participant SchemaStore
  participant EventStore
  DispatcherManager->>Maintainer: send heartbeat watermark
  Maintainer->>Maintainer: signal checkpoint recalculation
  Maintainer->>EventBroker: request dispatcher scan
  EventBroker->>SchemaStore: check DDL frontier
  SchemaStore-->>EventBroker: return scan range or blocked frontier
  EventBroker->>EventStore: execute cursor-aware scan request
  EventStore-->>EventBroker: return KV and scan position
  EventBroker->>EventBroker: enqueue, continue, or retry scan
Loading

Possibly related PRs

  • pingcap/ticdc#5511: Refactors EventStore.GetIterator around ScanRequest and scan-position-aware iteration.
  • pingcap/ticdc#5554: Updates dispatcher reset behavior to trigger scan and handshake progress immediately.
  • pingcap/ticdc#5643: Modifies eventBroker.doScan control flow and quota-release handling.

Suggested labels: lgtm, approved

Suggested reviewers: wk989898, lidezhu

Poem

A rabbit nudges clocks ahead,
Checkpoints wake from periodic bed.
Scans find cursors, queues align,
Schema gates retry by design.
Low-latency hops along! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the main change: adding an opt-in low-latency performance mode.
Description check ✅ Passed The description includes the required issue number, change summary, tests, impact questions, and release note.
Linked Issues check ✅ Passed The changes implement the requested low-latency mode across LogPuller, EventService, DispatcherManager, and Maintainer, with tests for throughput compatibility and queue behavior.
Out of Scope Changes check ✅ Passed No clear unrelated changes stand out; the added cleanup, metrics, and scan-state work all support the low-latency latency-reduction objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Command failed


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@maintainer/maintainer.go`:
- Around line 961-964: Update the status-handling flow around HandleStatus to
always call notifyCheckpointUpdate after applying req.Statuses, rather than only
when watermarkUpdated is true. Preserve the existing HandleStatus call and rely
on the buffered notification channel to coalesce duplicate wakeups.

In `@pkg/eventservice/event_broker.go`:
- Around line 1056-1062: Update the blocking enqueue in prepareScanFromNotify to
select between sending d to c.taskChan[d.scanWorkerIndex] and broker shutdown
via the broker-level done channel or errgroup context. If shutdown wins, reset
the dispatcher’s queued scan state, including the associated busy/queued
markers, before returning so it cannot remain permanently queued.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 998e1e16-fee4-4cdc-b75c-0a3c2459d3cc

📥 Commits

Reviewing files that changed from the base of the PR and between 07e9447 and 52a0082.

📒 Files selected for processing (15)
  • downstreamadapter/dispatchermanager/task.go
  • downstreamadapter/dispatchermanager/task_test.go
  • logservice/coordinator/coordinator.go
  • logservice/coordinator/coordinator_test.go
  • logservice/eventstore/event_store.go
  • maintainer/maintainer.go
  • maintainer/maintainer_manager.go
  • maintainer/maintainer_test.go
  • pkg/config/server.go
  • pkg/config/server_config_test.go
  • pkg/eventservice/dispatcher_stat.go
  • pkg/eventservice/event_broker.go
  • pkg/eventservice/event_broker_test.go
  • pkg/eventservice/metrics_collector.go
  • pkg/metrics/event_service.go

Comment thread maintainer/maintainer.go
Comment on lines 961 to +964
m.controller.HandleStatus(msg.From, req.Statuses)
if watermarkUpdated {
m.notifyCheckpointUpdate()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Wake checkpoint calculation after status updates.

HandleStatus can change scheduler or barrier constraints used by calculateNewCheckpointTs, but this only signals recalculation when the watermark cache changed. A status-only or duplicate-watermark heartbeat therefore waits for the periodic ticker in low-latency mode. Notify after handling statuses as well; the buffered channel already coalesces redundant wakeups.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@maintainer/maintainer.go` around lines 961 - 964, Update the status-handling
flow around HandleStatus to always call notifyCheckpointUpdate after applying
req.Statuses, rather than only when watermarkUpdated is true. Preserve the
existing HandleStatus call and rely on the buffered notification channel to
coalesce duplicate wakeups.

Comment on lines +1056 to +1062
d.scanState = dispatcherScanQueued
d.schemaBlockedUntilTs = 0
d.scanMu.Unlock()

// Only the external EventStore notify path may wait for capacity. Scan workers
// use requestScan so that they never block on their own queue.
c.taskChan[d.scanWorkerIndex] <- d

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Blocking enqueue has no shutdown escape.

prepareScanFromNotify runs on the EventStore notify callback goroutine and blocks unconditionally on c.taskChan[d.scanWorkerIndex] <- d. After cancel() the scan workers return, so any notify in flight (or arriving before dispatchers are unregistered) blocks forever, leaking the notify goroutine and pinning the dispatcher in dispatcherScanQueued (permanently isScanBusy). Select on a broker-level done channel (or the errgroup ctx) alongside the send and bail out by resetting the state.

🛡️ Sketch
-	// Only the external EventStore notify path may wait for capacity. Scan workers
-	// use requestScan so that they never block on their own queue.
-	c.taskChan[d.scanWorkerIndex] <- d
+	// Only the external EventStore notify path may wait for capacity. Scan workers
+	// use requestScan so that they never block on their own queue.
+	select {
+	case c.taskChan[d.scanWorkerIndex] <- d:
+	case <-c.done: // closed by eventBroker.close()
+		d.scanMu.Lock()
+		if d.scanState == dispatcherScanQueued {
+			d.scanState = dispatcherScanIdle
+		}
+		d.scanMu.Unlock()
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
d.scanState = dispatcherScanQueued
d.schemaBlockedUntilTs = 0
d.scanMu.Unlock()
// Only the external EventStore notify path may wait for capacity. Scan workers
// use requestScan so that they never block on their own queue.
c.taskChan[d.scanWorkerIndex] <- d
d.scanState = dispatcherScanQueued
d.schemaBlockedUntilTs = 0
d.scanMu.Unlock()
// Only the external EventStore notify path may wait for capacity. Scan workers
// use requestScan so that they never block on their own queue.
select {
case c.taskChan[d.scanWorkerIndex] <- d:
case <-c.done: // closed by eventBroker.close()
d.scanMu.Lock()
if d.scanState == dispatcherScanQueued {
d.scanState = dispatcherScanIdle
}
d.scanMu.Unlock()
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/eventservice/event_broker.go` around lines 1056 - 1062, Update the
blocking enqueue in prepareScanFromNotify to select between sending d to
c.taskChan[d.scanWorkerIndex] and broker shutdown via the broker-level done
channel or errgroup context. If shutdown wins, reset the dispatcher’s queued
scan state, including the associated busy/queued markers, before returning so it
cannot remain permanently queued.

@asddongmen

Copy link
Copy Markdown
Collaborator Author

/test all

@ti-chi-bot

ti-chi-bot Bot commented Jul 25, 2026

Copy link
Copy Markdown

@asddongmen: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-cdc-mysql-integration-light 52a0082 link true /test pull-cdc-mysql-integration-light

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

*: optimize resolved-ts and checkpoint propagation latency

1 participant