분류
트랜잭션·락·DB 운영 · 2쪽
락 대기, 격리 수준, @Transactional 함정, 스키마 변경과 VACUUM 처럼 운영 중인 DB 에서 터지는 문제를 모았어요.
21편 · 마지막 글 2026.08.12
DB 운영 글
21편 중 13–21
대량 DELETE 가 복제를 무너뜨린다
오래된 로그를 정리하려고 천만 행을 한 번에 지웠더니, 복제 지연이 수십 분으로 뛰고 디스크는 오히려 늘었어요. 대량 삭제가 왜 사고가 되는지와 안전하게 나눠 지우는 법을 정리했어요.
서머타임에 배치가 두 번 돌거나 건너뛴다
한국은 서머타임이 없지만, 해외 결제사 리포트를 받는 순간 1년에 두 번 배치가 건너뛰거나 두 번 돌아요. 로컬 시각을 믿으면 생기는 정산 사고와 안전하게 스케줄 잡는 법을 정리했어요.
REPEATABLE READ, MySQL 과 PostgreSQL 은 다르다 — 격리 수준
같은 REPEATABLE READ 인데 MySQL 과 PostgreSQL 에서 동작이 달라요. DB 를 옮기면 코드는 그대로인데 결과가 바뀌는 이유죠. 이름은 같고 보장은 다른 격리 수준을 DB 별로 비교했어요.
운영 중 인덱스 추가 — CREATE INDEX CONCURRENTLY 로 쓰기 막지 않기
운영 중에 인덱스 하나를 추가했더니 몇 분 동안 주문이 안 들어왔어요. 스테이징에선 1초 만에 끝났던 작업이에요. 쓰기를 막지 않고 인덱스를 만드는 방법과 그때 조심할 점을 다뤄요.
pgbouncer transaction 모드가 깨는 prepared statement·SET
커넥션을 아끼려고 pgbouncer 설정 하나를 바꿨더니 앱이 가끔 이상해져요. 다시 보내면 성공해서 재현도 안 되고요. 세션에 걸어 둔 설정이 조용히 사라지는 이유와 피하는 법을 정리했어요.
PostgreSQL 이 쓰기를 거부할 때 — XID wraparound 막기
어느 날 PostgreSQL 이 모든 쓰기를 거부해요. 디스크도 CPU 도 멀쩡한데 DB 가 스스로 문을 닫은 거예요. 이게 왜 일어나는지, 몇 주 전에 미리 알아채려면 무엇을 봐야 하는지 정리했어요.
ALTER TABLE 이 기다리면 뒤에 줄이 선다 — 락 큐와 lock_timeout
1초면 끝나는 컬럼 추가 마이그레이션을 돌렸는데 서비스 전체가 몇 분간 멈췄어요. 마이그레이션은 시작도 못 했는데요. 락을 기다리는 줄이 평범한 조회까지 막는 구조를 풀어 드려요.
MySQL SELECT FOR UPDATE, 인덱스가 없으면 스캔한 행이 전부 잠긴다
재고를 잠그는 쿼리가 개발 DB 에선 멀쩡했는데, 프로모션 날 주문 API 가 통째로 멈춰요. 서로 다른 상품을 산 사람끼리 왜 서로를 기다리는지 풀어 드려요.
MySQL 의 utf8 은 UTF-8 이 아니다
닉네임에 이모지를 넣었더니 500 에러가 나요. 인코딩은 분명 utf8 로 맞췄는데도요. MySQL 의 utf8 이 이름과 달리 진짜 UTF-8 이 아닌 사연과 고치는 순서를 정리했어요.
조건에 맞는 글이 없어요. 브루니가 숨었나 봐요.