From ad1f8049338168d7d853ac528db869bc5d5616eb Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Mon, 22 Sep 2025 19:55:01 -0700 Subject: [PATCH 1/2] save --- docs/features/sharding/resharding/hash.md | 53 ++++++++++++++++++++ docs/features/sharding/resharding/schema.md | 4 +- docs/images/resharding-16x.png | Bin 0 -> 55183 bytes docs/images/resharding-slot-2.png | Bin 0 -> 23846 bytes 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 docs/images/resharding-16x.png create mode 100644 docs/images/resharding-slot-2.png diff --git a/docs/features/sharding/resharding/hash.md b/docs/features/sharding/resharding/hash.md index b366c59..8768069 100644 --- a/docs/features/sharding/resharding/hash.md +++ b/docs/features/sharding/resharding/hash.md @@ -4,6 +4,59 @@ icon: material/database-export-outline # Move data +Moving data from the source to the desination database is done using logical replication. This is an online operation, and doesn't require a maintenance window or pausing query traffic. + +The underlying mechanism is very similar to Postgres [subscriptions](https://www.postgresql.org/docs/current/sql-createsubscription.html), with some improvements, and happens in two steps: + +1. Copy data in the [publication](schema.md#publication) to the destination database +2. Stream row changes in real-time + +Once the replication stream syncrhonizes the two database clusters, the data on the destination cluster will be identical, within a few milliseconds, to the source cluster. + +## CLI + +PgDog has a command line interface you can call by running it directly: + +```bash +pgdog data-sync \ + --from-database \ + --from-user \ + --to-database \ + --to-user \ + --publication +``` + +Required (*) and optional parameters for this command are as follows: + +| Option | Description | +|-|-| +| `--from-database`* | Name of the source database cluster. | +| `--from-user` * | Name of the user configured in `users.toml` for the source database cluster. | +| `--to-database`* | Name of the destination database cluster. | +| `--to-user`* | Name of the user configured in `users.toml` for the destination database cluster. | +| `--publication`* | Name of the Postgres [publication](schema.md#publication) for tables to be copied and sharded. It should exist on the **source** database. | + +## How it works + +The first thing PgDog will do when data sync is started is create a replication slot on each primary database in the source cluster. This will prevent Postgres from removing the WAL, while we copy data for each table to the destination. + +Next, each table will be copied, in parallel, to the destination database, using [sharded COPY](../copy.md). Once that's done, table changes are synchronized, in real-time, with logical replication from the replication slot created earlier. + +The whole process happens entirely online, and doesn't require database reboots or pausing writes to the source database. + +### Replication slot + +
+ Cross-shard queries +
+ +### Copying data + + +
+ Cross-shard queries +
+ If you're using the `HASH` sharding function, adding a new node to the cluster will change the modulo number by 1. The number returned by the hash function is uniformly distributed across the entire integer range, which makes it considerably larger than the modulo. Therefore, changing it will more often than not result in most rows remapped to different shard numbers. You can visualize this phenomenon with a bit of Python: diff --git a/docs/features/sharding/resharding/schema.md b/docs/features/sharding/resharding/schema.md index 7513c7c..7331da5 100644 --- a/docs/features/sharding/resharding/schema.md +++ b/docs/features/sharding/resharding/schema.md @@ -8,7 +8,7 @@ PgDog can copy tables, indices and other entities from your production database 1. [Create tables](#tables-and-primary-keys), primary key indices, and sequences 2. Create [secondary indices](#secondary-indices) -The first step needs to be performed first, before [copying data](hash.md). The second step is performed once the data sync is almost complete. +The create tables step needs to be performed first, before [copying data](hash.md). The second step is performed once the data sync is almost complete. ## CLI @@ -74,7 +74,7 @@ PgDog will use that user to connect to the source and destination databases, so ### `pg_dump` version -PgDog is using `pg_dump` under the hood to export schema definitions. Postgres requires the version of `pg_dump` and the server to be identical. Our [Docker image](../../../installation.md) comes with `pg_dump` for PostgreSQL 16, but your database server may run a different version. +PgDog is using `pg_dump` under the hood to export schema definitions. Postgres requires the version of `pg_dump` and the Postgres server to be identical. Our [Docker image](../../../installation.md) comes with `pg_dump` for PostgreSQL 16, but your database server may run a different version. Before proceeding, make sure to install the correct version of `pg_dump` for your source database. If you have multiple versions of `pg_dump` installed on the same host, you can specify the path to the right one in `pgdog.toml`: diff --git a/docs/images/resharding-16x.png b/docs/images/resharding-16x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d6b6e50c280e2fc282704f8f5a654b83a904459 GIT binary patch literal 55183 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 tLnlU~Pj^XirN%(?V-Q7CdabU%e&`2p}~ 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 RAwET+uB&RRlw7uY{6A2?48#Bc literal 0 HcmV?d00001 diff --git a/docs/images/resharding-slot-2.png b/docs/images/resharding-slot-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9ec1b8079c34f70eb1f133fdd7ee17457c7f7d73 GIT binary patch literal 23846 zcmeFZ2T+sU_AVYP2q>sXk&Xz6Kq%4)Q4kT3DuQ%Fl@@w05v3zV5D{qtDk@DtdWnJ% znp6?#QbX^AKuB_T{JwL3=XdX&J9B34o&Wr2PG%V7efPV|+G{=QdDebow63<=X_|{P z5D4V7`t6(g5XcE?2;|5I>XYEgSJzQ#2;>YTz~H`@KEjvV&BN8s!P%DE%iqnG+t$y) z4g&ETDN1vA!PbckBV&c?!!i=Diwa;o>yJSvxni6@yhS!B{F-$sGbrphLVff2Qp7f# z9NdiB6#D7(KKEyU(=(&h3hdX=mLVs_>?=R9+q-3g>*eSS`aCqfMJjp$`I?r{VgWf z36_Z8P`sMy=J4$R@&N%|aIQh5>#m2=<&-x2E9)m1$;rAWsWN-IRE4Vz;_vDyIjOIw zFeI)|@5~Gu_wBy@=?XoNGUZZ3+iFhaP^0Y&=JzhoRdH8wO-^Rft2g#^oIlW!G$I^H zw(RB#Y=M27%w0$AA?tdwhFjjp=~nH%Q>w(XyN}z@WRD!xbkf^DAJK~)_h)-=aUFrV zAh4bi(D7#Z-7BAqi|@9BNMH@(+r0keZDyJdv#n)1-$hscY0^{(`9Fj_RWYj@T};p(Jh!KIluly5qegHJlb_aXB^%& zHdG&+TCpneIqPY|$KEFwX$LXum|K-oR(o>_hl`PxjrLr;0y6I|N;$w`K&5dCKLF zDOSg588}JeN_&*97W*I_1G8Ve9XqEpx!3hYK7I}HfXUCD31J=45oebAqWhP2hR>~r zH{n|RDbmdTN}e}v6fWRokFihKv>bmVfG9v+#gpZoPzP%+^f6jKBB8JHAXrF~ZOLlX z+FQ|qrNw6|$MOE6(R0oY4SeUQ-_tmZB?$;c)2y-XAX5UO+1t%NrWX8~V;xAaNk7`0 zp{7)oJvfq8#X6|J7H_j@JR*Eyc~AJf^=>x0Q>p4_?2(6_JJzW&tiC%*?f%)4C)gAY z#(rM=zM^(1{sUEp^9$;`Wqgw}I411S3 zgTu;*4*5#=w~~i(=nhSMEVF3DS~p9z8I9mneD3M^8t!Q7u3_zVjo0@KsVu~E2#wR# z+78odiB@%;y&u_{2`d=6%ra~%?}|C$>_b~U89nCEc!N3d?-g^UVyd;bf5Da~q&;QJ z9~t~QeKNaLx-MB!+56GOw8-e7HNx4Z>?1!aPla>cLq86c?yKg|U>O?9W

1k_<*) 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 Wn%!@_%U61lNlZ)0JkuvByzv`vHxhXO literal 0 HcmV?d00001 From f449a8b03beeccb3351016b50ce1048b09d4ff73 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Tue, 23 Sep 2025 12:53:54 -0700 Subject: [PATCH 2/2] Cleanup --- docs/features/sharding/resharding/hash.md | 96 ++++++++++++--------- docs/features/sharding/resharding/schema.md | 20 +++-- docs/roadmap.md | 2 +- 3 files changed, 70 insertions(+), 48 deletions(-) diff --git a/docs/features/sharding/resharding/hash.md b/docs/features/sharding/resharding/hash.md index 8768069..06fd7fc 100644 --- a/docs/features/sharding/resharding/hash.md +++ b/docs/features/sharding/resharding/hash.md @@ -4,14 +4,14 @@ icon: material/database-export-outline # Move data -Moving data from the source to the desination database is done using logical replication. This is an online operation, and doesn't require a maintenance window or pausing query traffic. +Moving data from the source to the destination database is done using logical replication. This is an online operation, and doesn't require a maintenance window or pausing query traffic. The underlying mechanism is very similar to Postgres [subscriptions](https://www.postgresql.org/docs/current/sql-createsubscription.html), with some improvements, and happens in two steps: 1. Copy data in the [publication](schema.md#publication) to the destination database 2. Stream row changes in real-time -Once the replication stream syncrhonizes the two database clusters, the data on the destination cluster will be identical, within a few milliseconds, to the source cluster. +Once the replication stream synchronizes the two database clusters, the data on the destination cluster will be identical, within a few milliseconds, to the source cluster. ## CLI @@ -31,7 +31,7 @@ Required (*) and optional parameters for this command are as follows: | Option | Description | |-|-| | `--from-database`* | Name of the source database cluster. | -| `--from-user` * | Name of the user configured in `users.toml` for the source database cluster. | +| `--from-user`* | Name of the user configured in `users.toml` for the source database cluster. | | `--to-database`* | Name of the destination database cluster. | | `--to-user`* | Name of the user configured in `users.toml` for the destination database cluster. | | `--publication`* | Name of the Postgres [publication](schema.md#publication) for tables to be copied and sharded. It should exist on the **source** database. | @@ -46,66 +46,84 @@ The whole process happens entirely online, and doesn't require database reboots ### Replication slot +PostgreSQL replication works on the basis of slots. They are virtual annotations in the Write-Ahead Log which prevent Postgres from recycling WAL segments and deleting the history of changes made to the database. +

- Cross-shard queries + Cross-shard queries
+With logical replication, any client that speaks the protocol (like PgDog) can connect to the server and stream changes made to the database, starting at the position marked by the slot. + +Before copying table data, we create a slot to mark a consistent starting point for our replication process. The slot is **permanent**, so even if resharding is interrupted, Postgres won't lose any of the WAL segments we need to resume it. + +!!! note "Unused replication slots" + Since permanent replication slots are not automatically removed by Postgres, if you choose to abort the resharding process, make sure to manually drop the replication slot to prevent excessive WAL accumulation on the source database. + +Once the slot is created, PgDog starts copying data from all tables in the [publication](schema.md#publication), and resharding it in-flight. + ### Copying data +Tables are copied from source to destination database using standard PostgreSQL `COPY` commands, with a few improvements. + +#### Parallelization + +If you are running PostgreSQL 16 or later and have configured replicas on the source database, PgDog can copy multiple tables in parallel, dramatically accelerating this process.
Cross-shard queries
-If you're using the `HASH` sharding function, adding a new node to the cluster will change the modulo number by 1. The number returned by the hash function is uniformly distributed across the entire integer range, which makes it considerably larger than the modulo. Therefore, changing it will more often than not result in most rows remapped to different shard numbers. +To set this up, make sure to add your read replicas to [`pgdog.toml`](../../../configuration/pgdog.toml/databases.md), for example: -You can visualize this phenomenon with a bit of Python: +```toml +[[databases]] +name = "source" +host = "10.0.0.1" +role = "replica" -=== "2 shards" +[[databases]] +name = "source" +host = "10.0.0.2" +role = "replica" +``` - ```python - >>> list(map(lambda x: x % 2, [1000, 1001, 1002, 1003, 1004])) - [0, 1, 0, 1, 0] - ``` +PgDog will distribute the table copy load evenly between all replicas in the configuration. The more replicas are available for resharding, the faster it will complete. -=== "3 shards" - ```python - >>> list(map(lambda x: x % 3, [1000, 1001, 1002, 1003, 1004])) - [1, 2, 0, 1, 2] - ``` +!!! note "Dedicated replicas" + To prevent the resharding process from impacting production queries, you can create a separate set of replicas just for resharding. -Since most rows will have to be moved, resharding a cluster in-place would put a lot of load on an already overextended system. + Managed clouds (e.g., AWS RDS) make this especially easy, but require a warm-up period to fetch all the data from the backup snapshot, before they can read data at full speed of their storage volumes. -PgDog's strategy for resharding is to **move data** from an existing cluster to a completely new one, while rehashing the rows in-flight. This process is parallelizable and fast, and since most of the work is done by the new cluster, production databases are not affected. +#### Binary `COPY` -## Data sync +PgDog uses the binary `COPY` format to send and receive data, which has been shown to be consistently faster than text, because it avoids the (de)serialization overhead of sending tuples in text form. PgDog decodes tuples in-flight and splits them evenly between destination shards, using the [sharded COPY](../copy.md) implementation. -Moving data online is a 2-step process: +!!! note "Binary compatibility" + While the data format used by PostgreSQL databases hasn't changed in decades, binary `COPY` sends rows exactly as they are stored on disk. -1. Copy data from tables using Postgres `COPY` -2. Stream real-time changes using logical replication + Therefore, sending binary data between two PostgreSQL databases running different + versions of Postgres, however unlikely, could result in incompatibilities. We recommend to _not_ change major versions of the server while resharding. -To make sure no rows are lost in the process, PgDog follows a similar strategy used by Postgres in logical replication subscriptions, with some improvements. +Once all tables are copied and resharded on the destination database cluster, PgDog will begin streaming real-time row updates from the [replication slot](#replication-slot). -### Copying tables +### Streaming updates -Copying table data from the source database cluster is done using Postgres `COPY` and logical replication slots. This is implemented in the `data-sync` command: +Once tables are copied over to the destination database, PgDog will stream any changes made to those tables from the [replication slot](#replication-slot) created previously. If it took a while to copy tables and the source database received a large volume of writes, this process could take some time. -```bash -pgdog data-sync --help -``` +You can check on the streaming process and estimate its ETA by querying the `pg_replication_slots` view on the __source__ database: -| Option | Description | Example | -|-|-|-| -| `--from-database` | Name of the **source** database cluster. | `prod` | -| `--from-user` | Name of the user configured in `users.toml` for the **source** database cluster. | `postgres` | -| `--to-database` | Name of the **destination** database cluster. | `prod-sharded` | -| `--to-user` | Name of the user configured in `users.toml` for the **destination** database cluster. | `postgres` | -| `--publication` | Name of the Postgres [publication](https://www.postgresql.org/docs/current/sql-createpublication.html) for tables to be copied and sharded. It should exist on the **source** database. | `all_tables` | +=== "Source database" + ```postgresql + SELECT confirmed_flush_lsn, pg_current_wal_lsn() FROM pg_replication_slots; + ``` + +| Column | Description | +|-|-| +| `confirmed_flush_lsn` | The transaction identifier that has been written to the destination database cluster. | +| `pg_current_wal_lsn()` | Current position in the Write-Ahead Log for this database. | -All databases and users must be configured in `pgdog.toml` and `users.toml`. +The replication delay between the two database clusters is measured in bytes. When that number reaches zero, the two databases are byte-for-byte identical, and traffic can be [cut over](cutover.md) to the destination database. -### Real time changes +## Next steps -After data sync is complete, changes for all tables in the publication will be streamed in real-time. Keep this connection -open until you are ready to cut traffic over to the new database cluster. +- [Traffic cutover](cutover.md) diff --git a/docs/features/sharding/resharding/schema.md b/docs/features/sharding/resharding/schema.md index 7331da5..ce1683a 100644 --- a/docs/features/sharding/resharding/schema.md +++ b/docs/features/sharding/resharding/schema.md @@ -3,10 +3,10 @@ icon: material/database-edit-outline --- # Schema sync -PgDog can copy tables, indices and other entities from your production database to the new, sharded database automatically. This is faster than using `pg_dump`, because we separate this process into two parts: +PgDog can copy tables, indexes and other entities from your production database to the new, sharded database automatically. This is faster than using `pg_dump`, because we separate this process into two parts: -1. [Create tables](#tables-and-primary-keys), primary key indices, and sequences -2. Create [secondary indices](#secondary-indices) +1. [Create tables](#tables-and-primary-keys), primary key indexes, and sequences +2. Create [secondary indexes](#secondary-indexes) The create tables step needs to be performed first, before [copying data](hash.md). The second step is performed once the data sync is almost complete. @@ -30,11 +30,11 @@ Required (*) and optional parameters for this command are as follows: | `--publication`* | The name of the Postgres table [publication](#publication) with the tables you want to sync. | | `--dry-run` | Print the SQL statements that will be executed on the destination database and exit. | | `--ignore-errors` | Execute SQL statements and ignore any errors. | -| `--data-sync-complete` | Run the second step to create secondary indices and sequences. | +| `--data-sync-complete` | Run the second step to create secondary indexes and sequences. | ## Tables and primary keys -The first step in the schema sync copies over tables and their primary key indices from the source database to the new, resharded cluster. This has to be done separately, because Postgres's logical replication only copies data and doesn't manage table schemas. +The first step in the schema sync copies over tables and their primary key indexes from the source database to the new, resharded cluster. This has to be done separately, because Postgres's logical replication only copies data and doesn't manage table schemas. ### Primary keys @@ -60,7 +60,7 @@ This will make sure _all_ tables in your database will be copied and resharded i ## Schema admin -Schema sync creates tables, indices, and other entities on the destination database. To make sure that's done with a user with sufficient privileges (e.g., `CREATE` permission on the database), you need to add it to [`users.toml`](../../../configuration/users.toml/users.md) and mark it as the schema administrator: +Schema sync creates tables, indexes, and other entities on the destination database. To make sure that's done with a user with sufficient privileges (e.g., `CREATE` permission on the database), you need to add it to [`users.toml`](../../../configuration/users.toml/users.md) and mark it as the schema administrator: ```toml [[users]] @@ -83,6 +83,10 @@ Before proceeding, make sure to install the correct version of `pg_dump` for you pg_dump_path = "/path/to/pg_dump" ``` -## Secondary indices +## Secondary indexes -This step is performed after [data sync](hash.md) is complete. Running this step will create secondary indices on all your tables, which will take some time. +This step is performed after [data sync](hash.md) is complete. Running this step will create secondary indexes on all your tables, which will take some time, depending on the number of indexes in your schema. + +## Next steps + +- [Move data](hash.md) diff --git a/docs/roadmap.md b/docs/roadmap.md index 0def0f0..2e13e63 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -87,7 +87,7 @@ Support for sorting rows in [cross-shard](features/sharding/cross-shard.md) quer | Feature | Status | Notes | |-|-|-| -| [Data sync](features/sharding/resharding/hash.md#data-sync) | :material-wrench: | Sync table data with logical replication. Not benchmarked yet. | +| [Data sync](features/sharding/resharding/hash.md) | :material-wrench: | Sync table data with logical replication. Not benchmarked yet. | | [Schema sync](features/sharding/resharding/schema.md) | :material-wrench: | Sync table, index and constraint definitions. Not benchmarked yet. | | Online rebalancing | :material-calendar-check: | Not automated yet, requires manual orchestration. |