도메인 특성에 맞는 캐싱 전략 설계 (Eviction, Warming)
https://github.com/ALLREVA/Allreva_BE
최근에 진행한 프로젝트이다
주제는 '공연 차대절 플랫폼' 으로 KOPIS 에서 공연 정보를 받아와서 해당 공연의 정보를 조회할 수 있고, 특정 공연의 차대절 및 수요조사 글을 등록할 수 있다
나는 트래픽이 많이 몰릴 것으로 예상되며 변경이 흔치 않은 '공연 상세 조회'에 캐싱을 도입하고자 하였다
ALLREVA 프로젝트에서 '공연' 도메인의 특성
우선 캐싱 전략을 세우기 이전에 해당 프로젝트에서 캐싱을 적용하려고 하는 도메인의 특성이 무엇인지 살펴봐야한다
ALLREVA 프로젝트에서 내가 정리한 공연 도메인의 제일 중요한 특성들은 다음과 같다
정보의 갱신이 매우 드물게 발생한다
우리는 KOPIS 로 '하루에 한 번' 특정 시각에 공연 데이터를 업데이트 한다
따라서 주최자가 정보를 바꾸든 말든 해당 데이터가 갱신되는 횟수는 많아야 하루에 한 번이다
(티켓팅 서비스가 아닌 차대절 서비스이기 때문에 주최자가 공연 정보를 수정하여도 그 즉시 반영하지 않아도 된다고 판단하였다)
실시간성을 요구하지 않는다
ALLREVA 프로젝트는 '공연 차대절 서비스'이기때문에 '공연 티켓팅 서비스' 와 같은 실시간성을 요구하지 않는다
주최자가 공연 정보를 수정하거나 삭제하더라도 하루 안에 반영을 해준다면 문제가 없을 것이다
그리고 이러한 특성이 KOPIS 로 데이터를 받아오는 부분에 적용되어 있다
조회가 매우 빈번하게 발생한다
티켓팅 서비스는 아니지만 결국 차대절 및 수요조사를 하기 위해서는 공연 정보를 확인하게 될 것이라고 판단하였다
또한 여러 공연 정보를 한 곳에서 확인할 수 있기 때문에 차대절을 원하지 않더라도 자주 조회가 발생할 것이다
(물론 프로젝트가 어느정도 자리를 잡는다면..!)
기술 선택에 대한 고민과 판단 근거
캐싱을 위해 적용할 수 있는 기술들로는 대표적으로 Redis, Memcached, Caffeine Cache 등이 있다
우선, 이 기술들을 선택하기 이전에 고려해야할 것이 글로벌 캐시를 사용할지 로컬 캐시를 사용할지 정하는 것이다
로컬 캐시 vs 글로벌 캐시
우선 많이 사용하는 Redis 가 대표적인 글로벌 캐시이다
글로벌 캐시는 로컬 캐시에 비해 네트워크로 인한 성능 저하가 발생할 수 있다
(물론 요즘은 Redis For Client-Side-Caching 으로 인해 성능 차이가 미비하다고 한다)
거기에 레디스가 여러 이유에 의해 죽는 경우도 발생할 수 있으니 전체적으로 관리 포인트가 하나 더 늘어난다고 할 수 있다
하지만 중앙에서 데이터가 관리되기 때문에 스케일 아웃 시 매우 편리하게 사용할 수 있다
(데이터의 일관성을 유지하기 쉽다)
로컬 캐시는 딱 반대이다
스케일 아웃 시 파편화 문제로 인해 고통받을 수 있으나 속도가 글로벌 캐시에 비해 살짝 더 빠르다
물론 관리 또한 글로벌 캐시에 비해 편리하다
우선 나는 로컬 캐시를 선택하였다
현재 ALLREVA 프로젝트는 모놀리틱한 구조이기에 파편화 문제가 지금 당장은 발생하지 않는다
물론 스케일 아웃을 하여 파편화 문제가 생기더라도 공연 정보의 동기화 자체가 별로 중요하지 않기 때문에 큰 문제가 되지 않는다
(티켓팅 서비스였다면 무조건 글로벌 캐시를 선택하였을 것이다)
성능이 로컬캐시가 살짝 더 빠르긴 하지만 이게 로컬 캐시를 선택한 이유는 아니다
그 부분은 차이가 매우 적다고 느껴져 애초에 판단할 때 배제하였다
내가 로컬 캐시를 선택한 이유는 사실 'Redis 관리하기 싫어서' 이다
로컬 캐시의 단점이 자신의 프로젝트에는 해당이 되지 않는다면 로컬 캐시를 선택하는 것이 좋은 선택인 것 같다
이중에서 내가 선택한 로컬 캐싱 방식은 ConcurrentHashMap 이었다
개발 기간이 꽤 촉박하였기 때문에 사용 방법이 익숙한 것을 선택하였고 도메인 특성 상 메모리 관리가 어렵지 않을 것이라 판단하였다
(밑에 Eviction 전략에서 설명)
캐싱 전략
캐싱 전략으로는 대표적으로 Look-Aside, Write-Through 등등이 있다
하지만 이 공연 도메인에서는 그런 읽기 전략이나 쓰기 전략말고 다른 것이 중요하다
아까 위에서 설명했듯이, 공연 정보는 '하루에 한 번 특정한 시각'에 불러온다
그 이외에는 데이터의 수정이 아예 없다
따라서 그에 맞는 특별한 전략을 세워야 한다
Cache Warming
공연 정보는 '하루에 한 번 특정한 시각'에 불러오며 현재 진행중인 공연 및 곧 진행 할 공연의 개수가 그리 많지 않다
따라서 유효한(진행중 + 진행 할) 공연을 '모두' 캐싱해버릴 수 있다
KOPIS 로 정보를 불러옴과 동시에 받아온 공연 정보들을 전부 캐싱하였다
처음 조회가 발생하여도 캐시 히트하게 되는 것이다!
Eviction 전략
많은 사람들이 Eviction Policy 로 LRU 나 LFU 를 자주 사용한다고 들었다
하지만 우리는 공연 개수가 많지 않기 때문에 보통은 캐시를 비우지 않아도 괜찮다
이미 종료된 공연만 비워주면 된다!
따라서 이미 자리잡은 서비스들이 겪는 Cache Stampede 문제 등등은 적어도 공연 상세 조회에서는 걱정하지 않아도 될 것이다!