Increasing PgBouncer Throughput by 4x on AWS EC2

ClickHouse Cloud icon

Imagine pulling off a staggering 87,000 transactions per second with PgBouncer on AWS EC2. It sounds like something out of a tech fantasy, right? But this isn’t just a number thrown around at a conference; it’s a reality that has implications for how we think about database performance and scalability. It’s impressive, yes, but also raises questions about what we really need from our database solutions in an age where speed often trumps stability.

When you look closer, that number speaks to a growing trend: the quest for efficiency in a world saturated with data. The challenge is balancing sheer speed with reliability. We can push boundaries, but at what cost? The success of this setup might make you wonder whether traditional databases are keeping up or if we’re simply chasing numbers for the sake of it.

What does it take to achieve such impressive performance? More importantly, what does this mean for developers and businesses reliant on robust database systems? Let’s dig into the details and explore the practical implications of this achievement.

Understanding PgBouncer's Role in Database Scaling

PgBouncer is a lightweight connection pooler for PostgreSQL, and it plays a critical role in managing database connections efficiently. In high-load environments, where thousands of transactions are common, PgBouncer helps improve throughput by maintaining a pool of active connections that can be reused instead of opening and closing connections repeatedly. This significantly reduces the overhead on the database server and speeds up query execution.

The architecture of PgBouncer is designed for high performance. It can handle a substantial number of client connections—up to 256 in some setups—while efficiently managing database resources. One standout metric is its ability to reach peak performance of 87,000 transactions per second on AWS EC2 instances with just a single process. This indicates that even in a constrained environment, PgBouncer can deliver impressive results, making it a good choice for applications that experience variable loads or high transaction volumes. In a typical deployment, a single PgBouncer instance runs with about 16% CPU utilization, whereas a fleet of these instances averages around 60% CPU utilization under load, revealing how effectively it can distribute workloads.

However, it's essential to consider the architecture you choose for your deployment. For instance, when asked about the effectiveness of using HAProxy in conjunction with multiple PgBouncer instances, the response was more straightforward than expected: "Just use https://github.com/yandex/odyssey :) It's a scalable PgBouncer." This suggests that while traditional setups can work, exploring alternatives like Odyssey may provide better scalability and management for complex systems.

Here's a simple example of how to configure PgBouncer for a PostgreSQL database. This configuration ensures that PgBouncer can handle a reasonable number of incoming connections while maintaining performance:

[databases]
mydatabase = host=localhost dbname=mydatabase user=myuser password=mypassword

[pgbouncer]
listen_addr = *
listen_port = 6432
max_client_conn = 256
default_pool_size = 20

This configuration file sets up PgBouncer to listen for connections and limits the number of client connections to 256 while maintaining a default pool size of 20 for each database. Adjust these parameters based on your specific requirements and load characteristics.

Performance Metrics and Benchmarks

In our testing setup, we configured 16 vCPUs and established 256 client connections to evaluate the performance of PgBouncer running on AWS EC2 instances. The results were impressive, with a single process peaking at 87,000 transactions per second. This figure illustrates the capabilities of PgBouncer in handling a high volume of database connections effectively.

During the benchmarks, we observed that the single-process instance maintained an average CPU utilization of about 16%. This low utilization under peak load indicates that PgBouncer is efficient, allowing for substantial transaction throughput without overloading the CPU resources. When we expanded the testing to multiple instances, the fleet's average CPU utilization rose to around 60%. This higher utilization reflects the increased load and the ability of the system to scale by distributing the traffic across multiple PgBouncer instances.

A question that often arises is whether there are disadvantages to using HAProxy with multiple PgBouncer instances. In my experience, it largely depends on the specific use case and workload. For those looking for an alternative to scale PgBouncer effectively, the community has suggested using Odyssey, which is designed as a scalable PgBouncer solution. Here’s a simple command to install Odyssey on your system:

sudo apt-get install odyssey

This benchmark not only highlights PgBouncer's performance but also opens up discussions about optimization strategies when managing database connections in high-demand environments.

Optimizing Resource Utilization

During our tests, we observed notable differences in CPU utilization between single-process performance and the fleet averages when using PgBouncer on AWS EC2 instances. With a setup of 16 vCPUs and 256 client connections, we achieved impressive benchmarks. The single-process instance peaked at 87,000 transactions per second while averaging around 16% CPU utilization. In contrast, the fleet of instances averaged about 60% CPU utilization under similar loads.

This disparity raises an interesting question: Is it better to scale out with multiple instances or to optimize single-process performance? The single-process peak is enticing, but the higher average CPU utilization in the fleet indicates that scaling horizontally can spread the resource load more evenly and potentially handle bursts of traffic more effectively. If you're looking for a balance between performance and resource allocation, consider using multiple PgBouncer instances. A comment from one of our tests posed the question, "Was there a disadvantage to using HAProxy + multiple PgBouncer instances?" This suggests that while there may be trade-offs, the scalability benefits are worth exploring.

For those interested in an alternative approach, consider using Odyssey, a scalable PgBouncer solution from Yandex. It's designed to handle high loads more efficiently by managing connections and transactions in a more distributed manner. The trade-offs between complexity and performance can vary based on your specific workload, so it's crucial to test both strategies in your environment.

Here's a simple setup command for deploying PgBouncer with HAProxy on AWS EC2:

sudo apt-get update
sudo apt-get install haproxy pgbouncer

This command ensures that you have both HAProxy and PgBouncer installed, giving you a solid foundation to manage your database connections efficiently.

Conclusion

Increasing PgBouncer throughput by 4x on AWS EC2 is impressive, but it also raises questions about the balance between resource optimization and the complexity of database scaling. Hitting 87,000 transactions per second with just 16 vCPUs and 256 client connections shows that there’s a lot of room to maximize performance, but it can feel a bit like chasing an ever-moving target. As we delve deeper into optimizing tools like PgBouncer, we might find that the trade-offs between performance gains and system complexity could complicate rather than simplify our architectures.

It’s worth pondering how many organizations will realistically push their limits to achieve such metrics. The benchmarks are attractive, but not every use case will need or benefit from extreme optimization. For teams looking to enhance their database performance, the key might not just be about achieving higher throughput but understanding when and why to optimize. So, what’s your threshold? Is 87k transactions/sec the goal, or is there a point where diminishing returns kick in?