Foundry
캐시/Redis
기초
핵심

캐시 읽기와 쓰기 전략

Cache-Aside부터 Write-Back까지, 어디에 먼저 쓰는가

캐시 읽기와 쓰기 전략

전략 비교

전략쓰기 경로강점약점
Cache-AsideDB 쓰고 캐시 삭제단순, 캐시 장애 내성첫 요청은 항상 미스
Write-Through캐시와 DB 동시 쓰기캐시가 항상 최신쓰기 지연 증가
Write-Back캐시만 쓰고 나중에 DB쓰기 폭주에 강함캐시 유실 시 데이터 손실
Write-AroundDB만 쓰고 캐시는 건너뜀안 읽는 데이터 낭비 없음쓰기 직후 읽기는 미스

Cache-Aside 읽기 흐름

GET key -> 미스
        -> DB SELECT
        -> SET key value EX ttl
        -> 응답

실무 포인트

  • 대부분의 서비스 기본값은 Cache-Aside. 캐시가 죽어도 DB로 서비스가 유지된다
  • 갱신 시 캐시를 새 값으로 덮기보다 삭제가 안전하다. 동시 갱신에서 옛 값이 덮어쓰는 경합을 피한다
  • Write-Back은 주문과 결제처럼 유실이 치명적인 데이터에는 쓰지 않는다
  • 작성 직후 상세 화면처럼 쓰고 바로 읽는 경로가 있으면 쓰기 시점에 캐시를 채우는 방식을 검토
면접에서 이렇게 나옵니다

Q.Cache-Aside와 Write-Through 중 무엇을 선택하고 왜 그렇게 판단했나요?

대부분 Cache-Aside 를 씁니다. 쓰기 경로가 단순하고 캐시 장애에 강합니다.

항목Cache-AsideWrite-Through
읽기캐시 확인 후 없으면 DB, 그리고 캐시에 채운다같다
쓰기DB 갱신 후 캐시 삭제DB 와 캐시를 함께 갱신
캐시 장애 시DB 로 계속 동작한다쓰기 경로가 함께 막힐 수 있다
첫 조회미스가 난다쓴 값이 이미 캐시에 있다
안 읽는 데이터캐시를 차지하지 않는다써 두었다가 안 읽히면 낭비

Write-Through 가 나은 경우는 쓰고 바로 읽는 패턴이 확실할 때입니다. 방금 쓴 값을 곧 조회하는 화면이면 첫 미스를 없앨 수 있습니다.

흔한 실수: Write-Through 를 정합성이 더 좋은 방식으로 답하는 것. 캐시와 DB 를 함께 쓰는 것은 원자적이지 않아서, 한쪽만 성공하는 창이 여전히 남습니다.

Q.데이터를 갱신할 때 캐시를 새 값으로 덮지 않고 삭제하는 이유는?

동시 쓰기에서 순서가 뒤바뀔 수 있기 때문입니다. 삭제는 여러 번 해도 결과가 같습니다.

요청 X 가 값을 10으로, Y 가 20으로 바꾸고 Y 가 나중이라고 해봅시다.

방식벌어지는 일결과
새 값으로 갱신X 의 캐시 쓰기가 늦게 도착한다DB 는 20, 캐시는 10. 만료까지 어긋난다
삭제두 번 지워도 같다캐시가 비어 다음 조회가 DB 에서 20을 읽는다

삭제가 순서에 둔감하다는 것이 핵심입니다.

그리고 안 읽힐 값을 미리 채우지 않는 이점도 있습니다. 갱신은 잦고 조회는 드문 데이터라면 갱신마다 캐시를 채우는 것이 낭비입니다.

흔한 실수: 삭제가 완벽하다고 보는 것. 조회가 DB 에서 옛 값을 읽은 뒤 삭제가 끼어들고, 그 다음 조회가 옛 값을 캐시에 채우는 좁은 창이 남습니다. 만료 시간을 함께 두어 수렴시킵니다.

Q.Write-Back의 위험은 무엇이고 어떻게 완화하나요?

캐시에만 쓰고 DB 반영을 미루는 방식이라, 캐시가 죽으면 아직 안 내려간 쓰기가 사라집니다.

위험내용
유실캐시 장애 시 미반영 데이터가 없어진다
정합성DB 를 직접 읽는 다른 시스템이 옛 값을 본다
복구 어려움무엇이 반영되지 않았는지 알기 어렵다
완화방법
캐시를 영속화한다로그를 남기는 저장소를 쓴다
복제를 둔다노드 하나가 죽어도 남는다
반영 지연을 짧게유실 범위를 줄인다
유실 가능한 데이터에만 쓴다조회수, 좋아요 수

그래서 실무에서는 잃어도 되는 값에만 씁니다. 게시글 조회수를 캐시에서 올리고 주기적으로 DB 에 반영하는 식입니다. 잔액이나 주문에는 쓰지 않습니다.

흔한 실수: 쓰기 성능만 보고 도입하는 것. 얻는 것은 쓰기 지연 감소이고 내주는 것은 지속성입니다. 그 데이터를 잃어도 되는지가 판단 기준입니다.

Q.캐시 서버가 다운되면 서비스는 어떻게 동작해야 하나요?

DB 로 계속 동작해야 하고, 동시에 DB 가 쓸려나가지 않게 막아야 합니다.

준비내용
캐시 실패를 미스로 처리예외를 던지지 않고 DB 조회로 넘어간다
타임아웃을 짧게캐시 응답을 오래 기다리면 그것이 지연 원인이 된다
DB 보호동시 조회 수 제한, 차단기, 요청 병합
축소 운영무거운 기능을 잠시 끄고 핵심만 유지한다
복구 시 점진 재적재한꺼번에 채우면 DB 가 다시 부하를 받는다

세 번째가 실제 장애의 관건입니다. 히트율 90%로 돌던 서비스가 캐시를 잃으면 DB 부하가 10배가 되어, 캐시 장애가 DB 장애로 번집니다.

흔한 실수: 캐시 조회 실패를 예외로 던져 요청을 실패시키는 것. 캐시는 없어도 동작해야 하는 계층입니다. 그리고 타임아웃을 길게 두면 캐시가 느릴 때 전체 응답이 그만큼 느려집니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

캐시/Redis 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.