diff --git a/history/2026-04-16-pgcat-patroni-tcp-keepalive.md b/history/2026-04-16-pgcat-patroni-tcp-keepalive.md new file mode 100644 index 0000000..4071bd1 --- /dev/null +++ b/history/2026-04-16-pgcat-patroni-tcp-keepalive.md @@ -0,0 +1,93 @@ +--- +date: 2026-04-16 +topic: pgcat + Patroni TCP keepalive 적용 (Step 1 옵션 B) +areas: + - infra/postgresql-ha.md +tags: [history, pgcat, patroni, postgresql, tcp-keepalive] +--- + +Patroni multi-host 마이그레이션 원래 Step 1 계획(pgcat Patroni REST API 연동)이 소스 재조사 결과 **pgcat 1.2.0 에 해당 기능 미존재** 판정 → kappa 결정에 따라 옵션 B(HAProxy 구조 유지 + TCP keepalive 추가)로 선회. + +## 배경 + +2026-04-15 19:53 UTC Patroni TL5→6 재선출 후 n8n 이 24h 동안 1038건 "Database connection timed out" 에러. 조사 결과 n8n TypeORM 풀의 단일 소켓이 failover 2분 전 열린 채 7588초간 idle 유지 → pgcat 까지 요청 도달조차 못하는 좀비 상태 (`230ec530-b8a6-406c-9165-35c9eb2d8282` 조사 문서). + +n8n rollout restart 로 즉시 정상화. 재발 방지를 위해 **pgcat 와 Patroni 양쪽에 TCP keepalive 명시 활성화**. + +## 변경 내용 + +### helm-charts (commit `7ebd7e3`) + +`values/pgcat.yaml` `configMaps.pgcat-config.pgcat.toml` `[general]` 섹션: + +```toml +tcp_keepalives_idle = 60 +tcp_keepalives_interval = 10 +tcp_keepalives_count = 3 +``` + +pgcat 1.2.0 에서 실제로 지원하는 정확한 키명 (`pgcat.toml` 예제 파일 및 `src/config.rs` 확인). 서버 소켓에 적용. + +### Patroni (DCS) + +```bash +patronictl -c /etc/patroni.yml edit-config \ + -p tcp_keepalives_idle=60 \ + -p tcp_keepalives_interval=10 \ + -p tcp_keepalives_count=3 --force +patronictl reload nocodb-cluster --force +``` + +3노드 전체 postgresql.conf 에 반영, SIGHUP 으로 적용 (재시작 불필요). 새 TCP 연결부터 keepalive 옵션 적용. + +**주의**: `SHOW tcp_keepalives_idle` 을 unix socket (psql local) 에서 실행하면 0으로 출력. TCP 세션 확인 필수: +```bash +PGPASSWORD=... psql -h 192.168.9.1 -p 5432 -U n8n -d n8n -c "SHOW tcp_keepalives_idle" +# → 60 +``` + +## 검증 — Patroni switchover 재현 테스트 + +**before**: TL6 leader postgres-3 (10.100.1.83) +**action**: `patronictl switchover --leader postgres-3 --candidate postgres-2 --force` +**after**: TL7 leader postgres-2 (10.100.3.185) + +### pgcat → 새 leader 도달 시간 + +``` +T1=22:24:37.696 UTC switchover 커맨드 반환 +t+0002ms pgcat 경유 SELECT → "connection lost" (HAProxy 아직 구 leader 마크) +t+5175ms 여전히 connection lost +t+7331ms 10.100.1.83 응답 (구 leader, 이제 replica — SELECT 는 성공) +t+8461ms 10.100.3.185 응답 (새 leader) +``` + +**write 가능 복구 시간: ~8.5초.** HAProxy `inter 3s fall 3` (9초 감지) 이론치와 일치. keepalive 와 독립 — HAProxy 헬스체크 파라미터가 결정. + +### 애플리케이션 영향 (switchover 전후 ~150초 창) + +| 서비스 | 에러 수 | 타입 | +|---|---|---| +| NocoDB | 1 | "unexpected EOF" 1회 | +| n8n | 9 건 (7초 윈도우) | SocketError/UnexpectedEof, Connection terminated, AllServersDown, Database connection timed out | + +**이전 2026-04-15 failover (1038건, 2시간 지속) 대비 극적 대비.** 좀비 소켓 없음. + +## 롤백 + +- `values/pgcat.yaml` 에서 `tcp_keepalives_*` 3줄 제거 → ArgoCD sync → pgcat rolling restart +- Patroni: `patronictl edit-config` 에서 동일 3개 파라미터 제거 → reload + +## 관측 기간 + +7일 (2026-04-23까지). 다음 Patroni failover 발생 시 app 에러 윈도우 < 10초 지속 여부 확인. 지속 시 원인 재조사. + +## 관련 문서 + +- `infra/postgresql-ha.md` — 「좀비 소켓 방지 — TCP keepalive」 섹션 신설 +- `history/2026-04-16-pgcat-patroni-api-audit-correction.md` — (별도 예정) pgcat Patroni API 미지원 정정, 원 감사 07497dd8 의 PR #944 cite 오류 +- helm-charts commit: https://gitea.inouter.com/kaffa/helm-charts/commit/7ebd7e3 + +## 후속 + +- kappa 지시: **PgPool-II PoC** (이 작업 안정화 후 별도 지시 예정) diff --git a/infra/postgresql-ha.md b/infra/postgresql-ha.md index 26c521c..4ed83c0 100644 --- a/infra/postgresql-ha.md +++ b/infra/postgresql-ha.md @@ -149,7 +149,29 @@ servers = [["192.168.9.1", 5432, "primary"]] pgcat는 풀링 전용으로만 쓰고, leader 탐지는 OpenWrt HAProxy에 위임. `query_parser_enabled = false` 설정 (read/write splitting 비활성). -Patroni failover 인시던트 이력: [[../history/2026-04-08-patroni-failover-incident|2026-04-08 pgcat/nocodb/outline read-only 사고]] +### 좀비 소켓 방지 — TCP keepalive + +Patroni failover 시 pgcat↔backend 및 client↔pgcat TCP 소켓이 반쪽만 끊어진 채 애플리케이션 풀이 계속 붙잡는 현상을 방지하기 위해 양쪽 모두 TCP keepalive 활성화. + +**pgcat (`db/pgcat-config` `[general]`)**: +```toml +tcp_keepalives_idle = 60 +tcp_keepalives_interval = 10 +tcp_keepalives_count = 3 +``` + +**Patroni (`postgresql.parameters` via `patronictl edit-config -p`)**: +``` +tcp_keepalives_idle = 60 +tcp_keepalives_interval = 10 +tcp_keepalives_count = 3 +``` + +동작: 60s idle 후 keepalive probe 전송, 10s 간격으로 3회 재전송 실패 시 커넥션 종료. 최대 감지 시간 **90초**. pgcat 는 서버 측에, Patroni 는 클라이언트(= pgcat 소켓) 측에 각각 설정 — 어느 쪽에서 먼저 죽음을 감지해도 소켓이 정리됨. + +검증: 2026-04-16 switchover 테스트(postgres-3→postgres-2, TL6→7) 기준 n8n 에러 윈도우 7초·9건으로 한정 ([[../history/2026-04-16-pgcat-patroni-tcp-keepalive|history]]). 이전 2026-04-15 19:53 UTC failover 시 1038건과 극적 대비. + +Patroni failover 인시던트 이력: [[../history/2026-04-08-patroni-failover-incident|2026-04-08 pgcat/nocodb/outline read-only 사고]] · [[../history/2026-04-15-pgcat-ha-promotion|2026-04-15 pgcat HA 승격 Step 0]] ## APISIX etcd 사용 현황