Add a cache — or fix the query?

judgment
상황

상품 상세 API가 느려져서 p95가 1초를 넘기 시작했다. 회의에서 "레디스 캐시 붙이면 되지 않아요?"라는 말이 제일 먼저 나오는 상황.

😴 Boring — Fix the query (EXPLAIN, index, N+1 removal)

언제: 느린 원인이 특정 쿼리 몇 개일 때. EXPLAIN 떠보면 대부분 풀스캔이나 N+1이라서, 인덱스 하나 추가하거나 조인 한 번으로 끝나는 경우가 의외로 많다.

비용: 인덱스가 늘면 쓰기가 약간 느려지고, 쿼리 구조를 바꾸면 코드 리뷰와 배포가 필요하다. 그래도 캐시 무효화 버그를 쫓는 것보다 훨씬 싸다.

✨ Novel — Add a cache layer (Redis read-through + TTL)

언제: 쿼리는 이미 최적인데 같은 결과를 초당 수천 번 읽어서 DB가 눌릴 때. 읽기가 쓰기보다 압도적으로 많고, 몇 초 오래된 데이터를 보여줘도 비즈니스가 괜찮다고 할 때만.

비용: 무효화 로직이라는 새로운 버그 종류가 생긴다. 오래된 데이터, 캐시 스탬피드, 그리고 Redis라는 운영 대상이 하나 늘어난다. "왜 캐시랑 DB가 다르지?"는 디버깅이 제일 오래 걸리는 류의 문제다.

⚖️ 기본 판단

기본은 캐시 말고 쿼리부터 고친다. EXPLAIN으로 원인을 눈으로 확인하고 인덱스와 N+1을 먼저 잡는다. 쿼리가 이미 최적인데도 같은 데이터를 읽는 트래픽이 DB를 누르고 있고, 약간 오래된 데이터를 보여줘도 된다는 합의가 있을 때만 캐시를 단다.

🚨 트립와이어 — 이 신호가 오면 바꾼다
  • 인덱스·N+1 다 잡았는데도 p99가 500ms 위에 머물고, 상위 10개 키 조회가 읽기 QPS의 80% 이상
  • 피크 시간에 DB CPU 80% 초과 + 커넥션 풀 대기 시작 (쿼리 하나 문제가 아니라 총 읽기량 문제라는 신호)
  • 읽기:쓰기 비율이 100:1 이상인데 매 요청이 DB까지 내려가고 있음
  • 트래픽 2~3배 이벤트(세일, 프로모션)가 예정돼 있는데 DB 스케일업으로는 비용이 안 맞음

🔧EXPLAIN ANALYZEpg_stat_statementsRedisGrafana / Datadog APM (p99, DB CPU)

🗣 영어 한 줄 평결

I fix the query first — I only add a cache once it's already optimal and reads still crush the DB.

checking microphone…

⚔️ Defend it — AI 시니어가 반박한다. 영어로 버텨라.

첫 메시지로 네 입장을 영어로 선언해라 — 예: “I'd start with Fix the query here, and only switch when …” 그러면 상대가 반박을 시작한다. 근거·숫자·트립와이어로 받아쳐라.

두어 번은 치고받은 뒤에 채점