Live data from Hacker News

Scalable PostgreSQL Connection Pooler

github.com

21–30 of 91 posts

Re: Scalable PostgreSQL Connection Pooler

#21
post #3

I appreciate the work going on to make high quality poolers for Postgres...I just really wish the work was done in-core so we could have built in connection pooling, or the work done to make grabbing a new connection as cheap as if you were using a pooler. It sucks to have to add complexity to your stack to fix a "deficiency" in Postgres' design. Still, I am glad there is effort put into project even if I selfishly w…

Can someone point to an article that explains the connection issue in detail?

Short of it is that Postgres uses a process per connection, so architectures that spin up and close connections frequently can have serious scalability issues.

Note the landing page for the AWS RDS Proxy, https://aws.amazon.com/rds/proxy/ , is as good a discussion as any as to why you'd want to put a pooling proxy in front of Postgres.

Re: Scalable PostgreSQL Connection Pooler

#23
post #8

Question for anyone who knows a lot about Postgres connection pooling: We want to move to using a connection pooling infrastructure component, but so far, we haven't been able to figure out how to do so given our setup. We've got a wacky data model where we have N Postgres schemas, each of which has the same tables (but with different data, obviously.) They're not tenants; more like separate "datasets." Picture somet…

We are building a solution for this problem at Splitgraph [0] – it sounds like we could probably help with your use case, assuming this is for analytical (OLAP) data. You can get it to work yourself with our open source code [1], but our (private beta, upcoming public) SaaS will put all your schemas on a more scalable “data delivery network,” which incidentally, happens to be implemented with PgBouncer + rewriting + ephemeral instances. We also have private repositories / fine-grained ACL shipping shortly.

In a local engine (just a Postgres DB managed by Splitgraph client to add extra stuff), there is no PgBouncer or batteries-included authN/Z, but we use Foreign Data Wrappers to accomplish the same query resolving. Our goal is for you to have the ability to do everything locally as an individual, with the SaaS becoming useful for “multiplayer” (teams and orgs).

On Splitgraph, every dataset – and every version of every dataset – has an address. Think of it like tagged Docker images. The address either points to an immutable “data image” (in which case we can optionally download objects required to resolve a query on-the-fly, although loading up-front is possible too) or to a live data source (in which case we proxy directly to it via FDW translation). This simple idea of _addressable data products_ goes a long way – for example, it means that computing a diff is now as simple as joining across two tables (one with the previous version, one with the new).

Please excuse the Frankenstein marketing site – we’re in the midst of redesign / rework of info architecture while we build out our SaaS product.

Feel free to reach out if you’ve got questions. And if you have a business case, we have spots available in our private pilot. My email is in my profile – mention HN :)

[0] https://www.splitgraph.com/connect

[1] examples: https://github.com/splitgraph/splitgraph/tree/master/example...

Re: Scalable PostgreSQL Connection Pooler

#24
post #8

Question for anyone who knows a lot about Postgres connection pooling: We want to move to using a connection pooling infrastructure component, but so far, we haven't been able to figure out how to do so given our setup. We've got a wacky data model where we have N Postgres schemas, each of which has the same tables (but with different data, obviously.) They're not tenants; more like separate "datasets." Picture somet…

This may sound naive, but implementing your own pooler is very easy e.g. in Go pgproto3 already does all packet-parsing for you. Transaction poolers are looking on ReadyForQuery packet and it's "in trnsaction" property like this [0]. All you need - is stick server connection on new ParameterStatus[1] packet for "SET search_path" instead of ReadyForQuery.

[0] https://github.com/pg-sharding/spqr/blob/358f816cd8a964a9c9e... [1] https://www.postgresql.org/docs/10/protocol-flow.html#id-1.1...

Re: Scalable PostgreSQL Connection Pooler

#25
post #11

FWIW I maintain Odyssey and will be happy to answer any question regarding it. Actually there was just a CVE-triggered release... I really hope to release more often with more new functionality. If you are interested in connection pooling maybe you will find interesing SPQR too https://github.com/pg-sharding/spqr Currently it's our experiment to build pooling-based PostgreSQL sharding.

Thanks very much for posting this. Odyssey is analogous to pgbouncer, correct? I haven't set up a connection pooler yet for our postgres instance but was planning to do it eventually with pgbouncer - are you able to comment how Odyssey compares?

Connection pooler allows you to get more transactions per second on the same hardware. All it does - pack a lot of connections into handful of concurrently running PG backends. In theory all it does - relay bytes between sockets. But there are workloads when it's CPU intensive, for example lots of concurrent TLS handshakes. And pgbouncer is single-threaded! Odyssey is more scalable.

PgBouncer is a great software, actually. We built Odyssey merely to create competitor for PgBouncer. But then started to add functionality that we needed for cloud installations. E.g. Odyssey computes transaction time quantiles, when PgBouncer computes average transaction time.

Re: Scalable PostgreSQL Connection Pooler

#26
post #22

Why might I want to use this or pgbouncer instead of, say, the connection pooling built into ORMs like SQLAlchemy?

The ORM connection pooler is client-side - so each instance of your application using SQLAlchemy will have its own connection pool. This may become unwieldy as you scale up the number of app servers/containers/processes.

In contrast, connection poolers like Odyssey or pgbouncer live external to your applications, meaning that:

1. You can connect to them from any application written in any language (not just Python) 2. They provide a global pool for all of the applications connecting and help to not overload Postgres.

Re: Scalable PostgreSQL Connection Pooler

#27
post #22

Why might I want to use this or pgbouncer instead of, say, the connection pooling built into ORMs like SQLAlchemy?

You might want to have many app backends, each with it's own Alchemy pool. This setup would create a lot of Postgres connections. When the network flaps you need to reinstall lots of TLS connections. Maybe 100ms of cpu for each handshake. Also each connection may cost you a fork with lots of following CoW, also up to 100ms of cpu. And also Postgres gives you maximum TPS throughput when you run some hundreds of connections, not thousands. And you might want to isolate one microservice from another (in terms of DB throughput utilization). Poolers can help here too.

Re: Scalable PostgreSQL Connection Pooler

#28
post #3

I appreciate the work going on to make high quality poolers for Postgres...I just really wish the work was done in-core so we could have built in connection pooling, or the work done to make grabbing a new connection as cheap as if you were using a pooler. It sucks to have to add complexity to your stack to fix a "deficiency" in Postgres' design. Still, I am glad there is effort put into project even if I selfishly w…

Can someone point to an article that explains the connection issue in detail?

https://www.citusdata.com/blog/2020/10/08/analyzing-connecti...

Re: Scalable PostgreSQL Connection Pooler

#29
post #8

Question for anyone who knows a lot about Postgres connection pooling: We want to move to using a connection pooling infrastructure component, but so far, we haven't been able to figure out how to do so given our setup. We've got a wacky data model where we have N Postgres schemas, each of which has the same tables (but with different data, obviously.) They're not tenants; more like separate "datasets." Picture somet…

We are building a solution for this problem at Splitgraph [0] – it sounds like we could probably help with your use case, assuming this is for analytical (OLAP) data. You can get it to work yourself with our open source code [1], but our (private beta, upcoming public) SaaS will put all your schemas on a more scalable “data delivery network,” which incidentally, happens to be implemented with PgBouncer + rewriting +…

We're already sharding our datasets onto separate PG nodes using FDWs (mostly due to us running PG on GCP, and GCE VMs having inherent vertical scaling limitations on node-local storage, which we rely 100% on for our workloads.)

Also, our "datasets" are all live data. They aren't modified by the users querying our API, but they are constantly appended to (and I mean constantly, i.e. every few milliseconds.)

For us, PG is in our stack at this point because of its hybrid-OLAP nature: it can do realtime, row-at-a-time ingestion of data without degradation, like an OLTP store / time-series DB; but it can then perform intensive OLAP workloads against that up-to-the-moment data, involving joins, CTEs, partial computed-expression indices, etc.

(The use-case for this sort of mixed workload? Think "realtime monitoring/alerting on custom-per-user financial Business-Intelligence queries from a common financial transaction stream." We can't pre-denormalize the data, because each client wants something different. Instead, we need a normalized representation with tons of indices that serves all potential queries equally well, in roughly real time.)

For non-realtime analysis of "data at rest" (i.e. data that can be ingested in at-most-hourly batches), we can just use Snowflake. We already do, for logs and other things.

To be honest, our fondest dream would be to have a two-tiered DB setup:

1. a cold layer, where we get the SQL semantics of Postgres's querying engine, but where the storage engine is similar to those of scale-out DW services like Snowflake, with elastic per-workload compute warehouse nodes fetching compressed-columnar data from object storage into local per-worker caches (it sounds like this is similar to what you're building?)

2. a hot layer, using traditional Postgres storage, which serves as a sort of writeback cache for the cold layer:

• where all INSERTs hit the hot layer and then get async-batched to the cold layer;

• where the hot layer keeps its own indices to enable fancy OLAP querying of the hot data;

• where those queries see the cold data as "part of" the hot data, in a UNION ALL sense (probably through a FDW);

• where those queries will constraint-exclude the cold data (and thus trigger no workload on the cold layer) if the cold data isn't relevant to resolving the query — like PG11 partition constraint-exclusion.

AFAIK, you can't currently use a foreign table as a partition of a local parent table, so that'd be the first thing needing to be solved there. The next problem after that would be resolving the need for an AccessExclusiveLock to modify the range constraint on each of the parititons, since 1. the split-point between "historical" and "timely" data would be sliding forward every hour-or-so, but 2. the table would be just saturated with long-running SELECTs, so much so that it would never get a moment to lock itself to make a modification like that.

(Really, the magic wand there would be to allow partitions to have multiple parents and for "a partition" — the metadata that contains the list/range/hash constraint — to be a separate DB object from the DB table it refers to, where multiple "partitions" can reference one table-with-the-partition's-data-in-it, as long as the data meets the union of all their constraints. With those abstractions, you could build a new parent table that also references the old child tables through new partition metadata, and then just do an atomic swap of the parent tables' names when you're ready, where old queries would go on using the tables they had already dereferenced to their OIDs, and new queries would start using the new tables. Then queue up an effectively-async DROP TABLE on the old parent table, that would resolve when the DB runs out of old queries locking it open.)

Re: Scalable PostgreSQL Connection Pooler

#30
post #25

Earlier quoted context omitted.

Thanks very much for posting this. Odyssey is analogous to pgbouncer, correct? I haven't set up a connection pooler yet for our postgres instance but was planning to do it eventually with pgbouncer - are you able to comment how Odyssey compares?

Connection pooler allows you to get more transactions per second on the same hardware. All it does - pack a lot of connections into handful of concurrently running PG backends. In theory all it does - relay bytes between sockets. But there are workloads when it's CPU intensive, for example lots of concurrent TLS handshakes. And pgbouncer is single-threaded! Odyssey is more scalable. PgBouncer is a great software, act…

How does Odyssey compare to other high-performance poolers like pgagroal?
Post reply on HN