PostgreSQL 19

PostgreSQL 논리 복제 슬롯, failover에서 살리는 법 (17 이후 실전 가이드)

논리 복제(logical replication)를 실제 운영에서 굴려본 사람이라면 한 번쯤 겪는다. HA 구성 잘 짜놨고, 프라이머리가 죽어도 스탠바이로 넘어가는 건 문제 없다. 근데 넘어가고 나서 CDC 파이프라인이 조용히 멈춰있다. Debezium 로그를 보면 "replication slot does not exist". 이유는 단순하다 — 복제 슬롯은 프라이머리에만 있었고, 스탠바이가 승격되는 순간 그 슬롯의 커밋 위치 정보가 통째로 증발한 거다.PostgreSQL 17에서 failover slots가 정식으로 들어왔고, 18에서 1년치 버그 패치가 얹혀서 이제 프로덕션에서 쓸만해졌다. 이번 글은 그 세팅을 처음부터 끝까지 밟아보는 실무 가이드다. RDS를 쓰는 팀에게도 해당되는 이야기가 있어서 뒤..

IT/DB 운영 2026.08.09

PgBouncer vs pgcat vs Supavisor, 2026년에 뭘 쓸까

Postgres 커넥션 풀러 얘기다. 15년 넘게 PgBouncer가 사실상 표준이었다. 근데 최근 몇 년 사이에 pgcat(Rust), Supavisor(Elixir) 같은 대안이 부쩍 눈에 띈다. 우리 팀에서도 지난 분기에 새 서비스용 풀러를 뭘로 갈지 논의가 있었고, 실제로 각각을 조금씩 다르게 굴려봤다. 이 글은 그 경험을 바탕으로 세 개를 나열해보는 글이다. "이거 써라"는 아니고, 어떤 상황에서 뭐가 맞더라 정도의 정리.세 개가 각자 어떤 물건인가PgBouncer는 여전히 단일 바이너리에 2MB짜리 프로세스로 커넥션 수천 개를 받아낸다. 트랜잭션 모드 풀링, 심플한 config, 문서화 잘 되어 있고, 튜닝 노하우가 인터넷에 널려있다. 단점은 단일 스레드라는 것. CPU 하나를 다 태우면 그게..

IT/DB 운영 2026.08.06

PgBouncer transaction pool로 갈아탄 다음 날 새벽에 벌어진 일

session pooling에서 transaction pooling으로 갈아탄 지 이틀째 되던 날 새벽 2시 반, 폰이 울렸다. 결제 API의 P99가 800ms를 넘겼다는 알람. 침대에서 노트북을 여는 순간 이미 뭐가 원인인지 짐작이 갔다. prepared statement 다.왜 갈아탔나우리 팀에서 PgBouncer는 오래전부터 session pool로 돌고 있었다. 백엔드가 Django였고, connection이 세션 내내 유지되는 게 편했다. 그런데 최근 서비스가 커지면서 DB 커넥션 수가 감당이 안 됐다. RDS 앞단 PgBouncer에 client는 3천이 넘게 붙는데 server 커넥션은 200~300 정도로 억제하고 싶었다. session pooling에서는 client 한 명이 붙어있는 ..

IT/DB 운영 2026.07.31

idle_in_transaction_session_timeout, 이거 하나로 커넥션 풀이 살아난다

오늘 알게 된 건 아니고 예전부터 알고는 있었는데, 최근에 신규 서비스 튜닝 도우면서 "아 이거 진짜 모르는 팀 아직도 많구나" 싶어서 짧게 남긴다.PostgreSQL 파라미터 중에 idle_in_transaction_session_timeout 라는 게 있다. 이름 그대로 트랜잭션 시작해놓고 아무것도 안 하는 세션을 강제 종료해주는 값이다. 기본값은 0, 즉 비활성이다.왜 이게 문제가 되나전형적인 시나리오는 이렇다.앱에서 BEGIN 날려서 트랜잭션 열어놓고, 그 사이에 외부 API 호출한다. 근데 그 API가 30초쯤 걸린다. 그동안 이 커넥션은 어떤 상태냐면 idle in transaction. 살아는 있는데 아무 일도 안 하고, 그런데 락은 잡고 있을 수도 있다.이런 커넥션이 몇 개 쌓이면 pg_s..

IT/DB 운영 2026.07.16

PostgreSQL 17 autovacuum, 이제 maintenance_work_mem 상한 신경 안 써도 된다

지난주에 팀에서 PG16 → PG17 업그레이드 검증하다가 알게 된 건데, 이거 모르는 분 꽤 많더라. 짧게 하나만 짚고 넘어간다.핵심: 1GB 상한이 사라졌다PG16까지는 autovacuum_work_mem(또는 fallback으로 maintenance_work_mem)이 아무리 커도 실질적으로 1GB 제한이 있었다. dead tuple ID를 저장하는 자료구조가 단순 배열이었고, TIDStore가 아니라 6바이트짜리 ItemPointerData 배열이라 메모리 크기와 상관없이 내부적으로 1GB(정확히는 MaxAllocSize)까지만 쓸 수 있었기 때문이다.이게 뭐가 문제였냐면, 큰 테이블에서 dead tuple이 1GB 배열에 다 안 들어가는 순간 인덱스 vacuum 페이즈가 여러 번 반복된다. 인덱..

IT/DB 운영 2026.07.12

Vault Dynamic Secrets로 PostgreSQL 크리덴셜 관리하기

애플리케이션에 DB 비밀번호를 어떻게 넣어놓고 계셨나요. 우리 팀은 예전에 Kubernetes Secret에 base64로 넣어놓고, 분기마다 수동으로 로테이션했다. 근데 이게 몇 년 이어지다 보니 문제가 쌓였다. 누가 언제 그 시크릿을 봤는지 감사 로그가 없고, 로테이션 날에는 여러 서비스가 동시에 재기동되면서 P99 레이턴시가 튀었다. 결국 Vault Dynamic Secrets로 넘어갔는데, 처음 설정할 때 헤맨 부분이 좀 있어서 정리해둔다.이 글은 PostgreSQL 기준이지만 MySQL이나 MongoDB도 큰 틀은 같다. 최근 Vault 1.19에서 rotation_schedule 필드로 크론 스타일 스케줄이 정식 지원되면서 static role 운용이 훨씬 편해졌다.Dynamic Secrets..

IT/DevSecOps 2026.07.06

session pooling에서 transaction pooling으로 갈아탄 후 3주간 벌어진 일

지난달에 결국 pgbouncer 풀 모드를 session에서 transaction으로 바꿨다. 결과부터 말하면 잘 됐다. 근데 그 3주 동안 두 번은 새벽에 잠에서 깼고, 한 번은 회의 도중에 대시보드 보고 얼굴이 하얘졌다. 기록 삼아 남긴다.왜 갈아탔나우리 서비스는 백엔드 20개 파드가 각각 커넥션 풀 20을 잡는다. 그러니까 idle 상태에서도 Postgres 쪽에는 400개 커넥션이 잡혀 있다는 얘기다. Aurora r6g.2xlarge 기준 max_connections가 900 남짓인데, 스케일 아웃 몇 번 하면 아슬아슬해진다.그동안 pgbouncer를 session pooling으로 쓰고 있었는데, 이건 사실상 아무 이득이 없었다. 클라이언트 커넥션 하나가 백엔드 커넥션 하나를 트랜잭션 단위가 ..

IT/DB 운영 2026.07.05

RDS Proxy 붙였더니 P99가 오히려 늘어난 이야기

지난 주에 스테이지에서 결국 롤백했다. 프로덕션 붙이기 전에 걸러진 게 다행이라면 다행인데, 나흘을 매달렸으니 후련한 기분은 아니다.발단은 흔한 이유였다. 라이더팀 서비스가 시간대별로 커넥션이 폭주하면서 too many connections 로그를 하루에 몇 십건씩 뱉기 시작했다. Aurora PostgreSQL 15, max_connections 200에 라이더 API 파드가 오토스케일링으로 4개에서 20개까지 오가는 상황. HikariCP maximumPoolSize를 낮춰봐도 임계가 애매하게 겹칠 때는 여전히 튕겼다. AWS 문서에서 "RDS Proxy는 이럴 때 붙이면 된다"라고 아주 자신있게 쓰여있길래, 시니어분과 얘기해서 도입 PoC를 시작했다.붙인 순간, 왜인지 느려졌다붙이고 나서 첫 번째 ..

IT/AWS 2026.07.04

PgBouncer transaction vs session 모드, 뭘 쓸까

Postgres 앞에 PgBouncer를 두는 건 거의 관습처럼 되어 있다. 그런데 막상 처음 도입할 때 보면 pool_mode 선택지가 세 개 있고, 그중 실제로 쓰는 건 거의 둘 — transaction과 session이다. 둘 다 써본 입장에서 정리해본다. 어느 쪽이 정답이라기보다, 트레이드오프가 꽤 명확하다.참고로 PgBouncer 1.21 이후 transaction 모드에서도 prepared statements가 지원되기 시작했다. 이게 의외로 선택 기준을 흔든다. 예전에는 ORM/드라이버 호환성 때문에 어쩔 수 없이 session 모드를 골랐던 케이스들이 다시 transaction으로 돌아갈 만한 여지가 생겼다.session 모드 — 가장 안전하지만 풀링 효과가 약하다pool_mode = se..

IT/DB 운영 2026.06.29

autovacuum이 돌고 있는 줄 알았다

autovacuum이 돌고 있는 줄 알았다지난주에 PostgreSQL 디스크가 갑자기 부풀어오르는 사건이 있었다. 정확히는 이미 며칠 전부터 부풀고 있었는데, 우리가 늦게 알아챈 거다.처음에는 단순히 "데이터가 많아져서 그렇겠지" 생각했다. 그런데 dead tuple 비율을 찍어보니 40%를 넘기고 있었다. 어떤 테이블은 60%. 라이브 row보다 죽은 row가 더 많은 상태였다. autovacuum 로그를 뒤져보니 마지막 vacuum이 4일 전에 멈춰 있었다. 그리고 그 사이에 누가 무엇을 했는지 추적이 시작됐다.pg_stat_activity가 말해준 것pg_stat_activity 뷰를 열어보니 한 세션이 4일째 살아 있었다. state는 idle in transaction. xact_start는 월..

IT/DB 운영 2026.06.22