시스템 디자인

잘못된 캐싱 전략이 당신의 서비스를 망치고 있습니다

캐싱을 활용한 확실한 성능 개선 비법 대공개

2024.10.28 | 조회 476 |
0
|

데브필 DevPill

Top 1% 개발자로 거듭나는 성공 처방전

Introduction

모 스타트업의 채용 공고를 보면 이런 문구가 있습니다. "우리는 초당 100만 건의 트랜잭션을 처리합니다." 멋진 말이죠? 하지만 실제로 이런 처리량을 달성하는 서비스는 얼마나 될까요?

현실은 조금 다릅니다. 대부분의 서비스가 겨우 수백 TPS를 처리하는데도 CPU는 이미 한계치를 찍고, 응답 시간은 계속해서 늘어나고 있습니다. 더 많은 서버를 투입해도 근본적인 해결책이 되지 못하죠. 그리고 우리는 결국 같은 질문 앞에 서게 됩니다.

"도대체 어떻게 해야 성능을 개선할 수 있을까?"

답은 의외로 단순할 수 있습니다. 바로 '캐싱'입니다. 하지만 여기서 함정이 있습니다. 잘못된 캐싱 전략은 오히려 더 큰 문제를 초래할 수 있거든요. Cache-aside? Write-through? Write-back? 각각의 전략들은 언제 써야 하며, 어떤 장단점이 있을까요?

이 글에서는 현업에서 가장 많이 사용되는 5가지 캐싱 전략을 상세히 살펴보려고 합니다. 각 전략의 작동 원리와 장단점을 이해하고 나면, 여러분의 서비스에 가장 적합한 캐싱 전략을 선택할 수 있을 거예요. 우리 함께 시스템 성능 개선의 비밀을 파헤쳐볼까요?

 


캐싱 전략 가이드: 최적의 전략 선택 방법

캐싱은 시스템 성능을 향상시키는 가장 효과적인 방법 중 하나입니다. NoSQL 데이터베이스조차도 속도가 느릴 수 있으며, 우리 모두가 알다시피 현대 시스템에서 속도는 매우 중요한 요소입니다.

적절하게 구현된 캐시는 응답 시간을 단축하고, 데이터베이스 부하를 줄이며, 운영 비용을 절감할 수 있습니다. 다양한 캐싱 전략이 있으며, 적절한 전략을 선택하는 것만으로도 성능에 큰 차이를 만들 수 있습니다. 캐싱 전략은 데이터의 특성과 접근 패턴, 즉 데이터가 어떻게 쓰이고 읽히는지에 따라 달라집니다. 예를 들어 다음과 같은 상황을 고려해야 합니다:

  • 쓰기 작업이 많고 읽기가 상대적으로 적은 시스템인가요? (예: 시계열 로그)
  • 한 번 작성된 데이터가 여러 번 읽히는 구조인가요? (예: 사용자 프로필)
  • 매번 고유한 데이터가 반환되나요? (예: 검색 결과)

모바일 게임의 상위 10위 리더보드를 위한 캐싱 전략은 사용자 프로필을 집계하고 제공하는 서비스의 전략과는 완전히 다를 수밖에 없습니다. 성능 최적화를 위해서는 상황에 맞는 적절한 캐싱 전략을 선택하는 것이 핵심입니다. 이제 다양한 캐싱 전략을 자세히 살펴보겠습니다.

Cache-Aside (보조 캐시)

제가 참여했던 프로젝트들에서 가장 흔히 사용된 캐싱 방식입니다. 이 방식에서 캐시는 독립적으로 존재하며, 애플리케이션이 캐시와 데이터베이스 모두와 직접 통신합니다. 캐시와 주 데이터베이스 사이에는 직접적인 연결이 없으며, 모든 캐시 및 데이터베이스 작업은 애플리케이션에서 관리합니다.

동작 방식은 다음과 같습니다:

  1. 애플리케이션이 먼저 캐시를 확인합니다.
  2. 캐시에서 데이터를 찾으면(캐시 히트), 해당 데이터를 읽어서 바로 클라이언트에 반환합니다.
  3. 캐시에서 데이터를 찾지 못하면(캐시 미스), 애플리케이션은 추가 작업을 수행합니다. 데이터베이스에 쿼리하여 데이터를 가져오고, 이를 클라이언트에 반환함과 동시에 캐시에도 저장하여 동일한 데이터에 대한 후속 요청이 캐시 히트가 되도록 합니다.

활용 사례와 장단점

Cache-aside는 범용성이 높으며 특히 읽기 작업이 많은 워크로드에 매우 적합합니다. Memcached와 Redis가 이 방식에 가장 널리 사용되는 도구입니다. Cache-aside를 사용하는 시스템은 캐시 장애에 대한 내구성이 뛰어납니다. 캐시 클러스터가 다운되더라도 시스템은 데이터베이스에 직접 접근하여 계속 작동할 수 있기 때문입니다. (다만 최대 부하 상황에서 캐시가 다운되면 상황이 심각해질 수 있습니다. 응답 시간이 크게 증가하고, 최악의 경우 데이터베이스마저 마비될 수 있습니다.)

또 다른 장점은 캐시의 데이터 모델을 데이터베이스와 독립적으로 설계할 수 있다는 점입니다. 예를 들어, 여러 쿼리 결과를 조합하여 생성된 응답을 특정 요청 ID와 매핑하여 저장할 수 있습니다.

Cache-aside에서는 일반적으로 데이터를 데이터베이스에 직접 쓰는 방식을 사용합니다. 이런 경우 캐시와 데이터베이스 간의 데이터 불일치가 발생할 수 있습니다. 개발자들은 보통 TTL(Time To Live)을 설정하여 이 문제를 해결합니다. TTL이 만료될 때까지는 다소 오래된 데이터를 제공하더라도 시스템이 계속 작동하도록 하는 것입니다. 데이터의 실시간성이 매우 중요한 경우에는 캐시 항목을 즉시 무효화하거나, 뒤에서 설명할 다른 쓰기 전략을 사용해야 합니다.

Read-Through Cache

Read-through cache는 데이터베이스와 직렬로 연결되어 동작합니다. 캐시 미스가 발생하면 자동으로 누락된 데이터를 데이터베이스에서 가져와 캐시를 갱신한 후, 애플리케이션에 반환합니다.

Cache-aside와 마찬가지로 read-through 전략도 지연 로딩 방식을 사용합니다. 즉, 데이터는 처음 요청받을 때 비로소 로드됩니다.

활용 사례와 장단점

Read-through는 Cache-aside와 매우 비슷해 보이지만, 두 가지 중요한 차이점이 있습니다:

  1. Cache-aside에서는 애플리케이션이 데이터베이스 조회와 캐시 갱신을 직접 관리해야 합니다. 반면 read-through에서는 이러한 로직이 캐시 라이브러리나 독립 캐시 서비스에서 자동으로 처리됩니다.
  2. Cache-aside와 달리, read-through 캐시는 반드시 데이터베이스의 데이터 모델과 동일한 구조를 유지해야 합니다.

Read-through 캐시는 동일한 데이터가 반복적으로 요청되는 읽기 중심 워크로드에서 가장 효과적입니다. 예를 들어 인기 뉴스 기사의 조회가 이에 해당합니다. 다만 한 가지 단점이 있습니다. 데이터가 처음 요청될 때는 반드시 캐시 미스가 발생하며, 이때 캐시를 채우는 추가적인 시간이 소요됩니다. 개발자들은 이 문제를 해결하기 위해 캐시 '워밍업' 또는 '예열' 작업을 수행합니다. 즉, 주요 데이터를 미리 캐시에 로드해 두는 것입니다. Cache-aside와 마찬가지로 캐시와 데이터베이스 간의 데이터 불일치 문제가 발생할 수 있는데, 이는 다음에 설명할 쓰기 전략들을 통해 해결할 수 있습니다.

Write-Through Cache

이 전략에서는 모든 데이터가 반드시 캐시를 거쳐 데이터베이스에 기록됩니다. 캐시는 데이터베이스와 직렬로 연결되어 있으며, 모든 쓰기 작업은 캐시를 통해 메인 데이터베이스로 전달됩니다. 이러한 구조는 캐시와 데이터베이스 간의 데이터 일관성을 자연스럽게 보장합니다.

구체적인 동작 과정은 다음과 같습니다:

  1. 애플리케이션이 데이터를 캐시에 기록합니다.
  2. 캐시는 해당 데이터를 메인 데이터베이스에 기록합니다. 이 과정이 완료되면 캐시와 데이터베이스가 완벽히 동기화된 상태가 됩니다.

활용 사례와 장단점

Write-through 캐시는 단독으로 사용될 때는 특별한 이점이 없어 보일 수 있습니다. 오히려 데이터를 캐시와 데이터베이스에 순차적으로 기록해야 하므로 추가적인 지연이 발생합니다. 하지만 read-through와 함께 사용하면 상황이 달라집니다. Read-through의 모든 장점을 누리면서도 데이터 일관성까지 완벽하게 보장받을 수 있습니다. 모든 쓰기 작업이 캐시를 통과하므로 별도의 캐시 무효화 처리가 필요하지 않다는 것도 큰 장점입니다.

DynamoDB Accelerator(DAX)가 이러한 read-through/write-through 캐시의 대표적인 예시입니다. DAX는 DynamoDB와 애플리케이션 사이에서 중개자 역할을 하며, 모든 읽기와 쓰기 작업이 DAX를 통해 이루어집니다. (참고: DAX를 사용하실 계획이라면, 반드시 데이터 일관성 모델과 DynamoDB와의 상호작용 방식을 철저히 이해하고 계획하셔야 합니다.)

Write-Around 

이 전략에서는 데이터를 데이터베이스에 직접 기록하고, 실제로 읽히는 데이터만 선택적으로 캐시에 저장합니다.

활용 사례와 장단점

Write-around는 특히 read-through와 조합했을 때 큰 효과를 발휘합니다. 데이터가 한 번 작성된 후 거의 읽히지 않거나 전혀 읽히지 않는 경우에 매우 효율적입니다. 실시간 로그 기록이나 채팅방 메시지가 대표적인 예시입니다. Cache-aside와도 잘 어울리는 전략입니다.

Write-Back 또는 Write-Behind

이 전략에서는 애플리케이션이 캐시에 데이터를 기록하면, 캐시가 즉시 완료 응답을 보내고 나중에 비동기적으로 데이터베이스에 기록합니다.

Write-through와 매우 유사해 보이지만 결정적인 차이가 있습니다: Write-through에서는 캐시에 기록된 데이터가 즉시 데이터베이스에 동기화되는 반면, write-back에서는 이 동기화가 비동기적으로 이루어집니다. 따라서 애플리케이션 입장에서는 write-back 방식의 쓰기 작업이 더 빠르게 느껴집니다. 응답을 반환하기 전에 캐시만 업데이트하면 되기 때문입니다.

활용 사례와 장단점

Write-back 캐시는 쓰기 성능을 크게 향상시키므로 쓰기 작업이 많은 시스템에 특히 적합합니다. Read-through와 함께 사용하면 가장 최근에 수정되거나 접근된 데이터를 항상 캐시에서 빠르게 조회할 수 있어, 읽기와 쓰기가 모두 많은 혼합 워크로드에서도 뛰어난 성능을 보입니다.

이 전략의 또 다른 장점은 데이터베이스 장애에 대한 내구성이 뛰어나다는 것입니다. 일시적인 데이터베이스 다운타임이 발생하더라도 시스템이 계속 작동할 수 있습니다. 더불어 배치 처리나 데이터 병합이 가능한 경우, 데이터베이스로의 전체 쓰기 횟수를 줄일 수 있습니다. 이는 DynamoDB처럼 요청 횟수에 따라 비용이 청구되는 데이터베이스를 사용할 때 특히 중요한 장점이 됩니다.

(그러나 DAX는 write-through 방식으로 동작하므로, 쓰기가 많은 애플리케이션에서는 이러한 비용 절감 효과를 기대할 수 없습니다. 실제로 DAX를 처음 접했을 때 이 점이 제 첫 번째 의문이었습니다. DynamoDB는 비용이 상당히 높을 수 있는데, 아쉽게도 아마존은 이 부분에 대한 해결책을 제시하지 않았습니다.)

일부 개발자들은 트래픽 급증 시의 부하를 더 효과적으로 관리하기 위해 Redis를 cache-aside와 write-back 용도로 동시에 활용합니다. 단, 이 전략의 가장 큰 위험은 캐시 장애 시 데이터가 영구적으로 손실될 수 있다는 점입니다.

참고로 대부분의 관계형 데이터베이스 스토리지 엔진(예: InnoDB)은 이미 내부적으로 write-back 캐시를 기본 탑재하고 있습니다. 쿼리 결과는 먼저 메모리에 기록된 후 적절한 시점에 디스크로 동기화됩니다.

결론

지금까지 다양한 캐싱 전략과 각각의 장단점을 살펴보았습니다. 실무에서는 시스템의 목표를 명확히 정의하고, 데이터 접근 패턴(읽기/쓰기 비율과 특성)을 철저히 분석한 후, 이에 가장 적합한 전략이나 전략들의 조합을 선택해야 합니다.

잘못된 전략을 선택하면 어떻게 될까요? 시스템의 목표나 데이터 접근 패턴과 맞지 않는 전략을 선택하면, 불필요한 지연이 발생하거나 캐싱의 이점을 제대로 활용하지 못하게 됩니다. 예를 들어, 데이터가 한 번 작성된 후 거의 읽히지 않는 상황에서 write-through/read-through를 사용하면, 캐시가 불필요한 데이터로 채워지게 됩니다. 물론 캐시 용량이 충분하다면 큰 문제가 되지 않을 수 있습니다. 하지만 메모리가 제한적이고 서버 비용이 중요한 고성능 시스템에서는 올바른 캐싱 전략 선택이 결정적인 차이를 만들어냅니다.

이 글이 여러분의 캐싱 전략 선택에 도움이 되었기를 바랍니다. 여러분의 프로젝트에서는 어떤 캐싱 전략을 사용하고 계신지, 그리고 그 선택의 이유는 무엇인지 댓글로 공유해 주시면 감사하겠습니다. 다음에 또 다른 유익한 주제로 찾아뵙겠습니다.

 


👥 더 나은 데브필을 만드는 데 의견을 보태주세요

Top 1% 개발자로 거듭나기 위한 처방전, DevPill 구독자 여러분 안녕하세요 :) 

저는 여러분들이 너무 궁금합니다. 

어떤 마음으로 뉴스레터를 구독해주시는지, 

어떤 환경에서 최고의 개발자가 되기 위해 고군분투하고 계신지, 

제가 드릴 수 있는 도움은 어떤 게 있을지. 

아래 설문조사에 참여해주시면 더 나은 콘텐츠를 제작할 수 있도록 힘쓰겠습니다. 설문에 참여해주시는 분들 전원 1개월 유료 멤버십 구독권을 선물드립니다. 유료 멤버십에서는 아래와 같은 혜택이 제공됩니다.

  • DevPill과의 1:1 온라인 커피챗
  • 멤버십 전용 슬랙 채널 참여권
    • 채용 정보 공유 / 스터디 그룹 형성 / 실시간 기술 질의응답
  • 이력서/포트폴리오 템플릿

 

설문 참여하고 유료 멤버십 혜택받기 →

 

 

다가올 뉴스레터가 궁금하신가요?

지금 구독해서 새로운 레터를 받아보세요

이번 뉴스레터 어떠셨나요?

데브필 DevPill 님에게 ☕️ 커피와 ✉️ 쪽지를 보내보세요!

댓글

의견을 남겨주세요

확인
의견이 있으신가요? 제일 먼저 댓글을 달아보세요 !
© 2024 데브필 DevPill

Top 1% 개발자로 거듭나는 성공 처방전

뉴스레터 문의dev.redpill@gmail.com

자주 묻는 질문 서비스 소개서 오류 및 기능 관련 제보

서비스 이용 문의admin@team.maily.so

메일리 사업자 정보

메일리 (대표자: 이한결) | 사업자번호: 717-47-00705 | 서울 서초구 강남대로53길 8, 8층 11-7호

이용약관 | 개인정보처리방침 | 정기결제 이용약관