700 views
asked in PostgreSQL by
Using PgBouncer to improve performance and reduce the load on PostgreSQL

1 Answer

answered by

inchirags@gmail.com                        Chirags PostgreSQL DBA Tutorial                           https://www.chirags.in

*************************************************************************************

Using PgBouncer to improve performance and reduce the load on PostgreSQL

*************************************************************************************

---------install and configure pgbouncer----------------

Let's assume we have a PostgreSQL server.

postgres@dept:~$ psql -h 127.0.0.1 -p 5432 -U postgres -d postgres
Password for user postgres:
psql (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.

postgres=#
postgres=# select version();
                                                              version
-----------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 16.4 (Ubuntu 16.4-1.pgdg22.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
(1 row)
postgres=#

Let's install pgbouncer:

root@dept:~# sudo apt-get install pgbouncer

The next step is to configure pgbouncer.

root@dept:~# sudo vi /etc/pgbouncer/pgbouncer.ini

In the [databases] block, add the following entry:

* = host=localhost port=5432

In the "Pooler personality questions" section, I define pool_mode=transaction.

...

;;;

;;; Pooler personality questions

;;;

;; When server connection is released back to pool:

;;   session      - after client disconnects (default)

;;   transaction  - after transaction finishes

;;   statement    - after statement finishes

pool_mode = transaction

...

In the "Connection limits" section, we set the total number of clients that can connect to some high value:

max_client_conn=5000.

...

;;;

;;; Connection limits

;;;

;; Total number of clients that can connect

max_client_conn = 5000

...

In the "Authentication settings" section, we set auth_type = md5 to authenticate users by password. The file with database login and password will be located at /etc/pgbouncer/userlist.txt

...

;;;

;;; Authentication settings

;;;

;; any, trust, plain, md5, cert, hba, pam

auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

...

In the "Users allowed into database 'pgbouncer'" section, we set the admin_users parameter. This is the database user who will have permission to make pgbouncer settings in the database.

...

;;;

;;; Users allowed into database 'pgbouncer'

;;;

;; comma-separated list of users who are allowed to change settings

;admin_users = user2, someadmin, otheradmin

admin_users = postgres

...

Now let's open the file with users at /etc/pgbouncer/userlist.txt.

root@dept:~# vi /etc/pgbouncer/userlist.txt

If you are using PostgreSQL versions starting from 14, then the default password_encryption method is scram-sha-256.

Here we place the username in double quotes and the scram-sha-256 password hash (in one line):

"postgres" "SCRAM-SHA-256$4096:kPG/5jtnbUx+myFzRoZ6CA==$S1/MVQVNkpMXI+s0PAKw2u4P3YHkDcVLAjl5lVyCGuA=:/yoSqXXuIvlNDxmj1izwlivbFRBWatiHQGh50p4bfVc="

To determine the scram-sha-256 password hash, you can use the following method:

psql -h db_host -p db_port -Atq -U postgres -d postgres -c "SELECT concat('\"', usename, '\" \"', passwd, '\"') FROM pg_shadow"
OR 
postgres=# SELECT usename, passwd FROM pg_shadow;
 usename  |                                                                passwd
----------+---------------------------------------------------------------------------------------------------------------------------------------
 postgres | SCRAM-SHA-256$4096:kPG/5jtnbUx+myFzRoZ6CA==$S1/MVQVNkpMXI+s0PAKw2u4P3YHkDcVLAjl5lVyCGuA=:/yoSqXXuIvlNDxmj1izwlivbFRBWatiHQGh50p4bfVc=
(1 row)
(END)

To make our application use pgbouncer when connecting to the database, all we need to change is the port number: use 6432 instead of 5432.

Note : 

If you are using PostgreSQL versions up to 13 inclusively, then the default password_encryption method is md5.

Here we place the username in double quotes and the md5 password hash (in one line):

"my_db_user" "md5badc318d987f61146c6ad8e15d84a111"

To determine the md5 password hash, you can use the following method:

echo "md5"$(echo -n 'YourdbpasswordYourdbusername' | md5sum | awk ' { print $1 } ')

After that, let's reload pgbouncer:

sudo service pgbouncer restart

And after that, we will be able to connect to the database through pgbouncer using port 6432 (pgbouncer default port).

: Note end

Let's run a performance test to compare the performance of connecting to PostgreSQL with and without pgbouncer, using the pgbench utility.

The maximum number of connections for my database is set to 100:

postgres=# show max_connections;
 max_connections
-----------------
 100
(1 row)

Connecting to the Postgres database server without using PgBouncer.

This command will start a test with 1000 concurrent clients for 60 seconds, connecting directly to the PostgreSQL database.

postgres@dept:~$ pgbench -c 1000 -T 60 mydatabase -h 127.0.0.1 -p 5432 -U postgres
Password:
pgbench (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
pgbench: error: could not count number of branches: ERROR:  relation "pgbench_branches" does not exist
LINE 1: select count(*) from pgbench_branches
                             ^
pgbench: hint: Perhaps you need to do initialization ("pgbench -i") in database "mydatabase".
postgres@dept:~$ 

Note: if you are getting error like above then run the below command.

postgres@dept:~$ pgbench -i mydatabase
Output:
dropping old tables...
NOTICE:  table "pgbench_accounts" does not exist, skipping
NOTICE:  table "pgbench_branches" does not exist, skipping
NOTICE:  table "pgbench_history" does not exist, skipping
NOTICE:  table "pgbench_tellers" does not exist, skipping
creating tables...
generating data (client-side)...
100000 of 100000 tuples (100%) done (elapsed 0.51 s, remaining 0.00 s)
vacuuming...
creating primary keys...
done in 1.27 s (drop tables 0.01 s, create tables 0.04 s, client-side generate 0.59 s, vacuum 0.35 s, primary keys 0.29 s).

Now, again run

postgres@dept:~$ pgbench -c 1000 -T 60 mydatabase -h 127.0.0.1 -p 5432 -U postgres
Password:
pgbench (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
starting vacuum...end.
pgbench: error: connection to server at "127.0.0.1", port 5432 failed: FATAL:  sorry, too many clients already
connection to server at "127.0.0.1", port 5432 failed: FATAL:  sorry, too many clients already
pgbench: error: could not create connection for client 100
postgres@dept:~$

Simulating the work of 1000 clients interacting with a database where only 100 clients can be connected at maximum results in an error.

FATAL:  sorry, too many clients already

Check into PostgreSQL Datbase maximun connection limit is

postgres@dept:~$ psql
psql (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
Type "help" for help.
postgres=#  SHOW max_connections;
 max_connections
-----------------
 100
(1 row)

postgres=# 

Connecting to the Postgres database server using pgbouncer:

When connecting to the database using pgbouncer, everything works without any issues.

postgres@dept:~$ pgbench -c 1000 -T 60 mydatabase -h 127.0.0.1 -p 6432 -U postgres
Password:
pgbench: error: connection to server at "127.0.0.1", port 6432 failed: FATAL:  password authentication failed
pgbench: error: could not create connection for setup
postgres@dept:~$

Now, I am going to add md5 in /etc/postgresql/16/main/pg_hba.conf file.

Add below line.

# IPv4 local connections:
host    all             all             127.0.0.1/32            md5

root@dept:~# sudo systemctl restart pgbouncer
root@dept:~# sudo systemctl restart postgresql
root@dept:~# su - postgres

postgres@dept:~$ pgbench -c 1000 -T 60 mydatabase -h 127.0.0.1 -p 6432 -U postgres
Password:
pgbench (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
starting vacuum...end.
transaction type: builtin: TPC-B (sort of)
scaling factor: 1
query mode: simple
number of clients: 1000
number of threads: 1
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 1797
number of failed transactions: 0 (0.000%)
latency average = 33878.157 ms
initial connection time = 33073.513 ms
tps = 29.517544 (without initial connection time)
postgres@dept:~$

Now, we can test with below command

Let's compare the number of transactions per second that the database performs when the application connects to the database without using pgbouncer and when it uses pgbouncer.

postgres@dept:~$ vi mysql.sql
select 1;

The -C option in the pgbench indicates that for every single transaction pgbench will close the open connection and create a new one. This is useful to measure the connection overhead.

In my test I perfom select-only transactions. The reason is I want to exclude measuring update contention, when lots of transactions blocked waiting for other transactions.

The application connects to the database without using pgbouncer:

postgres@dept:~$ pgbench -c 20 -T 60 mydatabase -h 127.0.0.1 -p 5432 -U postgres -C -f mysql.sql
Password:
pgbench (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
starting vacuum...end.
transaction type: mysql.sql
scaling factor: 1
query mode: simple
number of clients: 20
number of threads: 1
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 475
number of failed transactions: 0 (0.000%)
latency average = 2535.545 ms
average connection time = 125.613 ms
tps = 7.887849 (including reconnection times)
postgres@dept:~$

#using PgBouncer

postgres@dept:~$ pgbench -c 20 -T 60 mydatabase -h 127.0.0.1 -p 6432 -U postgres -C -f mysql.sql
Password:
pgbench (16.4 (Ubuntu 16.4-1.pgdg22.04+1))
starting vacuum...end.
transaction type: mysql.sql
scaling factor: 1
query mode: simple
number of clients: 20
number of threads: 1
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 1540
number of failed transactions: 0 (0.000%)
latency average = 779.689 ms
average connection time = 37.899 ms
tps = 25.651237 (including reconnection times)
postgres@dept:~$

Here we can compare both the requests

latency average = 2535.545 ms - 779.689 ms --- improvement 

tps = 7.887849 - 25.651237  --- improvement

#Useful admin console commands

Here are a few commands that can be used after connecting to the pgbouncer database. These may be helpful for troubleshooting purposes:

SHOW HELP: Displays the help page. It is useful when remembering commands.

SHOW STATS: Displays transaction count, timing, etc.

SHOW POOLS: Displays active and waiting clients and server counts. It also shows how long the oldest client waited in the queue. It is very helpful when determining pool_size.

SHOW SERVERS: Displays information about database connections made by PgBouncer.

SHOW CLIENTS: Displays information about clients that connected via PgBouncer.

SHOW DATABASES: Displays information about configured databases.

PAUSE [DB]: Useful when stopping connection to a specific database. PgBouncer waits for all queries to be completed, then puts new connections into a queue. You should be careful about timeouts on all sides. It is very useful when restarting PostgreSQL. You may want to increase the number of file descriptors. This command will not return before all queries have finished.

RESUME [DB]: Resumes the KILL, PAUSE, or SUSPEND the specific database.

RECONNECT [DB]: Closes and reconnects all server connections. If you are planning to do a switchover, consider using PAUSE command. If you have done a failover, consider using the KILL command.

DISABLE [DB]: Disallows new connections to the specific database.

ENABLE [DB]: Allows new connections to the specific database after a DISABLE command.

KILL [DB]: Drops all client and server connections and pauses the specific database.

RELOAD: It can be used for reloading the PgBouncer after a configuration change.

SHUTDOWN: It can be used to exit the PgBouncer process. Use systemd instead if possible.

Note : Flow the Process shown in video.

Please Like and Subscribe for more videos:

https://www.youtube.com/@chiragstutorial

Don't forget to, Follow, Like,  Share &, Comment

Tutorial Link :

https://www.chirags.in/tutorials/PostgreSQL_Database

Thanks & Regards,

Chitt Ranjan Mahto "Chirag"

____________________________________________________________________

Note: All scripts used in this demo will be available in our website.

Link will be available in description.

Most popular tags

laravel postgresql laravel-10 replication ha postgresql mongodb laravel-11 mongodb database mongodb tutorial ubuntu 24.04 lts streaming-replication mysql database laravel postgresql backup laravel login register logout database mysql php laravel 11 - login with otp valid for 10 minutes. user and admin registration user and admin login multiauth technlogy asp.net asp.net c# mysql master slave replication centos linux laravel sql server schedule backup autobackup postgresql django python haproxy load balancer install self sign ssl laravel 11 gaurds zabbix 7 how to install graylog on ubuntu 24.04 lts | step-by-step asp.net core mvc .net mvc network upload c# ssl integration sql server on ubuntu 22.04 lts mssql server ms sql server sql server user access in postgres mysql password change cent os linux configure replica laravel 11 socialite login with google account google login kubernetes (k8s) install nginx load balancer install install and configure .net 8.0 in ubuntu 24.04 lts php in iis php with iis php tutorial chirags php tutorials chirags php tutorial chirags tutorial laravel 11 guards mongodb sharding metabase business analytics metabase postgresql 16 to postgresql 17 postgresql migration letsencrypt mongodb crud rocky linux laravel custom captcha laravel 11 captcha laravel captcha mongo dll php.ini debian 12 nginx apache nextcloud gitea in ubuntu git gitea npm error node js mysql ndb cluster mysql cluster ssl oracle login register logout in python debian windows shell batch file bat file time stamp date time shopping cart in laravel centos rhel swap memeory rhel 5.5
...