Skip to content

feat: pgbouncer (session) przed PostgreSQL dla appservera - #35

Merged
mpasternak merged 9 commits into
mainfrom
feat/pgbouncer
Sep 27, 2026
Merged

mpasternak merged 9 commits into
mainfrom
feat/pgbouncer

Conversation

@mpasternak

Copy link
Copy Markdown
Member

Po co

Django w appserverze (CONN_MAX_AGE=0, ASGI) otwiera nowe połączenie z PostgreSQL przy każdym żądaniu. Pomiar na publikacje.up.lublin.pl (27.09.2026, z kontenera appservera, mediany z 30 prób): połączenie 18 ms + pierwsze zapytanie na świeżym procesie 9,7 ms (zimny cache katalogu) vs 1,5 ms na rozgrzanym — przy medianie całego żądania 100 ms.

pgbouncer w trybie session trzyma gotowe, rozgrzane procesy bazy. Znika fork backendu i zimny cache; zostaje tańsze logowanie SCRAM do samego pgbouncera. Szacunek: connect + pierwsze zapytanie z ~28 ms do rzędu 3–8 ms — do potwierdzenia pomiarem po wdrożeniu (kryterium: ≥ 3× szybciej, mediana request_time nie rośnie).

To nie jest ochrona przed floodem (tę daje #34 + iplweb/bpp#833).

Co się zmienia

  • nowa usługa pgbouncer (docker-compose.pgbouncer.yml, edoburu/pgbouncer:v1.25.2-p0) z własnym skryptem startowym pgbouncer/entrypoint.sh — obrazowy wpisuje hasło bez escapowania ("/% psują logowanie)
  • tylko appserver przez pulę (DJANGO_BPP_DB_HOST: ${BPP_APPSERVER_DB_HOST:-pgbouncer}, port 6432); authserver, Celery, denorm-queue (LISTEN), netdata, backup — bezpośrednio jak dotąd
  • ta sama konfiguracja dla dbserver i bazy zewnętrznej — pgbouncer łączy się z DJANGO_BPP_DB_HOST/_PORT
  • pool_mode = session na sztywno (transaction łamie WITH HOLD cursory Django, LISTEN, SET)
  • to samo konto co dziś (auth_file z .env), zero migracji .env, domyślnie włączone
  • appserver → pgbouncer service_healthy, jak do dbserver
  • sonda przez osobny wpis <baza>_health z pool_size=1 — nie robi się unhealthy pod pełną pulą
  • pula 80, przycinana przy starcie do max_connections − max(40, 20 + 0,75×rdzenie) z ostrzeżeniem; query_wait_timeout=15, max_client_conn=1000, ulimits.nofile=4096, logowanie połączeń wyłączone, SHOW POOLS przez stats_users
  • make configure-resources zna pgbouncera; docs: nowa docs/konfiguracja/pgbouncer.md + usługi, limity, healthchecki, komendy, CLAUDE.md

Spec: docs/superpowers/specs/2026-09-27-pgbouncer-design.md (2 rundy review) · Plan: docs/superpowers/plans/2026-09-27-pgbouncer.md

Testy (lokalnie)

  • nowy make test-pgbouncer (prawdziwy PostgreSQL 18 + nasz skrypt): 25/25 — hasło p"a%s$ w\x, izolacja i reset sesji między klientami, ten sam proces bazy dla kolejnych połączeń, sonda przy pełnej puli, przycięcie przy max_connections=50, baza niedostępna przy starcie, brak wymaganej zmiennej. 4/4 mutacje wykryte (brak escapowania, transaction, pusty server_reset_query, sonda przez główną pulę). W CI obok test-nginx-limits.
  • tests/test_makefile.sh: 295 pass; nowy test na wyrenderowanym docker compose config ze starym .env (tylko appserver przez pulę, reszta bezpośrednio — mutacja netdata→pgbouncer wykryta). 1 FAIL tylko lokalnie (pozostałość w moim repo-lokalnym .env), nie na CI.
  • test-waf 82/82, test-nginx-limits zielony, shellcheck czysty, mkdocs build --strict OK
  • końcowe review całego brancha: 0 Critical, 1 Important (limit deskryptorów zależny od daemona — naprawione ulimits), docs-sync poprawione

Po merge'u, przed wdrożeniem na publikacje.up.lublin.pl

Posprzątać zdublowane DJANGO_BPP_DB_* w tamtejszym .env; pomiar przed/po.

🤖 Generated with Claude Code

mpasternak and others added 9 commits September 27, 2026 19:46
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… logi)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er; poprawki z 2. review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…puli) + test na zywo

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…thy), testy statyczne + CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y w CLAUDE.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s timeout, netdata w tescie, docs

- ulimits.nofile 4096 w compose: domyslny soft limit zalezy od daemona
  (czesto 1024), a pgbouncer przy max_client_conn=1000 potrzebuje ~1174
- test-pgbouncer: z_limitem (bash) zamiast timeout — na stockowym macOS brak
  timeout dawal falszywe OK w 7b i falszywy BLAD w 7
- test statyczny: netdata na liscie serwisow laczacych sie bezposrednio
- docs: komentarz trybu bazy zewnetrznej, healthcheck pgbouncera,
  PGBOUNCER_CPU_LIMIT nie jest liczony przez configure-resources

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mpasternak
mpasternak merged commit 3bc05f6 into main Sep 27, 2026
7 checks passed
@mpasternak
mpasternak deleted the feat/pgbouncer branch September 27, 2026 22:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant