SMALL

DB운영 9

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

pgbouncer transaction mode에서 prepared statement 깨진 새벽 사건

지난주 새벽에 또 깼다. 4시쯤 핸드폰이 미친 듯이 울리는데, 화면을 보니 prepared statement "S_42" does not exist 에러가 분당 수천 건씩 쌓이고 있었다. 결제 API 쪽이었는데, 그날따라 더 짜증났던 건 — 두 시간 전에 내가 직접 머지한 PR 때문이라는 게 거의 확실했기 때문이다.결론부터 말하면 pgbouncer transaction pooling 모드 + 새 JDBC 드라이버 조합이 문제였다. 근데 거기까지 가는 과정이 정말 길었다.새벽 4시, 일단 롤백부터운영 룰은 단순하다. 새벽에 깨면 일단 의심되는 배포부터 롤백. 두 시간 전 머지한 PR이 두 개 있었다 — 하나는 pgbouncer 버전 업(1.18 → 1.23), 다른 하나는 백엔드 서비스의 PostgreSQ..

IT/DB 운영 2026.06.17

PgBouncer transaction mode에 prepared statement 켰다가 새벽에 깬 이야기

지난주 일요일 새벽 2시쯤 알림이 왔다. 결제 API 쪽에서 prepared statement "S_3" does not exist 에러가 분당 수백 건씩 찍히고 있었다. 그 전날 PgBouncer를 1.25.1로 올린 게 화근이었다. 안 그래도 PG16.11에 PgBouncer 1.25.1 조합에서 prepared statement 관련 버그 리포트가 올라온 게 있었는데, 우리도 그 케이스에 정확히 걸려든 거였다.이번 글은 그날 새벽 내가 뭘 보고 뭘 했고, 최종적으로 어떻게 마무리됐는지에 대한 기록이다. 깔끔한 해결책 같은 건 아직 없다. 워크어라운드로 일단 막아둔 상태.배경: 왜 transaction mode + prepared statement를 켰나작년에 우리 팀은 PgBouncer를 1.21로..

IT/DB 운영 2026.05.25

Aurora PostgreSQL 14 → 16 Blue/Green 업그레이드에서 삽질한 새벽 이야기

지난주 화요일 새벽 2시, 메이저 버전 업그레이드를 한다고 멘션이 와있었고 나는 콘솔 앞에 있었다. 사전 리허설은 두 번 했다. 스위치오버 30초, 길어야 1분. 그런데 실제 작업은 7분 걸렸다. 7분이라는 숫자 자체보다, 그 7분 동안 회사 메인 서비스의 결제 API가 절반쯤 죽어있었다는 게 문제였다.이 글은 그날 무슨 일이 있었는지, 그리고 다음에 같은 작업을 또 한다면 뭘 다르게 할지에 대한 기록이다. AWS 공식 문서나 베스트 프랙티스 글들이 말하지 않는 것들이 좀 있더라.시작은 평범했다대상은 Aurora PostgreSQL 14.10 클러스터다. 14가 2026년 11월에 standard support가 끝난다는 공지가 작년 말에 나왔고, 우리는 6월 안에 16으로 올리기로 했다. 17이 아니라..

IT/DB 운영 2026.05.20

Redis Cluster slot migration 중에 P99이 4초까지 튄 새벽

지난주 화요일 새벽 2시 47분알림이 울렸다. 캐시 레이어 P99가 평소 8ms 수준에서 4초까지 튀었다는 것이다. 멘탈이 나갔다. 침대에서 노트북을 펴는데 손이 약간 떨렸다.원인은 Redis Cluster slot resharding이었다. 평소처럼 야간 저트래픽 시간대에 노드 두 대를 추가하고 슬롯을 옮기는 작업이 돌아가고 있었는데, 이게 그냥 평범하게 끝나지 않았다. 몇 시간 동안 로그와 메트릭을 뒤지면서 알게 된 것들을 정리해둔다.우리 환경24노드 Redis Cluster (마스터 12, 레플리카 12). EKS 위에서 StatefulSet으로 운영 중이고, 키 수는 약 1.2억개, 메모리는 노드당 평균 28GB. 샤드 수가 늘어 일부 노드가 메모리 한계에 다다라서 노드를 추가하기로 했다. 새 노..

IT/DB 운영 2026.05.07

pg_stat_io로 새벽 3시에 vacuum I/O 폭탄 잡은 이야기

지난주 화요일 새벽 3시, 슬랙 알림이 미친 듯이 울렸다. 결제 DB의 P99 레이턴시가 평소 12ms에서 280ms로 튀어 올랐다. 폰을 더듬어 잡고 일어나면서 머리가 멍했다. 트래픽은 한산한 시간대인데 왜?처음엔 단순한 락 경합인 줄 알았다. pg_stat_activity 봤는데 long-running 쿼리도 없고, pg_locks도 깨끗했다. 근데 디스크 IOPS는 평소 대비 4배. 뭔가 백그라운드에서 디스크를 갈아먹고 있는 게 분명한데 보이질 않았다. 멘탈이 살짝 나갔다.pg_stat_io를 켰다작년에 PG16으로 올리면서 pg_stat_io 뷰를 알게 됐었는데, 평상시엔 잘 안 보던 거였다. 이번 같은 상황에서 진가를 발휘하는 뷰다. context 컬럼에 bulkread, bulkwrite, v..

IT/DB 운영 2026.05.01

PgBouncer transaction 모드에서 prepared statement 제대로 쓰는 법

왜 굳이 켜야 하나PgBouncer 1.21에서 transaction pooling 모드에서도 prepared statement를 쓸 수 있게 된 게 벌써 2년 가까이 됐다. 우리 팀도 작년 가을에 1.22로 올리고 max_prepared_statements를 켰는데, 그동안 마주친 함정 몇 개가 있어서 정리해둔다. 비슷한 마이그레이션을 앞두고 있는 분들에게 도움이 됐으면 한다.이 글은 "PgBouncer는 뭔가요"부터 시작하지 않는다. 이미 transaction 모드로 PgBouncer를 운영 중이고, 애플리케이션이 prepared statement를 쓰고 있거나 쓰고 싶은 상황을 가정한다.JDBC, asyncpg, pgx, psycopg3 같은 모던 드라이버는 기본적으로 Parse/Bind/Execu..

IT/DB 운영 2026.04.29

PostgreSQL 16 → 17 메이저 업그레이드, replication slot 살리려다 새벽을 태운 이야기

지난주 새벽에 우리 팀 메인 OLTP 클러스터를 PG 16.4에서 17.4로 올렸다. 사실 이 업그레이드는 한 달 전부터 일정에 잡혀 있었고, 나는 자신이 있었다. 17부터는 pg_upgrade가 logical replication slot을 살려준다는 그 기능 때문이었다. 16까지는 메이저 올릴 때마다 슬롯을 다 날리고, subscriber 쪽에서 다시 풀 싱크를 떠야 했는데 그게 진짜 끔찍했었다. 우리는 분석계로 빠지는 publication이 4개 있었고, 가장 큰 테이블이 압축 후 1.2TB짜리라 풀 싱크 한 번 뜨면 6시간이 그냥 사라졌다.근데 그 자신감이 새벽 3시 17분에 박살 났다. 정확히 어디서 박살났는지, 그리고 다음에 같은 작업을 하는 분들이 같은 데서 안 깨지길 바라는 마음으로 적어둔..

IT/DB 운영 2026.04.26
BIG