사례3건
3건 중 1~3번째
- 증상
2025년 1월 21일 23시 UTC쯤, 보관 데이터를 담는 데이터베이스 인스턴스의 남은 저장 공간이 거의 없다는 자동 알림이 울렸다. 23시 26분부터 워크플로 대기열이 늘면서 워크플로와 잡의 시작과 취소가 느려지고 UI에서 워크플로를 보기 어려워졌다.
- 촉발
1월 16일에 보관 데이터베이스의 함수 하나를 고친 코드 변경이 의도치 않게 로그 메시지를 지나치게 많이 만들어 냈다.
- 원인
- 구성 요소
- 기여 요인
- 감지
23시쯤 보관 데이터베이스의 남은 저장 공간이 거의 없다는 자동 알림이 울렸다. 같은 시각에 요청량 알림이 따로 울려 팀은 워크플로 지연을 곧바로 이 문제와 연결하지 못했다. 그 알림이 해결된 뒤에도 대기열이 늘자 다른 팀이 조사에 나섰다.
- 조치
- 23시 44분에 워크플로 대기열을 처리하는 이벤트 소비자를 증설했다.
- 23시 55분에 문제가 난 보관 데이터베이스의 읽기 복제본을 독립된 주 인스턴스로 승격했다.
- 후속 조치
- 로그 메시지를 지나치게 많이 만들던 데이터베이스 함수를 고쳤다.
- 워크플로 보관 호출의 재시도 정책에 최대 지속 시간을 두어 기본 타임아웃보다 일찍 실패하게 하고, 보관 서비스에 문제가 생겨도 워크플로 서비스가 받는 영향을 줄인다.
- 장기적으로 워크플로 보관 과정을 이벤트 기반 방식으로 바꿔 두 서비스를 떼어 놓는다.
- 데이터베이스에 예측 모니터링과 이상 탐지 모니터링을 더해, 이상한 움직임이 위험 수준에 닿기 전에 알림을 받는다.
- 교훈
보관 데이터베이스의 문제를 알리는 알림은 울렸지만, 데이터베이스가 예측보다 훨씬 빨리 차서 고객 영향이 나기 전에 대응할 시간이 거의 없었다. 워크플로 서비스가 보관 서비스를 동기로 호출하기 때문에 보관 쪽 문제가 워크플로 전체의 지연으로 번졌다.
- 증상
처리되지 않은 잡이 밀리는지 감시하던 DataDog 에서 알림이 울렸다. 대량의 잡이 처리되지 못하고 쌓여 있었다.
- 촉발
Redash 에서 reader 인스턴스로 보내야 할 데이터 분석용 쿼리가, 데이터 소스 등록 때 잘못 설정한 클러스터 엔드포인트를 거쳐 writer 인스턴스에서 오래 실행됐다.
- 원인
- 구성 요소
- 기여 요인
- 감지
처리되지 않은 잡이 밀리는지 감시하던 DataDog 알림이 대량의 잡이 쌓였을 때 울렸다.
- 조치
- Redash 의 데이터 소스 설정 실수를 고쳐 reader 엔드포인트를 가리키게 했다.
- VACUUM 을 막는 쿼리라고 확신한 뒤 pg_terminate_backend 로 그 쿼리의 프로세스를 강제로 끝냈다.
- 프로세스가 끝난 것을 확인하고 VACUUM 을 다시 수동으로 실행해 dead tuples 를 대량으로 치웠다.
- 후속 조치
- Redash 컨테이너의 /etc/hosts 에서 writer 엔드포인트 호스트 이름을 테스트용 무효 주소인 TEST-NET-1 의 IP 주소로 지정해, Redash 에 writer 엔드포인트를 잘못 설정해도 실제로는 접속하지 못하게 한다.
- PostgreSQL 사용자의 statement_timeout 을 알맞게 설정해 오래 걸리는 쿼리를 자동으로 멈춰 재발을 막는다.
- 늘어날 잡을 견디도록 qg 를 개선하거나, SELECT FOR UPDATE SKIP LOCKED 로 락을 잡는 river 같은 기술을 쓰는 것을 검토한다.
- 교훈
que_jobs 와 전혀 관계없는 쿼리라도 같은 DB 인스턴스에서 오래 실행되면 que_jobs 의 dead tuples 를 치우지 못하게 막아 테이블이 계속 커지고, qg 의 디큐 성능 저하와 DB 부하 상승으로 이어진다. 글쓴이는 이것을 오래 걸리는 쿼리 때문에 VACUUM 이 효과를 내지 못하는 PostgreSQL 운영의 전형적인 경우로 보았다. 이런 상황에서 어디를 확인해야 하는지를 정해 두고 습관으로 만들어야 한다고 느꼈다. 현재 qg 가 쓰는 advisory lock 과 Recursive CTE 는 dead tuples 의 영향을 받기 쉬운 설계다.
- 증상
5월 11일 05:45 UTC쯤 데이터베이스 커넥션 풀이 가득 찼고, 모니터링이 이를 곧바로 감지해 05:46 UTC에 엔지니어를 호출했다. 많은 고객이 replicate.com 웹사이트와 API에서 느린 응답이나 HTTP 500 오류를 받았고, 예측 작업을 제대로 실행하지 못했다.
- 촉발
5월 9일과 10일에 기능 플래그로 넓게 켠 비동기 예측 상태 업데이트 기능이 같은 예측 ID로 INSERT 쿼리를 동시에 보내기 시작했다. 5월 11일 05:00 UTC가 조금 지나 평소 수준의 트래픽 변동이 이 불안정한 상태를 무너뜨렸다.
- 원인
- 구성 요소
- 기여 요인
- 감지
05:45 UTC쯤 데이터베이스 커넥션 풀이 가득 차자 모니터링 시스템이 거의 곧바로 이를 감지해 05:46 UTC에 엔지니어를 호출했다.
- 조치
- 07:31 UTC에 기능 플래그로 비동기 예측 업데이트 기능을 모두 껐다. 몇 분 안에 데이터베이스가 회복했고 서비스가 정상으로 돌아왔다.
- 후속 조치
- 비동기 예측 업데이트 기능을 꺼 둔 채로, 같은 예측 ID에 INSERT가 쌓이지 않도록 다시 설계한다.
- 방치하면 비슷한 문제를 일으킬 수 있는 잠금 경합과 그 밖의 데이터베이스 부하 집중 지점을 점검한다.
- 큰 장애가 나면 무슨 일이 있었고 무엇을 고치는지 담은 자세한 보고서를 공개한다.
- 교훈
Replicate는 이 장애에 복잡한 시스템 장애의 전형적인 특징이 있다고 보았다. 시스템은 성능이 떨어진 채로도 겉으로는 잘 돌다가 어느 순간 크게 무너졌다. 장애를 촉발한 방어 장치가 같은 장애를 일부 막아 주기도 했다. 변경은 새 위험을 만들지만 위험을 없애는 것도 변경이다. 한 가지를 빠르게 만든 성능 개선이 다른 곳을 훨씬 나쁘게 만들 수 있다.
이 3건에서 가장 많이 나오는 구성 요소: 데이터베이스, PostgreSQL vacuum. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.