date
slug
author
status
tags(최대 3개)
summary
type
thumbnail
category
updatedAt

TL;DR
- 13년 된 모놀리식 위에서 모든 사이트가 DB Writer 하나를 공유하던 구조가, 한 고객의 트래픽·코드·실수를 즉시 전사 장애로 번지게 했습니다.
- 가장 근본적인 카드였던 새로운 DB 전환은 순서를 미루고, 더 빠르게 효과를 내는 기본기(캐싱·쿼리 최적화·DB 부하 분산)를 먼저 골랐습니다. 새로운 DB는 폐기가 아니라, 안전하게 이관하기 위해 지금도 빌드업 중입니다.
- 약 20일동안 TF와 1차 적용을 거치며 RUM TTFB −22.16%(TF 기간 누적, exact permutation test, p<0.0001), 적용 직후 **Aurora Writer 연결 피크 −65~75%·위젯 쿼리 약 −90%**를 확인했습니다.
- 같은 측정 체계 구간에서 위험급 장애 빈도 30%, MTTR 30%로 줄었고, 탐지는 고객이 먼저 발견한 데서 시스템이 먼저 탐지하는 쪽으로 바뀌었습니다.
- 아쉬웠던 대응 두 건도 있었습니다. 위험도는 낮았지만 그 회고까지 정직하게 담았습니다.
측정되지 않는 위험 위에 있었습니다
관측성(Observability)을 살펴봤습니다. 모니터는 있지만, 애플리케이션 로그 수집 체계는 미비했습니다. 장애를 시스템이 아니라 고객과 CX가 먼저 발견하는 구조였습니다.
문제를 미리 파악하지 못한 이유는 단순합니다. 위험을 감지할 눈이 없었습니다.
2026년 4월, 전사 장애가 2건이나 발생했습니다. 모든 사이트가 DB Writer 하나를 공유하는 구조였습니다. ProxySQL 동기화 문제, Aurora Writer 포화, 단일 고객의 JS amplification 등 원인은 달랐지만 뿌리는 같았습니다.
이 구조에서는 한 고객의 트래픽·코드·실수가 즉시 전사로 번집니다. 모니터링과 온콜로 완화는 할 수 있어도 제거하려면 구조 자체를 바꿔야 합니다. 문제는 그 작업을 라이브 서비스를 멈추지 않은 채로 해야했습니다.

가장 화려한 카드를 뽑으려다, 기본기를 먼저 골랐습니다
구조를 바꾸는 가장 근본적인 카드는 DB를 고객 단위로 분리하는 것이었고, 그 연장선에 새로운 DB(분산형 데이터베이스)로의 전환이 있었습니다. Writer 단일 병목 자체를 없애는 그림은 매력적이었습니다.
다만 새로운 DB로 옮기려면 새 DB를 세우고, 데이터를 실시간으로 동기화한 뒤, 짧은 점검 시간에 한 번에 전환해야 합니다. 기본기는 라이브 서비스에 그대로 얹을 수 있었지만, 이 전환은 아무리 잘해도 짧은 점검과 롤백 준비가 필요했습니다. 이행 난이도가 가장 높았습니다.
반면 더 빠르게 효과를 내는 방법이 있었습니다. 이번 TF에서 아래 세 가지를 점검했습니다.
- DB 조회 자체를 줄이기 — 위젯·통화·버전 등 반복 조회를 캐싱·memoize로
- 쿼리를 가볍게 — 상품 상세의 N+1과 서브쿼리를 묶음·리터럴로
- 부하를 분산하기 — 단일 인스턴스에 몰린 Writer 연결을 재배치
새로운 DB라는 화려한 카드보다 기본기가 먼저였습니다. DB 조회와 부하를 먼저 줄여 두면 새로운 DB 전환의 긴급도도 내려갑니다. 이 판단이 순서를 미룬 결정의 핵심이었습니다.
그래서 우선순위를 명확히 적습니다. 새로운 DB 전환은 폐기가 아니라 순서를 미룬 것입니다. 선행 조건(캐싱·쿼리 최적화·ProxySQL 검증·스테이징)을 먼저 끝내기로 했고, 새로운 DB 이관 자체는 1차 안정화 이후 안전하게 진행하기 위해 지금도 빌드업하고 있습니다.

새로운 DB를 미루고 주말에 한 일
TF를 띄웠고, 2주 뒤 새벽에 1차 적용했습니다.
인프라팀과 함께 CTO 형섭님,백엔드 경연님, 프론트엔드 덕성님, 파운데이션팀 무원님이 설계하고 배포했습니다. QA팀은 품질과 테스트를 맡았고, 여러 스쿼드가 필요할 때마다 테스트를 함께 돌렸습니다. 어느 항목도 한 팀 단독으로 끝나지 않는다는 원칙이 이 주말에 그대로 작동한 셈입니다.
실제로 바꾼 것은 다음과 같습니다.
- Aurora MySQL ZDP(Zero Downtime Patching) 업그레이드 + Reader 재배치(4→3, 연결 재분배)
- Redis 6 → Valkey 9 전환 (메이저 버전을 단번에 끌어올린 과감한 업그레이드)
- 위젯·인라인 위젯 read-through 캐싱(TTL 1시간) 도입
- N+1 쿼리 제거(상품 상세 22개) + 서브쿼리를 애플리케이션 리터럴로 치환
- 통화·버전 등 hot path의 memoize(요청당 1회로 축소)
특히 Redis 6 → Valkey 9 메이저 업그레이드는 AWS 본사에서 ElastiCache를 담당하던 전문 엔지니어 승민 님이 리드했습니다. 캐시 엔진을 운영하던 사람이 직접 설계했기에, 큰 폭의 버전 점프를 무중단에 준하는 전환으로 끝낼 수 있었습니다.





결과는 측정 조건과 함께, 검증한 것만 적습니다.
지표는 두 결로 나뉩니다. 체감 속도(RUM·nginx)는 2주간의 TF에서 점진 배포가 누적된 결과이고, Aurora·캐시의 큰 계단식 변화는 1차 적용 직후 나타났습니다.
Aurora Writer 부하
PRE는 7일 간 baseline, POST는 1차 적용 직후 구간입니다.
- Writer 연결 수 피크: −65~75% (한 고객의 부하가 Writer 연결을 끌어올리던 폭이 줄었습니다)
- 위젯·인라인 위젯 쿼리: 약 −90% (캐싱으로 SELECT가 Writer에 닿기 전에 빠집니다)
CPU와 메모리 사용률도 비교할 수 있지만 핵심 지표로 두지 않았습니다. 전사 장애의 원인은 CPU나 메모리 부하가 아니라 Writer 커넥션 부하였기 때문입니다.

배포 직후의 변화는 더 분명했습니다.


TapPay 로드 차단 배포 직후 Writer 연결 1분 피크 −90%·평균 −15%, 위젯·인라인 위젯 캐싱 배포 직후 SELECT 약 −20%를 확인했습니다.
추세도 모두 같은 방향이었습니다(PRE→POST 실측).




ElastiCache
동일 구간 평균입니다.
- GetCommands/s: 4,995 → 2,186 (−56.2%)
- CacheHits/s: 3,320 → 1,321 (−60.2%)
- EngineCPU: 6.52% → 4.66% (−28.5%)

요청당 캐시 조회 자체가 줄며 연결 압력이 크게 내려갔습니다.



체감 속도 (RUM, brand-site)
PRE 16평일 vs POST 13평일, 양측 exact permutation test입니다.
- TTFB 평균: 815.6ms → 634.8ms (−22.16%, p<0.0001)
- FCP 평균: 1,167.6ms → 953.0ms (−18.38%, p<0.0001)
- LCP 평균: 1,273.1ms → 1,093.5ms (−14.11%, p<0.0001)
VIP 커머스 사이트 (서버 nginx request_time, 13평일 비교)
- A사: 660ms → 466ms (−29.39%, p=0.0022)
- B사: 692.7ms → 554.2ms (−20.0%, p=0.0154)
한 고객이 전사를 흔들던 구조의 압력은 TF를 거쳐 1차 적용에서 가장 크게 내려갔습니다.

숫자로 증명하는 안정성: SLI·SLO·SLA
좋아졌다는 느낌만으로는 신뢰받지 못합니다. 그래서 안정성 자체를 지표로 봅니다.
- SLI: 지금 얼마나 잘 되고 있나 — 가용성·에러율·P95 응답·MTTR
- SLO: 우리가 세운 기준 — 가용성 99.95%, P95 500ms, MTTR 30분
- SLA: 고객에게 약속하는 선 — SLO보다 여유 있게
이 지표는 매일 09:00 KST에 도는 크론잡이 ALB·Datadog·장애 채널을 모아 자동 산출하고, Error Budget과 Burn Rate(Google SRE Workbook 방식)까지 계산해 사내 노션에 기록합니다.



같은 측정 체계로 비교 가능한 구간만 보면 이렇습니다.
- 위험급 장애 빈도: 2025년 4분기 6건 → 2026년 1~4월 2건 (분기 평균 1/3)
- MTTR(전사 위험급): 1시간 이상 → 23~35분
- 탐지 주체: 고객·CX가 먼저 발견 → 시스템이 먼저 탐지하고 자동 분석

이 변화의 토대는 모든 데이터(로그·APM·메트릭)를 Datadog으로 일원화한 것이었습니다. 그 위에 장애를 P1~P4로 나누고, 등급별 알람과 온콜 프로세스를 세우고, 포스트모템으로 재발을 막았습니다.
장애 하나가 시스템 하나를 남기는 식이었습니다. 입사 초기 겪었던 WAF 룰셋 변경 장애는 네트워크·인프라 변경은 잠수함 패치 대신 전사 공지 후 모니터링으로 확인한다는 변경관리 프로세스를 낳았습니다. 컨테이너 이미지가 삭제되며 로그인 페이지가 멈춘 장애는 그날 오후 포스트모템으로 이어져 재발 항목을 못 박았습니다. 그 결과 같은 유형의 장애는 더 이상 반복되지 않았고, 매번 유형이 다른 장애만 남았습니다.
인프라팀의 기조는 ‘무소식이 희소식’
좋은 인프라는 티가 나지 않습니다. 고객이 인프라의 존재를 느끼지 못하는 상태가 좋은 상태입니다. 인프라팀의 슬로건이 무소식이 희소식인 이유입니다.
초기에는 그 무소식을 사람이 만들었습니다. 회사 근처 오피스텔에서 노트북을 곁에 두고 지냈고, 결혼식장에서 휴대폰으로 장애를 확인했습니다. 그날 장애는 온콜이 1차에서 2차로 자동 에스컬레이션됐고, 자동화가 20분 안에 정상 동작을 확인했습니다.

한 사람이 깨어 있어 막는 방식은 지속되지 않습니다. 그래서 같은 일을 자동화와 프로세스로 옮겼습니다. 이벤트 대응 자동화, 등급별 알람, 온콜, 포스트모템입니다. 2026년 1월부터 장애 빈도가 줄어든 이유는 사람이 하던 탐지와 1차 대응을 시스템이 맡았기 때문입니다.
탐지는 됐지만 복구가 늦은 새벽 장애
쉬운 문제라고 말할 수 없습니다. 13년간 한 줄씩 쌓인 결정 위에서, 라이브 트래픽을 끊지 않고 기반을 바꾸는 일은 어느 항목도 한 팀 단독으로 끝나지 않았습니다.
그 주말에도 새벽에 아쉬운 대응 두 건이 있었습니다. 둘 다 서비스 위험도가 높은 장애는 아니었고, 공통점은 발생 시각이었습니다.
- 새벽 배치 작업 지연: 배포 자동화 스크립트가 백그라운드 데몬을 의도치 않게 함께 종료시키며 일부 배치 작업이 멈췄습니다. 위험도는 낮았지만 새벽 시간대라 인지와 복구에 시간이 걸렸습니다.
- DB 패치 직후 일시적 연결 이슈: 패치로 커넥션이 재설정되는 짧은 구간에서 일부 서비스의 연결 풀이 잠시 stale 상태로 남았습니다. 시스템은 이를 감지했지만, 담당자가 잠든 새벽이라 사람 손이 닿기까지 시간이 걸렸습니다.
핵심 교훈은 탐지는 시스템이 했지만, 새벽의 사람 공백을 자동 조치로 메워야 한다는 것이었습니다. 두 건 모두 포스트모템으로 후속 항목을 정리했습니다.
- 배치 재시작 절차를 코드로 고정(데몬 detach 의무화), DB 컷 작업 후 전 구간 능동 검증 체크리스트화
- ProxySQL 벤치마크 → 스테이징 검증 → 그다음에 새로운 DB 사전 검증
- baseline 데이터 별도 아카이빙(측정 retention 만료로 비교 표본이 줄어든 문제)
안정화는 결국 모두의 일을 풀어줍니다
인프라 안정화는 인프라팀만의 성과로 끝나지 않습니다. 서비스가 안정적일수록 다른 팀의 일이 같이 풀립니다.
- 세일즈는 결제 순간에 터지지 않는 서버를 근거로 더 많은 고객을 확보합니다.
- 마케팅은 부정 이슈에 발목 잡히지 않고 더 공격적으로 움직입니다.
- CX는 장애 VOC 인입이 줄어 진짜 고객 경험에 시간을 씁니다.
- AM은 이탈을 고민하던 브랜드의 신뢰를 회복합니다.
- 데이터팀은 더 많은 고객 데이터를 더 안정적으로 다룹니다.
마무리: 8개월이 남긴 한 문장
가장 화려한 카드를 먼저 꺼내는 것이 항상 정답은 아닙니다. 회사가 처한 상황에 맞는 기술과 순서가 있고, 그걸 데이터로 판단하는 것이 엔지니어링이라고 배운 8개월이었습니다. 새로운 DB는 버린 카드가 아니라 순서를 미룬 카드이며 지금도 안전한 이관을 위해 빌드업하고 있습니다.
위험 위에 앉아 있던 인프라는 이제 그 위험의 위치를 데이터로 봅니다.
김용현 Infra Team Lead
아임웹에서 인프라팀 리드를 맡고 있습니다.
’무소식이 희소식’을 데이터로 만드는 일을 합니다.
