Skip to content

*: add low-latency performance mode#5749

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

*: add low-latency performance mode#5749
asddongmen wants to merge 18 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 and low-latency performance modes.
    • Low-latency mode enables faster heartbeat, checkpoint, and event processing.
    • Added automatic handling for schema-blocked event scans.
    • Added a metric for scan tasks dropped when queues are full.
  • Bug Fixes

    • Improved scan scheduling, recovery, and notification ordering under load.
    • Improved changefeed metrics updates for more accurate resolved timestamp and lag reporting.

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

📝 Walkthrough

Walkthrough

The PR introduces throughput and low-latency server modes, configurable heartbeat and manager timing, event-driven checkpoint propagation, reporting-round-aware coordinator metrics, and an event-service scan state machine with schema-blocked retries and queue recovery.

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 throughput/low-latency configuration and selects heartbeat, manager, and resolved-ts advancement timing from the active mode.
Checkpoint and coordinator propagation
maintainer/maintainer.go, maintainer/maintainer_test.go, logservice/coordinator/*
Adds event-driven checkpoint recalculation, change-aware watermark updates, complete reporting-round tracking, and timestamp-based metric refresh behavior.
Dispatcher scan state machine
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
Replaces the scan flag with explicit states and adds coalesced notifications, schema-blocked rescheduling, queue-full recovery, lifecycle cleanup, and dropped-task metrics.

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

Sequence Diagram(s)

sequenceDiagram
  participant DispatcherManager
  participant Maintainer
  participant EventBroker
  participant SchemaStore
  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->>EventBroker: enqueue or retry scan
Loading

Suggested reviewers: lidezhu, wk989898

Poem

A rabbit sees heartbeats hop,
Checkpoints wake and scanners stop
At schema gates, then try once more—
Queues breathe softly, metrics soar.
Low-latency paws lead the way! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.89% 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 summarizes the main change: introducing a low-latency performance mode.
Description check ✅ Passed The description matches the template and includes the issue number, change summary, tests, questions, and release note.
Linked Issues check ✅ Passed The changes implement the requested opt-in low-latency mode across LogPuller, EventService, DispatcherManager, and Maintainer with default throughput behavior.
Out of Scope Changes check ✅ Passed The diff stays focused on low-latency performance mode, related metrics, and supporting tests without unrelated code changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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