pgBouncer connection pooler olarak harika; ancak default yapılandırması bir düşmanlığı kabul ediyor: kullanıcı listenizi manuel olarak userlist.txt’ye yazmak zorundasınız. Her yeni DB kullanıcısı eklediğinizde dosyayı güncellemek, hash’i hesaplamak, pgBouncer’ı reload etmek. Operasyonel bir baş ağrısı.

auth_query bunu çözüyor: pgBouncer authentication için PostgreSQL’in kendisine sorgu atıyor.

auth_user kurulumu

PostgreSQL tarafında düşük yetkili bir kullanıcı ve pg_shadow benzeri bir view oluşturuyoruz:

CREATE ROLE pgbouncer LOGIN PASSWORD 's3cret';

CREATE OR REPLACE FUNCTION pgbouncer.user_lookup(in i_username text,
                                                 out uname text,
                                                 out phash text)
RETURNS record AS $$
BEGIN
    SELECT usename, passwd FROM pg_catalog.pg_shadow
    WHERE usename = i_username INTO uname, phash;
    RETURN;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

REVOKE ALL ON FUNCTION pgbouncer.user_lookup(text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION pgbouncer.user_lookup(text) TO pgbouncer;

SECURITY DEFINER önemli — fonksiyon pg_shadow’a erişim için tanımlayan kullanıcının yetkilerini kullanıyor. Aksi takdirde pgbouncer rolü pg_shadow okuyamaz.

pgBouncer config

pgbouncer.ini:

[databases]
* = host=127.0.0.1 port=5432

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432

auth_type = scram-sha-256
auth_user = pgbouncer
auth_query = SELECT uname, phash FROM pgbouncer.user_lookup($1)

pool_mode = transaction
max_client_conn = 1000
default_pool_size = 25

Artık userlist.txt yok. PostgreSQL’e yeni bir rol oluştursanız, pgBouncer restart’ı gerektirmeden doğrulama çalışıyor.

md5 vs scram-sha-256

PostgreSQL 14+ default olarak scram-sha-256 kullanıyor. pgBouncer 1.18+ bunu tam destekliyor. Eski cluster’larda md5’e düşmek zorunda kalıyorsanız:

auth_type = md5

Ama yeni kurulum yapıyorsanız scram-sha-256 kullanın — md5 artık zayıf.

Pool mode tercihi

Üç mod var, çoğu Laravel/Django uygulaması için tercih:

  • session — bağlantı baştan sona aynı. Prepared statement’lar çalışır, ama pool faydası zayıf.
  • transaction — her transaction sonunda bağlantı serbest. En yaygın tercih. Prepared statement’ları default’ta kullanamazsınız (server-side prepare).
  • statement — her query sonunda. Çoğu ORM ile sorunlu.

Pratik: transaction’la başlayın, sorun yaşarsanız session’a geçin.

Yaygın hata: read-only role’ün password’ü yok

auth_query pg_shadow.passwd’i okuyor. Eğer kullanıcı SSO ile geliyorsa veya peer authentication kullanıyorsa, passwd alanı NULL’dur — pgBouncer login’i reddeder. Bu durumda pg_hba.conf üzerinden trust veya peer kurmak gerekir, ama production’da bunu istemezsiniz.

İzleme

pgBouncer kendi admin DB’sini sağlıyor:

psql -p 6432 pgbouncer -U pgbouncer
> SHOW POOLS;
> SHOW STATS;
> SHOW CLIENTS;

cl_waiting > 0 görüyorsanız default_pool_size’ı arttırmak gerekiyor olabilir. sv_idle çok yüksekse tam tersi — pool overprovision’da.