Launch HN: PeerDB (YC S23) – Fast, Native ETL/ELT for Postgres
For the past 8 years, working at Microsoft on Postgres on Azure, and before that at Citus Data, I’ve worked closely with customers running Postgres at the heart of their data stack, storing anywhere from 10s of GB of data to 10s of TB.
This was when I got exposed to the challenges customers faced when moving data in and out of Postgres. Usually they would try existing ETL tools, fail, and decide to build in-house solutions. Common issues with these tools included painfully slow syncs - syncing 100s of GB of data took days; flaky and unreliable - frequent crashes, loss of data precision on target etc., and; feature-limited - lack of configurability, unsupported data types and so on.
I remember a specific scenario where a tool didn’t support something as simple as the Postgres’ COPY command to ingest data. This would have improved the throughput by orders of magnitude. We (customer and me) reached out to that company to request them to add this feature. They couldn’t prioritize this feature because it wasn’t very easy - their tech stack was designed to support 100s of connectors rather than supporting a native Postgres feature.
After multiple such occurrences, I thought, why not build a tool specialized for Postgres, making the lives of many Postgres users easier. I reached out to my long-time buddy Kaushik, who was building operating systems at Google and had led data teams at Safegraph and Palantir. We spent a few weeks building an MVP that streamed data in real-time from Postgres to BigQuery. It was 10 times faster than existing tools and maintained data freshness of less than 30 seconds. We realized that there were many Postgres native and infrastructural optimizations we could do to provide a rich data-movement experience for Postgres users. This is when we decided to start PeerDB!
We started with two main use cases: Real-time Change Data Capture from Postgres (demo: https://docs.peerdb.io/usecases/realtime-cdc#demo) and Real-time Streaming of query results from Postgres (demo: https://docs.peerdb.io/usecases/realtime-streaming-of-query-...). The 2nd demo shows PeerDB streaming a table with 100M rows from Postgres to Snowflake.
We implement multiple optimizations to provide a fast, reliable, feature-rich experience. For performance, we can parallelize the initial load of a large table, still ensuring consistency. Syncing 100s of GB goes from days to minutes. We do this by logically partitioning the table based on internal tuple identifiers (CTID) and parallelly streaming those partitions (inspired by this DuckDB blog - https://duckdb.org/2022/09/30/postgres-scanner.html#parallel...)
For CDC, we don’t use Debezium, rather handle replication more natively—reading the slot, replicating the changes, keeping state etc. We made this choice mainly for flexibility. Staying native helps us use existing and future Postgres enhancements more effectively. For example, ...
104 comments
[ 2.8 ms ] story [ 171 ms ] threadReal-time Change Data Capture from Postgres (demo: https://docs.peerdb.io/usecases/realtime-cdc#demo)
Real-time Streaming of query results from Postgres (demo: https://docs.peerdb.io/usecases/realtime-streaming-of-query-...)
I've worked with Sai for years, so I just wanted to put in a good word for PeerDB and its founders. Sai is resourceful and relentless; his energy and optimism are contagious. Kaushik complements that with deep backend and analysis skills.
Data movement is a big pain point with different players. I think it's time that there's a Postgres-centric solution out there built by a team who gets Postgres. Best of luck!
Good luck!
1 - https://www.youtube.com/watch?v=ZNvuobLvL6M
As a vision statement to me it resonates, now curious to give it a try and see if it fulfills on that vision.
In regards to CSV as a connector, postgres’s COPY command should do it right? Am I missing something? Is it CSV files in cold storage (like s3 etc)? OR periodic streaming of CSV files into Postgres?
[0] https://docs.peerdb.io/sql/commands/supported-connectors#:~:...
Or the reverse, is it possible to have a forever running query that can stream results as and when new data comes...
For CDC, change stream does give us events in case of schema changes, we would have to replay them on the destination. Schema changes on the destination are not supported, the general recommendation is to build new tables / views and let PeerDB manage the destination table.
For streaming the results of a query, as long as the query itself can execute (say a few columns were added or untouched columns were edited) mirror job will continue to execute. In case this is not the case, there will be some manual intervention needed to account for the schema changes.
Thanks for the question, this is a requested feature and on our roadmap.
Simply looking at the docs on these two pages, its unclear to me whether there's a way to update the mirror definition when a schema change occurs or if I need to drop & recreate the mirror (and what the effects of this are in the destination):
- https://docs.peerdb.io/sql/commands/create-mirror
- https://docs.peerdb.io/usecases/Streaming%20Query%20Replicat...
All-in-all, very excited to see this project and will be watching it closely!
1/ logical replication support for schema (DDL) changes
2/ a native logical replication plugin (not wal2json) which is easier to read from the client side. pgoutput is fast but from reading/parsing from the client side is not as straightforward.
3/ improve decoding perf - i've observed pgoutput to cap at 10-15k changes per sec, for an average usecase. This is after good amount of tuning - ex: logical_replication_work_mem etc. Enabling larger tps - 50k+ tps would be great. Also this is important for Postgres, considering the diverse variety of workloads users are running. For example at Citus, I saw customers doing 500k rps (with COPY), I am not sure logical replication can handle those cases.
4/ logical replication slots in remote storage. one big risk with slots is that they can grow in size (if not read properly) and use up storage on the source. allowing shipping slots to remote storage would really help. i think Oracle allows something like this, but not 100% sure.
5/ logical decoding on standby. it is coming in postgre 16! we will aim to support in PeerDB, right after it is available.
I can think of many more, but sharing a few top ones that came to my mind!
As a source, PeerDB should likely work with any Postgres based databases (like Citus). Query based replication should work! Log based (CDC) replication could have a few quirks - i.e. the source database should support "pgoutput" format for change data capture. As we evolve we do planning to enable a native data-movement experience for Postgres based (both extensions and postgres-compatible) databases!
> no dependence on kafka, zookeper, kafka connect
That's not required with Debezium either, using Debezium Server (even with Kafka, ZK is obsolete nowadays anyways)
> managed experience for CDC from PostgreSQL through our enterprise & hosted offerings
There's several hosted offerings based on Debezium (one example being what we do at decodable.co)
> performance wise, with the optimization we are doing
I'd love to learn more about this. Debezium also supports parallel snapshotting, but I'm not clear what exactly you mean by parallelized reading of slos and the CDC impact on targets. Looking forward to reading your blog post :)
> Looks like Debezium Server doesn't require Kafka, ZK for setup. However it supports only messaging queues as sinks (targets). So to stream CDC from Postgres to a DWH - one needs to a) setup/manage messaging infra as a part of their stack to capture CDC changes b) write/manage reading from the message queue and replaying the changes to the target store (ex: Snowflake, BQ etc). With PeerDB, you can skip these 2 steps. CREATE MIRROR can have targets that are queues, DWHs or databases.
> That is true, however the ones we tried aren't very simple to work with. For example - confluent was super tricky to work with. One has to setup a sink (to message queues), use another connector to move those changes to snowflake, use something else to normalize those changes to the final table. Overall total number of moving parts were quite a lot. decodable.co might give a better experience, will give it shot! :)
> On parallel snapshotting, very interesting, looks like it is a recent feature Debezium added (March 2023). I missed that one. In regards to parallelized reading of slot, Postgres enables you to read a single slot concurrently across 2 connections using 2 separate publications - each publication filters a set of tables. Same here, we are also excited for the benchmarks. Will keep you posted! :)
Thanks again!
Could this be used as a sort of "live backup" of your data? (i.e. just making sure that data isn't lost if the server dies down completely, not thinking of HA)
Sorry if it's a bit of a stupid question, I realize it's not the main focus of PeerDB.
Sure you can use PeerDB for backing up data - using CDC based replication or query based replication and both of these are pretty fast with PeerDB. You can have cold backups (store data to s3, blob etc) or hot backups (another postgres database). However note that the replication is async and there is some lag (few 10s of seconds) on the target data-store. So if you are expecting 0 data-loss, this won't be the right approach for backups/HA. With streaming replication, replication can be synchronous (synchronous_commit setting), which helps with 0 data-loss.
(Also, not having pricing when launching seems like a very strange choice, since potential buyers might pass and never come back.)
On the pricing side, valid feedback. We are actively working with customers and are coming up with custom (reasonable) pricing based on their use-case and usage level of product. Through this process we are getting a ton of feedback. As mentioned in the post, a common concern we heard from customers is that the existing tools are expensive (pricing is black box) - they charge based on the amount data-transferred. We are thinking of ways to make pricing more transparent (see post on what our thinking has been so far). But haven't landed on the right strategy yet. We didn't want to rush through publishing any pricing.
We are currently using DMS to send data to S3 and from there to Snowflake.
In our setup DMS pushes Parquet files on s3. Snowflake then loads data from there.
We’ve occasionally had to do a full table sync from scratch, which is painfully slow. We are going to have to do that in the very near future - when we are upgrading from Postgres 11 to Postgres 15.
The S3 step also seems unnecessarily complicated, since we have to expire data from the bucket.
How does PeerDB handle things like schema changes? Would the change replicate to Snowflake? (I’m sure this is in the docs, but I’m supposed to be on holiday this week ) Thanks for the quick reply.
I cannot wait to try this to see if I can remove Meltano (Postgres-to-Postgres) and my custom Postgres-to-Bigquery code.