Skip to content

perf(replication): implement async processing during replication#1166

Open
ygxio wants to merge 11 commits into
pgdogdev:mainfrom
ygxio:faster-replication
Open

perf(replication): implement async processing during replication#1166
ygxio wants to merge 11 commits into
pgdogdev:mainfrom
ygxio:faster-replication

Conversation

@ygxio

@ygxio ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

fixes #1036

@ygxio

ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

I am still working on the design for it, just a peak if the direction seems well @levkk

@ygxio ygxio changed the title faster replication v1 faster replication Jul 8, 2026
@levkk

levkk commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Cool! Would be good to see some benchmark numbers, just to get a sense of how much faster this is.

@ygxio

ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Do you have any such setup so that i can benchmark it?

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.39207% with 30 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...backend/replication/logical/subscriber/pipeline.rs 95.01% 20 Missing ⚠️
...c/backend/replication/logical/subscriber/stream.rs 82.69% 9 Missing ⚠️
pgdog/src/backend/replication/logical/error.rs 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@levkk

levkk commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Do you have any such setup so that i can benchmark it?

This might work:

benches/bench.sh

Specifically, see resharding folder.

@ygxio

ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author
image

PGDOG_BIN=/tmp/pgdog-new bash benches/resharding/replication/run.sh --baseline main

@ygxio

ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

For BENCH_SCALE = 3000, DEST_LATENCY_MS=10 we have more performance boosts

image

@ygxio

ygxio commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

RUNS = 2
WARMUP = 1
BENCH_SCALE = 5000
DEST_LATENCY_MS = 10
USE_TOXI = 1

image

@levkk results seems good but also too good at a point

@levkk

levkk commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Async should be a big improvement, so not that surprising. This is very cool. Let me know when you're ready for a review, I'll tag Kiryl.

@ygxio

ygxio commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@levkk ready for review

@ygxio ygxio changed the title faster replication feat: faster replication Jul 13, 2026
@levkk
levkk requested a review from meskill July 13, 2026 17:42
}

#[cfg(test)]
mod test {

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.

Do you think we should add more unit tests here? I think we should have some for testing the whole flow - prepare -> execute -> await. And also some tests for possible errors

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure @meskill would add more tests

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.

We still miss some important tests:

  • error path - something that will trigger an error response, validate that we get the error properly and we won't block the execution for future calls
  • missed rows calculation - just some calls to generate missed rows and make sure we get proper stats for it

@ygxio

ygxio commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@meskill i have added a few more could you take a look?

@meskill

meskill commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Thanks @ygxio I'm still checking the code more deeply, but anyway looking great so far.

Putting my bench results to confirm the improvements:

Against main

With defaults:
image

With toxi and latency for source/destination for 1ms:
image

Separately

And the next without comparison with main (compare against prev run) since since it is executing too long to get the result.

With latency 10ms:
image

With latency 100ms:
image

@ygxio

ygxio commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

i see from 1 to 10 to 100 ms of latency the jump has been pretty high, need to see the cause maybe

Comment thread pgdog/src/backend/replication/logical/subscriber/pipeline.rs Outdated
Comment thread pgdog/src/backend/replication/logical/subscriber/pipeline.rs
Comment thread pgdog/src/backend/replication/logical/subscriber/stream.rs
Comment thread pgdog/src/backend/replication/logical/subscriber/pipeline.rs Outdated
}

#[cfg(test)]
mod test {

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.

We still miss some important tests:

  • error path - something that will trigger an error response, validate that we get the error properly and we won't block the execution for future calls
  • missed rows calculation - just some calls to generate missed rows and make sure we get proper stats for it

Comment thread pgdog/src/backend/replication/logical/subscriber/pipeline.rs
Comment thread pgdog/src/backend/replication/logical/subscriber/stream.rs Outdated
@ygxio
ygxio force-pushed the faster-replication branch from 8cf5e8b to 0c5844d Compare July 20, 2026 10:16
@ygxio

ygxio commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

DEFAULT
image

Src/dest latecy = 1 ms

image

Src/dest latecy = 10 ms

image

Src/dest latecy = 100 ms

image

Looks like almost same performance

@ygxio

ygxio commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

have fixed most of the issues, need a re review @levkk @meskill

@meskill meskill changed the title feat: faster replication perf(replication): implement async processing during replication Jul 23, 2026

@meskill meskill 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.

Looks good, only the small test fix and we'll merge

Comment on lines +482 to +517
async fn prepare_invalid_sql_sync_returns_error() {
let server = test_server().await;
let conn = PipelinedConnection::new(server).unwrap();

// A single in-transaction prepare with several statements uses
// ParseAcks(n): the waiter must resolve only after ALL n ParseComplete
// acks arrive (exercises the n -> 0 countdown, not just n == 1).
conn.prepare(
&[
Parse::named("__pipe_m1", "SELECT $1::bigint"),
Parse::named("__pipe_m2", "SELECT $1::text"),
Parse::named("__pipe_m3", "SELECT $1::bool"),
],
true,
// Out-of-transaction prepare of invalid SQL: Postgres replies with an
// ErrorResponse, which is latched and surfaced through the Sync path.
let err = conn
.prepare(&[Parse::named("__pipe_bad", "NOT VALID SQL")], false)
.await
.unwrap_err();
assert!(
matches!(err, Error::PgError(_)),
"unexpected error: {err:?}"
);
// The error was taken while surfacing, so nothing remains latched.
assert!(conn.take_error().is_none());
}

#[tokio::test]
async fn prepare_invalid_sql_flush_returns_error() {
let server = test_server().await;
let conn = PipelinedConnection::new(server).unwrap();

// In-transaction prepare uses Flush, so Postgres sends no ReadyForQuery
// on error. The parked ParseAcks waiter can only be released by the
// 'E' handler's wake_all(): this proves the prepare does not hang.
let err = conn
.prepare(&[Parse::named("__pipe_bad", "NOT VALID SQL")], true)
.await
.unwrap_err();
assert!(
matches!(err, Error::PgError(_)),
"unexpected error: {err:?}"
);
assert!(conn.take_error().is_none());
}

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.

those are identical tests, please verify

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@meskill one it for out of transaction and other is for in transaction, should i merge them into one test with a loop over in_transaction value either false or true

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add async streaming for replication to improve replication speed

3 participants