왜 클라우드플레어는 인기 없는 아이템까지 메모리에 캐시하는가
(blog.cloudflare.com)클라우드플레어가 캐시 전략을 바꾸어서 SSD의 쓰기 부하를 최대 25%까지 줄인 경험을 블로그에 올렸습니다. (영어) 통념과는 달리, 클라우드플레어는 접근 빈도가 높지 않은 아이템도 일부러 메모리에 캐시하는 방식으로 이런 목표를 달성했습니다.
SSD는 쓰기에 취약한 저장 매체입니다. SSD에서 데이터를 저장하는 플래시메모리 셀은 재기록 가능한 횟수가 제약되어 있으며, 한번 기록된 내용을 지우고 다시 기록하는 것은 상대적으로 오랜 시간이 걸릴 뿐더러 읽기 작업까지 덩달아 느리게 만드는 작업입니다. 따라서 SSD에서는 특히 쓰기 작업을 줄이는 것이 중요한 최적화입니다.
클라우드플레어는 서버에 고성능 NVMe SSD를 많이 사용하는 업체이기 때문에, 당연히 이런 부분을 고민했습니다. 클라우드플레어는 CDN 업체인데, CDN이란 본질적으로 커다란 네트워크 캐시라고 할 수 있지요. 클라우드플레어 서버의 SSD에 저장되는 내용 또한 결국 캐싱된 아이템인데, 관찰 결과 그 중에는 한번 캐싱된 이후 다시는 액세스되지 않는 내용(일명 “원 히트 원더”)이 참 많았습니다. 따라서 이런 아이템들은 SSD에 기록하지 않는 것이 좋을 것입니다. 1번만 접근이 일어나는 아이템을 SSD에 기록하지 않는 방안을 실험한 결과, SSD의 레이턴시가 거의 5%나 줄어든다는 고무적인 결과가 나왔습니다.
문제는 이 아이디어를 어떻게 실제 서비스 규모에서 적용할 수 있느냐는 것이었습니다. 1번 접근할 때는 캐시하지 않다가 2번 접근할 때부터 캐싱한다는 것은 데이터 원본에 대한 접근량이 2배로 늘어난다는 뜻이 됩니다. 당연히 그만큼 여러 비용이 발생할 것이고, 이는 본말전도지요. 그래서 클라우드플레어는 캐시 기록을 2단계로 계층화하였습니다. 처음에는 모든 아이템을 ‘단기 캐시’인 메모리에 캐싱한 다음, 접근 횟수가 여러 번인 아이템만 “승급”하여 ‘영구 캐시’인 SSD에 기록하는 것입니다. 그러면 접근 빈도가 낮은 아이템은 자연스레 캐시에서 밀려나겠죠. 읽기의 경우는 따로 신경쓸 필요가 없었습니다. 왜냐하면 SSD로부터 읽어오는 것은 이미 운영체제가 잘 캐싱해주고 있기 때문입니다.
물론 이러한 발상을 실제 서비스에 적용하는 부분은 조심스럽고 보수적으로 이루어지고 있습니다. 이 발상은 기본적으로 많은 메모리를 소비할 텐데 이는 운영체제의 기존 캐시와 경합할 수도 있고, 혹은 서버 프로세스를 무중단 배포방식으로 업데이트하는 도중에는 일시적으로 메모리가 부족해져서 결과적으로 서비스 품질이 나빠질 수도 있기 때문이지요. 따라서 위 아이디어는 새로 도입한 메모리가 충분한 서버에서만 적용하는 방식으로 점진적으로 도입하고 있습니다.
도입 결과는 긍정적입니다. 캐시 용량을 튜닝해가며 적용한 결과 SSD 쓰기가 20%에서 최대 25%까지 줄어들었고, 이는 레이턴시 감소로 이어졌습니다. 추후 클라우드플레어는 이 기법을 더 많은 서버로 확대하고, 승급 알고리즘을 개선하여 “강등” 또한 도입하며, SSD뿐만이 아니라 HDD까지 고려한 계층 구조를 만들 것이라고 합니다.
이 아이디어를 보고 가장 먼저 생각난 것은 Java의 가비지 컬렉션 기법이었습니다. 대다수 가비지 컬렉션 기법들의 기본 전제는 바로 [대부분의 객체는 아주 짧은 시간 동안만 사용된다]는 일명 ‘약한 세대 가설’(weak generational hypothesis)이니까요. 이런 원리가 변형 기출(?)로 적용된 것이 위 내용이 아닐까 합니다.
좋은 글 감사합니다.
클라우드플레어 블로그에 은근 읽어볼 글이 많이 올라오는 것 같아요.
좋은 회사 기술 블로그는 어떻게 운영되는가 https://news.hada.io/topic?id=1698
CloudFlare 는 블로깅이 사내 문화로 정착되어서 그런듯 합니다.