Skip to content

Instantly share code, notes, and snippets.

@linuxmalaysia
Last active September 15, 2024 02:16
Show Gist options
  • Save linuxmalaysia/0c6287c25957bc1b36af750d4abeb838 to your computer and use it in GitHub Desktop.
Save linuxmalaysia/0c6287c25957bc1b36af750d4abeb838 to your computer and use it in GitHub Desktop.
# Harisfazillah Jamel - 11 Sept 2024 # Need to create systemd template for pgbouncer@.service and pgbouncer@.socket # By using so_reuseport in pgbouncer setting # and copy of /etc/pgbouncer/pgbouncer.ini to /etc/pgbouncer/pgbouncer.ini # Do this after all the tune and test run with single pgbouncer done. # https://www.2ndquadrant.com/en/blog/run…
#!/bin/bash
# Harisfazillah Jamel - 11 Sept 2024
# Need to create systemd template for pgbouncer@.service and pgbouncer@.socket
# By using so_reuseport in pgbouncer setting
# and copy of /etc/pgbouncer/pgbouncer.ini to /etc/pgbouncer/pgbouncer.ini
# Do this after all the tune and test run with single pgbouncer done.
# https://www.2ndquadrant.com/en/blog/running-multiple-pgbouncer-instances-with-systemd/
# https://www.enterprisedb.com/postgres-tutorials/pgbouncer-setup-extended-architecture-use-cases-and-leveraging-soreuseport
# Please check for running pgbouncer if you find this script in your server
# ps -ef | grep pgbouncer
# use multitail to tail many log fails. multitail /var/log/postgresql/pgbouncer-50001.log /var/log/postgresql/pgbouncer-50002.log
# More detail in this LinuxMalaysia GIST comments.
# Check if an argument is provided
if [ -z "$1" ]; then
echo "Error: Please provide a port number as an argument."
echo "Example usage: ./configure_pgbouncer.sh 12345"
exit 1
fi
# Get the port number from the argument
port_number="$1"
# Enable systemd services (replace template with the port number)
systemctl enable pgbouncer@"$port_number".socket pgbouncer@"$port_number".service
# Copy configuration file and set ownership
cp /etc/pgbouncer/pgbouncer-template.ini /etc/pgbouncer/pgbouncer-"$port_number".ini
chown postgres /etc/pgbouncer/pgbouncer-"$port_number".ini
# Update configuration file (replace template references with port number)
sed -i "s/pgbouncer-template.log/pgbouncer-$port_number.log/g" /etc/pgbouncer/pgbouncer-"$port_number".ini
sed -i "s/pgbouncer-template.pid/pgbouncer-$port_number.pid/g" /etc/pgbouncer/pgbouncer-"$port_number".ini
# Start systemd services
systemctl start pgbouncer@"$port_number".socket pgbouncer@"$port_number".service
# Check if PID and log files exist
if [ -f "/var/run/postgresql/pgbouncer-$port_number.pid" ]; then
echo "PID file /var/run/postgresql/pgbouncer-$port_number.pid exists."
else
echo "PID file /var/run/postgresql/pgbouncer-$port_number.pid does not exist."
fi
if [ -f "/var/log/postgresql/pgbouncer-$port_number.log" ]; then
echo "Log file /var/log/postgresql/pgbouncer-$port_number.log exists."
tail /var/log/postgresql/pgbouncer-$port_number.log
else
echo "Log file /var/log/postgresql/pgbouncer-$port_number.log does not exist."
fi
# Check if pgbouncer process is running
if ps -ef | grep "/usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer-$port_number.ini" | grep -v grep > /dev/null; then
echo "pgbouncer process is running."
else
echo "pgbouncer process is not running."
fi
systemctl status pgbouncer@"$port_number".socket pgbouncer@"$port_number".service
exit
@linuxmalaysia
Copy link
Author

https://www.pgbouncer.org/config.html

Refer to so_reuseport

Each PgBouncer instance on the same host needs different settings for at least unix_socket_dir and pidfile, as well as logfile if that is used. Also note that if you make use of this option, you can no longer connect to a specific PgBouncer instance via TCP/IP, which might have implications for monitoring and metrics collection.

@linuxmalaysia
Copy link
Author

linuxmalaysia commented Sep 15, 2024

PgBouncer: A Guide to Efficiently Managing Multiple Instances

PgBouncer is a connection pooler for PostgreSQL, designed to minimize the performance overhead of establishing new database connections. Applications can interact with PgBouncer as if it were a PostgreSQL server, while PgBouncer manages underlying connections to the actual database.

PgBouncer traditionally operates as a single process, which can limit its ability to utilize multiple CPUs on a host. To improve scalability and resource utilization, running multiple PgBouncer instances is often recommended. This guide will demonstrate how to set up and manage these instances using systemd, ensuring efficient operation and easy administration.

Using SO_REUSEPORT for Multi-Instance Deployment

PgBouncer version 1.12 introduced support for the SO_REUSEPORT socket option, allowing multiple instances to listen on the same port and share connections. This approach offers several advantages:

Improved Scalability: Multiple instances can handle more concurrent connections and distribute the load across available CPUs.
Efficient Resource Utilization: By sharing connections, instances can reduce the overhead of connection establishment and management.
Simplified Configuration: All instances can listen on the same port, simplifying management and deployment.

Configuration Considerations

When running multiple instances on the same host, ensure each instance has unique settings for at least unix_socket_dir, pidfile, and logfile (if used). Note that using SO_REUSEPORT prevents direct TCP/IP connections to specific instances, which may impact monitoring and metrics collection.

Key Steps for Setting Up Multiple PgBouncer Instances with Systemd

Configure PgBouncer: Create individual configuration files for each instance, specifying unique connection pool settings, authentication credentials, and other parameters.
Create Systemd Units: Write systemd unit files for each instance, defining the service name, execution command, and other relevant settings.
Start and Manage Instances: Utilize systemd commands to start, stop, restart, or reload the PgBouncer instances as required.

This guide assumes you have PgBouncer installed on Ubuntu 22.04 LTS. To ensure you're using the latest version (currently 1.23.1 as of September 2024), we recommend installing PostgreSQL Global Development Group's (PGDG) repository. This repository provides access to the most recent PgBouncer packages. You can find installation instructions for PGDG on the PostgreSQL

https://wiki.postgresql.org/wiki/Apt#PostgreSQL_packages_for_Debian_and_Ubuntu

sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh

Detailed PgBouncer Installation (Optional)

For detailed instructions on installing PgBouncer itself, refer to the Scaleway documentation: https://www.scaleway.com/en/docs/tutorials/install-pgbouncer/. This guide provides a step-by-step process for setting up PgBouncer on your Ubuntu server.

@linuxmalaysia
Copy link
Author

linuxmalaysia commented Sep 15, 2024

Ensure PgBouncer is configured correctly by editing /etc/pgbouncer/pgbouncer.ini. Adjust settings as needed, such as

localhost: Replace with the hostname or IP address of your PostgreSQL database.
pool_mode: Choose session or transaction based on your application requirements.
max_client_conn: Set the maximum number of concurrent client connections.

Using SCRAM-SHA-256 Authentication

Ensure your PostgreSQL database uses SCRAM-SHA-256 password encryption.

Sample Configuration

This is a sample pgbouncer.ini configuration to get you started. Remember to modify the settings as needed for your specific environment.

[databases]

postgres = host=localhost port=5432
* = host=localhost port=5432

[pgbouncer]

listen_addr = localhost
listen_port = 6432
unix_socket_dir = /tmp

so_reuseport = 1

pool_mode = session

max_client_conn = 5000

auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid

@linuxmalaysia
Copy link
Author

linuxmalaysia commented Sep 15, 2024

You can simply copy the existing PgBouncer systemd file (/lib/systemd/system/pgbouncer.service) and configuration file (/etc/pgbouncer/pgbouncer.ini) to run separate services.

if you want to run multiple instances, you can obviously just make copies of pgbouncer systemd file /lib/systemd/system/pgbouncer.service and pgbouncer configuration file /etc/pgbouncer/pgbouncer.ini, run them as entirely separate services. But here we want to make use of the systemd template system. So create a file /etc/systemd/system/pgbouncer@.service by copying /lib/systemd/system/pgbouncer.service

Creating a Systemd Unit Template

Begin by creating a systemd unit template file named pgbouncer@.service in the /etc/systemd/system directory. Copy the content from the original service file (/lib/systemd/system/pgbouncer.service), making the following modifications, A placeholder %i has been added to Description, Requires and ExecStart. This will be replaced with our input during service creation.

Template Unit File (/etc/systemd/system/pgbouncer@.service):

[Unit]
Description=connection pooler for PostgreSQL (%i)
Documentation=man:pgbouncer(1)
Documentation=https://www.pgbouncer.org/
After=network.target
#Requires=pgbouncer.socket
Requires=pgbouncer@%i.socket

[Service]
Type=notify
User=postgres
###ExecStart=/usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer.ini
ExecStart=/usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer-%i.ini
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGINT
#LimitNOFILE=1024

[Install]
WantedBy=multi-user.target

It's essential to run systemctl daemon-reload after making changes to systemd unit files or configuration files. This command ensures that systemd reloads its configuration, taking the new changes into account.

@linuxmalaysia
Copy link
Author

Limitations of Shared Unix Sockets

While the so_reuseport setting allows multiple PgBouncer instances to share TCP/IP listening sockets, it doesn't extend to Unix-domain sockets. This creates a challenge

Disable Unix Sockets: This removes some of the convenience of this approach.
Separate Configuration Files: Each instance needs a unique configuration with a different Unix socket directory, which can become cumbersome.

Socket Activation: A Better Solution (PgBouncer 1.14+)

For PgBouncer versions 1.14 and later, we recommend using socket activation provided by systemd. This offers a more elegant solution:

Copy Systemd Unit Template: Copy /lib/systemd/system/pgbouncer.socket to /etc/systemd/system/pgbouncer@.service, modifying it as follows

Systemd Unit Template (/etc/systemd/system/pgbouncer@.service)

[Unit]
Description=Sockets for PgBouncer (%i)

[Socket]
ListenStream=6432
ListenStream=%i  # Instance-specific port
ListenStream=/tmp/.s.PGSQL.%i  # Instance-specific Unix socket

ReusePort=true

# additional settings that might be useful
#Backlog=
#SocketUser=
#SocketGroup=
#SocketMode=
#KeepAlive=
#KeepAliveTimeSec=
#KeepAliveIntervalSec=
#KeepAliveProbes=
#DeferAcceptSec=
#ReusePort=

[Install]
WantedBy=sockets.target

@linuxmalaysia
Copy link
Author

Copy the Original Configuration: Begin by copying the existing PgBouncer configuration file (/etc/pgbouncer/pgbouncer.ini) to a new location with a descriptive name, such as /etc/pgbouncer/pgbouncer-template.ini and update Log and PID File Paths

Edit the newly copied template file (pgbouncer-template.ini) and modify the following settings

logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid

to

logfile = /var/log/pgbouncer/pgbouncer-template.log
pidfile = /var/run/pgbouncer/pgbouncer-template.pid

These changes ensure each PgBouncer instance created from this template will have unique log and PID files. This prevents conflicts that could arise if multiple instances shared the same log and PID file paths.

@linuxmalaysia
Copy link
Author

Starting a New PgBouncer Instance

Ensure the primary PgBouncer instance is running. Verify its status using

systemctl status pgbouncer.socket pgbouncer.service

Copy the template configuration file (/etc/pgbouncer/pgbouncer-template.ini) to a new location with a descriptive name, such as /etc/pgbouncer/pgbouncer-50001.ini. This name reflects the chosen administration port number (50001 in this example) and set ownership of the new file to the postgres user.

cp /etc/pgbouncer/pgbouncer-template.ini /etc/pgbouncer/pgbouncer-50001.ini
chown postgres /etc/pgbouncer/pgbouncer-50001.ini

Modify the copied configuration file (pgbouncer-50001.ini) to replace references to the template names with the specific port number (50001). You can use sed or any preferred text editor for this purpose. Here's an example using sed

sed -i "s/pgbouncer-template.log/pgbouncer-50001.log/g" /etc/pgbouncer/pgbouncer-50001.ini
sed -i "s/pgbouncer-template.pid/pgbouncer-50001.pid/g" /etc/pgbouncer/pgbouncer-50001.ini

Enable the systemd socket and service for the new PgBouncer instance, specifying the chosen port number

systemctl enable pgbouncer@50001.socket pgbouncer@50001.service
systemctl start pgbouncer@50001.socket pgbouncer@50001.service

or

systemctl enable pgbouncer@50001.socket pgbouncer@50001.service --now

The chosen port number (50001 in this example) should be unique and not used by any other application. Run systemctl daemon-reload after making changes to systemd files for them to take effect.

@linuxmalaysia
Copy link
Author

linuxmalaysia commented Sep 15, 2024

Verify the existence of the PID file.

ls -lisah /var/run/postgresql/pgbouncer-50001.pid

Ensure its ownership and permissions are correct: owner should be postgres, and permissions should allow read access for the owner only (e.
g., -rw-------).

Check if the log file exists at /var/log/postgresql

ls -lisah /var/log/postgresql/pgbouncer-50001.log

Confirm its ownership and permissions are set to postgres with read access only for the owner.

Verify if the PgBouncer process is running with the specific configuration file. This command filters process information and searches for the PgBouncer process with the specified arguments.

ps -ef | grep "/usr/sbin/pgbouncer /etc/pgbouncer/pgbouncer-50001.ini" | grep -v grep

Use systemctl command to obtain the status of both the socket and service for the new instance.

systemctl status pgbouncer@50001.socket pgbouncer@50001.service

To view all running PgBouncer instances

ps -ef | grep pgbouncer | grep -v grep

@linuxmalaysia
Copy link
Author

Creating Additional PgBouncer Instances

To create more PgBouncer instances, simply repeat the steps outlined in the previous section, using a different port number for each instance. Ensure that the chosen port number is unique and not in use by any other application.

Resource Considerations

When adding PgBouncer instances, be mindful of your operating system's virtual CPU (vCPU) count. Avoid exceeding this limit to prevent performance degradation. You can use commands like lcpu or ntop to determine the number of vCPUs available on your system.

@linuxmalaysia
Copy link
Author

linuxmalaysia commented Sep 15, 2024

PgBouncer: A Guide to Efficiently Managing Multiple Instances

To effectively manage multiple PgBouncer instances, follow these steps:

  • Install Prerequisites: Ensure PostgreSQL, PgBouncer, and systemd are installed and configured correctly on your Ubuntu 22.04 or later server.
  • Create Systemd Templates: Create template files for both the socket (/etc/systemd/system/pgbouncer@.socket) and service (/etc/systemd/system/pgbouncer@.service) to define basic settings for each instance.
  • Configure PgBouncer: Create individual configuration files (e.g., pgbouncer-50001.ini, pgbouncer-50002.ini) based on the templates, specifying unique port numbers, log files, and PID files.
  • Enable and Start Instances: Use systemd commands to enable and start the newly created PgBouncer instances.
  • Verify Instances: Check the status of the running instances, including PID files, log files, and process information.

By following these steps, you can effectively optimize your PostgreSQL database's performance and scalability through the use of multiple PgBouncer instances. Detail configuration can be refer to LinuxMalaysia GIST, read all my comments.

https://gist.github.com/linuxmalaysia/0c6287c25957bc1b36af750d4abeb838

https://www.linuxmalaysia.com/2024/09/pgbouncer-guide-to-efficiently-managing.html

Blog post with the help of Google Gemini. Run and verify by human.

This guide base on this articles :-

https://www.2ndquadrant.com/en/blog/running-multiple-pgbouncer-instances-with-systemd/

https://www.enterprisedb.com/postgres-tutorials/pgbouncer-setup-extended-architecture-use-cases-and-leveraging-soreuseport

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment