티스토리 뷰

 

 

어떤 캐시를 사용할 지 고민하는 개발자

 

 

안녕하세요. 상품 조회에 캐시를 붙이면서 캐시를 사용할 수 있는 기회가 생겼습니다!

캐시에는 여러가지가 있겠지만 이번 글에서는 로컬캐시와 글로벌 캐시만 다뤄보도록 하겠습니다.

 

보통 통상적으로 캐시! 라고하면 글로벌 캐시인 "Redis"를 떠올리기 마련입니다. 하지만 로컬 캐시도 있다는 사실 알고 계셨나요 ?

 

그래서 단순히 읽기 성능을 개선하려고 캐시를 쓰는 거라면, 로컬 캐시도 괜찮지 않을까 싶었습니다.

캐시에 있는 값을 서버 메모리에서 바로 가져오면 네트워크를 거칠 필요도 없으니까요.

 

 

로컬 캐시가 조회 속도에 유리할 수 있다는 건 알고 있었지만, 막상 구현에는 Redis를 쓰고 있었습니다. Redis를 따로 띄우고 관리하는 비용까지 생각하니 ‘이 상황에서도 Redis를 쓸 이유가 있을까?’라는 의문이 들었습니다.

 

그래서 제가 생각했던 상품 서비스에 로컬 캐시를 넣어보면 어떨지, 서버가 늘어나거나 상품 정보가 바뀌는 상황을 하나씩 짚어봤습니다. 아래는 두 방식의 성능 비교 결과가 아니라, 어떤 조건에서 무엇을 선택할지 고민한 내용입니다.

 

이 정도면 로컬 캐시로도 괜찮지 않을까요?

 

제가 가정한 상품 서비스는 평상시에는 서버 한 대로 운영하고, 이벤트가 열리면 최대 세 대까지 늘어납니다.

여러 사용자가 함께 보는 상품 정보는 자주 바뀌지 않고, 각 서버의 메모리에도 충분히 들어간다고 가정했습니다.

요청을 받기 전에 데이터를 미리 채워두는 워밍업도 가능합니다. 사용자별 좋아요 여부와 주문 정보는 캐시 대상에서 제외했습니다.

 

서버가 한 대라면 DB에서 읽은 상품 정보를 애플리케이션 메모리에 저장해두고, 다음 조회에서 재사용하면 되지 않을까요?

이런 방식의 로컬 캐시라면 캐시에 있는 값을 가져올 때 네트워크를 거칠 필요가 없습니다. 데이터도 충분히 들어가는데, Redis를 따로 운영할 이유가 있을까 싶었습니다.

 

물론 캐시에 메모리를 얼마나 쓸지는 정해야 합니다. 애플리케이션도 같은 메모리를 사용하니, 저장할 양과 만료 정책을 함께 고민해야 하고요. 그래도 제가 두었던 조건에서는 로컬 캐시부터 검토해볼 만하다고 생각했습니다. 그런데 이벤트가 열려 서버가 세 대로 늘어나도 같은 방식으로 운영하면 괜찮을까요?

 

서버가 세 대가 되면 뭐가 달라질까요?

A 서버에 캐시가 충분히 쌓인 상태에서 B와 C가 새로 들어왔다고 해보겠습니다.

A가 가지고 있는 상품 정보가 새 서버에도 자동으로 생기지는 않겠죠. B와 C는 필요한 데이터를 따로 가져와야 합니다.

 

처음에는 ‘요청을 받기 전에 미리 채워두면 되지 않을까?’ 싶었습니다. 워밍업을 마친 서버에 요청을 보내면, 사용자가 빈 캐시 때문에 기다리는 일은 줄일 수 있으니까요.

 

그런데 미리 채우려면 결국 DB를 조회해야 하더라고요. B와 C가 동시에 데이터를 가져와도 괜찮을까요? 이벤트 요청을 처리하는 와중에 새 서버의 캐시를 채우는 조회까지 더해져도 될지 조금 걸렸습니다.

 

이때의 DB 부하는 아직 측정하지 않아서, 워밍업이 가능하다는 조건만으로 괜찮다고 말하기는 어려웠습니다. 서버를 재시작하면 캐시가 사라지니 다시 채워야 하고요. 그렇다고 서버가 세 대라는 이유만으로 로컬 캐시를 제외해야 할지도 확신은 없었습니다.

우선 캐시를 채우는 조회가 DB에 얼마나 부담을 주는지 확인해보고 싶었습니다.

 

일단 세 서버에 같은 상품 정보를 채워뒀다고 해보겠습니다.

그다음 가격이 바뀌면 어떨까요? 변경을 처리한 서버 말고, 나머지 두 서버의 캐시도 바꿔줘야 하지 않을까요?

 

로컬 캐시..

 

자주 안 바뀌면, 조금 늦게 바뀌어도 괜찮을까요?

 

상품 가격이 1,000원에서 900원으로 바뀌었다고 해보겠습니다. 변경을 처리한 A 서버가 DB와 자기 캐시를 갱신해도, B와 C의 캐시에는 1,000원이 남을 수 있습니다. 같은 상품을 보는데 어느 서버가 응답하느냐에 따라 가격이 달라지는 상황입니다.

 

캐시에 저장한 값의 유효 시간인 TTL을 짧게 두면 어떨까요? 만료된 값은 다시 가져오게 할 수 있습니다. 다만 그때까지는 이전 값을 보여줄 수 있고, 짧게 만료시킬수록 다시 조회하는 일도 늘어납니다.

 

여기서 제가 두었던 조건을 다시 보게 됐습니다. ‘상품 정보가 자주 바뀌지 않는다’고는 했는데, 바뀐 뒤 예전 가격을 얼마 동안 보여줘도 되는지는 정하지 않았습니다. 하루에 한 번만 바뀌어도 그 직후부터 새 가격을 보여줘야 한다면, 변경이 드물다는 이유만으로 TTL에 맡겨도 될까요?

 

반대로 목록에 표시되는 정보가 잠깐 늦어도 괜찮다면, 모든 변경을 즉시 전파하는 구조까지 필요할지는 따져볼 수 있습니다. 제 가정에서 먼저 정할 건 ‘하루에 몇 번 바뀌나’뿐 아니라 ‘바뀐 뒤 얼마나 늦어도 괜찮나’였습니다. 이 글의 가격 예시는 목록 표시를 위한 것이고, 실제 주문에 적용할 가격은 DB에서 별도로 확인합니다.

 

바뀌었다고 알려주면 로컬 캐시를 계속 쓸 수 있을까요?

 

만료될 때까지 기다리는 게 곤란하다면, 다른 서버에도 변경 사실을 알려주면 어떨까요? DB 변경이 끝난 뒤 ‘상품 7의 캐시를 지워주세요’라는 알림을 보내는 방식입니다. 각 서버가 이전 값을 지우고 다음 조회에서 DB 데이터를 다시 가져오도록 생각해봤습니다.

 

실제로 카카오페이는 변경이 드문 조회용 정보를 로컬에 두고 Redis Pub/Sub으로 무효화 알림을 전달하고 있었습니다. 다만 일시적인 불일치를 허용할 수 있었고, 이미 Redis를 운영 중이라는 조건이 있었습니다.

 

조회는 로컬에서 하고 변경만 알려줄 수도 있겠네요. 그런데 저는 Redis를 새로 운영할 비용이 아쉬워서 로컬 캐시를 생각했습니다.

알림을 위해 Redis를 추가한다면, 처음 기대했던 ‘서버 메모리만 사용하기’와는 비용이 달라집니다.

 

 

알림을 받지 못하는 서버는 어떻게 할지도 남습니다. 예를 들어 C 서버의 연결이 끊긴 사이 가격이 바뀌면, A와 B만 이전 캐시를 지울 수 있습니다. Redis 공식 문서를 확인해보니 Pub/Sub은 연결이 끊겨 놓친 메시지를 재접속 후 다시 전달하지 않습니다.

 

 

그렇다면 TTL을 함께 둘지, 연결이 복구되면 캐시를 비울지 같은 정책도 필요하겠습니다. 비운 데이터를 다시 가져오는 동안의 DB 부하도 봐야 하고요. 아직 이 구조를 구현해서 확인한 것은 아닙니다. 다만 로컬 캐시의 조회 속도를 얻으려면 제가 어디까지 관리할 수 있을지 생각해볼 필요가 있었습니다.

 

그럼 Redis에 같이 저장하면 편해질까요?

 

서버마다 가진 값을 맞추는 일(로컬 캐시 관리)이 부담스럽다면, 상품 정보를 외부 저장소에 두고 함께 읽을 수 있습니다.

이 글에서 말하는 공유 캐시이고, 글로벌 캐시라고도 부릅니다. Redis는 그 저장소로 사용할 수 있는 기술입니다.

 

 

A·B·C가 같은 캐시를 읽으면 서버별 복제본에 변경을 알리는 일은 줄어듭니다. B와 C가 새로 들어와도 공유 캐시에 값이 남아 있다면 재사용할 수 있습니다. 올리브영의 무형상품 서비스도 여러 서버와 오토스케일링을 고려해 공유 캐시를 선택했습니다.

 

 

처음에는 조회할 때마다 네트워크를 거치는 게 아깝다고 생각했습니다. 그런데 서버별 변경 알림과 새 서버의 캐시 채우기를 줄일 수 있다면, 그 통신 비용을 감수할 이유도 있겠네요. 그렇다고 같은 캐시를 읽으면 항상 DB의 최신 값이 보일까요?

DB를 바꾼 뒤 공유 캐시를 지우는 데 실패하면, 세 서버가 모두 이전 값을 읽을 수도 있습니다. 변경 반영을 관리하는 일까지 없어지지는 않습니다.

 

 

Redis를 운영하면서 연결과 타임아웃, 메모리 용량, 장애도 관리해야 합니다. Redis가 멈췄을 때 DB로 우회하도록 만들 수는 있지만, 그동안 캐시가 받던 요청까지 DB가 처리할 수 있을까요? 앞에서는 새 서버 두 대가 캐시를 채우는 부하가 걸렸는데, 이번에는 세 서버의 조회가 한꺼번에 DB로 갈 수 있습니다.

 

 

Amazon의 캐시 설계 글에서도 빈 캐시와 캐시 장애가 원본 서비스에 주는 부하를 다룹니다.

제 조건에서 로컬 캐시를 채우는 부담과 공유 캐시를 운영하는 부담 중 어느 쪽이 더 큰지는, 서버 수만 보고 결정하기 어려웠습니다.

 

둘 중 하나만 골라야 할까요?

 

여기까지는 로컬 캐시와 공유 캐시 중 하나를 고르는 쪽으로 생각했습니다. 그런데 상황에 따라 둘을 함께 쓰면 어떨까요? 예를 들어 변경이 드문 정보는 로컬에 두고, 여러 서버에서 변경을 함께 반영해야 하는 정보는 공유 캐시에 두는 식으로 대상을 나눌 수도 있습니다.

 

 

같은 데이터를 두 곳에 저장하는 방법도 있습니다. 먼저 로컬 캐시를 보고, 없으면 공유 캐시에서 가져와 로컬에 저장합니다. 공유 캐시에도 없다면 DB에서 조회해 두 캐시를 채우고요. 이렇게 하면 로컬에 값이 있을 때는 외부 조회를 생략하고, 새 서버는 공유 캐시에 남아 있는 값을 가져올 수 있습니다.

 

 

실제로 DoorDash는 Redis에 저장된 예측용 데이터를 반복해서 가져오는 비용을 줄이려고 애플리케이션에 로컬 캐시를 추가했습니다. 앞서 살펴본 변경 알림용 Redis와는 역할이 다릅니다. 이 구조에서는 Redis에도 조회할 데이터가 들어 있습니다.

 

 

다만 공유 캐시를 고쳐도 각 서버의 로컬 캐시는 예전 값을 가지고 있을 수 있습니다. 두 캐시의 만료 시간과 변경 반영을 함께 정해야 하니, 앞에서 고민했던 문제가 사라지는 건 아닙니다. 제 조건에서 처음부터 두 곳에 저장할 만큼 이득이 있을지는 아직 모르겠습니다. 이미 Redis를 쓰고 있고 반복되는 Redis 조회가 부담이라면, 자주 읽는 일부 정보에 로컬 캐시를 추가하는 쪽도 비교해볼 수 있겠습니다.

 

제 조건에서는 로컬 캐시도 검토할 만했습니다

데이터가 각 서버 메모리에 충분히 들어가고, 변경이 드물며, 이전 정보가 잠깐 보이는 것도 허용할 수 있다면 로컬 캐시부터 검토해도 괜찮다고 생각합니다. 서버가 최대 세 대라는 이유만으로 Redis를 추가해야 하는 건 아니니까요.

 

다만 제가 했던 실험은 데이터 변경 없이 같은 상품 목록을 반복 조회하는 방식이었습니다. 한 번 저장한 결과를 다시 쓰기 좋은 조건이었죠. 상품 정보가 바뀌어 캐시를 자주 지우는 상황에서도 같은 효과를 얻는지는 확인하지 못했습니다.

 

로컬 캐시와 Redis를 직접 비교한 결과가 없지만 해봐야겠습니다.

 

공유 캐시를 선택할 이유도 나름 있다고 생각합니다. 서버마다 변경을 알리고, 놓친 알림을 복구하는 일이 부담스럽다면 같은 저장소를 함께 읽는 편이 관리하기 수월할 수 있습니다. 대신 네트워크 통신과 별도 저장소의 운영 비용을 감수해야 하죠. 캐시가 멈췄을 때 DB로 몰리는 요청을 감당할 수 있을지도 남고요.

 

그래서 캐시를 고를 때는 성능과 함께 필요한 최종 데이터 일관성, 장애 상황에서의 가용성을 봐야겠다고 생각했습니다. 얼마나 빨리 읽을지, 변경된 정보를 얼마나 늦게 보여줘도 되는지, 캐시가 없어도 조회를 계속 제공할 수 있는지를 정하는 겁니다. 이 조건을 맞추는 데 드는 부담을 비교하면 로컬과 공유 캐시를 선택할 이유도 더 구체적으로 설명할 수 있겠습니다.

 

참고한 글과 공식 문서

 

카카오페이: 분산 시스템에서 로컬 캐시 활용하기

 

올리브영: 무형상품 서비스에 캐시 적용하기

 

Redis 공식 문서: Pub/Sub

 

Amazon Builders’ Library: Caching challenges and strategies

DoorDash: How We Applied Client-Side Caching to Improve Feature Store Performance by 70%

 

반응형

'개발 > DB' 카테고리의 다른 글

재고 동시성을 공부하며 이해한 SELECT와 FOR UPDATE  (0) 2026.10.05
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/10   »
일 월 화 수 목 금 토
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함