“모든 것을 효율적으로 Cache 할 수 있다면 게임 체인저가 될 수 있다.”
Netflix는 메타 데이터 Caching을 위해 Java로 작성된 범용 Cache인 Hollow를 OSS로 제공하고 있다.
일반적으로 소프트웨어 엔지니어들은 “빅데이터”라는 데이터를 보급을 요구하는 문제에 직면한다. 이런 유형의 문제는 다음과 같다.
- 전자 상거래 사이트내 제품의 메타 데이터
- 검색 엔진의 메타 데이터
- 영화 및 TV 프로그램에 대한 메타 데이터
이런 문제에 직면할 때 일반적으로 아래의 두 가지 방법 중 하나를 선택한다.
- Consumer의 원격 접근을 위해 데이터를 중앙 집중화하여 보관 (e.g. RDBMS, NoSQL, Memcached, Redis.,)
- 데이터를 직렬화(e.g. json, xml)하고 Consumer에게 배포하여 사본을 보관
위에서 언급된 방법의 확장에는 여러 가지 문제점이 존재한다. 데이터를 중앙 집중화하면 데이터 집합이 무한히 커질 수 있지만,
- 데이터와 상호 작용할 때 대기 시간 및 대역폭 제한이 존재
- 원격 데이터 저장소는 데이터의 로컬 복사본만큼 신뢰할 수 있음
반면, 로컬 복사본을 전체적으로 직렬화하여 메모리에 저장하면 지연 시간이 늘어나고 주파수 Access가 훨씬 늘어날 수 있지만 이 접근법은 데이터 집합의 크기가 커짐에 따라 Scaling 문제가 존재한다.
- 데이터 집합의 Heap 공간이 커진다
- 데이터를 가져오려면 더 많은 비트를 다운로드 해야 한다.
- 데이터를 업데이트하려면 상당한 CPU 리소스가 필요하거나 GC 동작에 영향을 미칠 수 있다.
엔지니어는 대부분 자주 Access하는 데이터를 로컬에 Cache하고 자주 Access하지 않는 데이터는 원격에서 가져오는 Hybrid 방식을 선택한다. 이 접근 방식에는 다음과 같은 문제가 있다.
- 자료 구조는 상당한 Heap 공간을 소비 할 수 있다.
- GC 행동에 부정적인 영향을 줄 수 있다.
Netflix에서는 로컬 Cache의 크기 조정은 많은 레코드의 원격 대기 시간과 더 많은 데이터를 로컬로 유지하는 Heap 요구 사항 사이의 조심스러운 조율이라는 관점으로 보고 있다.
Hollow는 Consumer에게 전체 읽기 전용 데이터를 메모리에 보관하는 기능을 제공한다. 부분 Cache에서 데이터를 업데이트하고 제거하는 결과를 회피한다.
Hollow를 사용하기전까지 Netflix는 Zeno를 사용했다. Hollow의 선구자인 Zeno는 크기가 제한되는 POJO(Plain Old Java Objects)로 데이터를 저장했다.
Hollow는 변화하는 데이터의 상태사이에 자동으로 delta를 생성한다. Consumer가 데이터 업데이트 상태를 유지하는데 필요한 노력을 최소화 시킨다. 또한 자동으로 데이터 중복을 제거하여 Consumer 데이터 셋의 Heap크기를 최소화 한다.
Hollow는 POJO 대신 데이터를 압축하고 고정 길이의 인코딩 방식으로 대체한다. 이 인코딩은 데이터 셋의 Heap 공간을 최소화하고 즉시 데이터에 Access하는데 드는 CPU 비용을 최소화하도록 설계 되었다. 인코딩 된 모든 레코드는 사용량이 많은 서버에서 GC 동작에 영향을 주지 않도록 JVM Heap에 풀링 된 메모리내의 재사용 가능한 slab에 저장된다.
Hollow는 여러 서버에 데이터를 분산하고 데이터 내구성을 위해 복제 알고리즘을 제공하지 않고 모든 Consumer가 모든 데이터를 사용할 수 있는 방법을 사용한다.
Hollow가 memcached와의 다른점은 아래와 같다.
- Memcached의 주요 이점은 분산 Caching 시스템으로 많은 인스턴스에서 메모리를 풀링한다는 점이다. 그러나 Hollow는 분산된 Caching 시스템은 아니며, 여전히 중앙 집중화되어 있다. 데이터 관점에서는 각 시스템으로 Caching되기에 분산 시스템이라 볼 수 있다.
- Hollow는 Netflix의 매우 높은 처리량에 대한 Cache 요구 사항을 충족 시키기 위해 제작되었다. Consumer에게 전체 데이터 셋을 복제한다는 것은 데이터를 수집하기 위해 네트워크 Hop을 만들 필요가 없으므로 데이터 셋의 어느 부분에나 Access할때 대기 시간이 거의 없음을 의미한다.
- Hollow는 전체 데이터 집합의 폭에 Access하기 위해 CPU 비용을 줄이는데에 중점을 두고 있다. Memcached와 같이 느슨한 형식의 key/value 저장소와는 달리 구조화된 데이터 모델을 요구하면 Access 비용 문제를 한번에 해결 할 수 있다.
- Hollow는 파일 저장소를 제공한다. S3, NFS, FTP도 가능하다. Consumer는 데이터 저장소의 전체 Snapshot을 읽고 데이터 셋을 메모리로 Boot Strap한다. 데이터 셋은 Delta 적용을 통해 메모리에 최신 상태로 유지된다. 각 Consumer의 메모리 내 사본은 일시적이다. 시스템 Restart시 BLOB 저장소에서 Snapshot을 다시 검색해야 한다.
- Blob 파일의 형식은 간단하다. 메모리내의 Layout과 거의 동일한 구조이기에 데이터를 초기화하는 작업은 Blob to 메모리로 복사하듯이 이루어지며 신속하게 수행된다.
그외 Hollow에 대한 궁금증을 아래에 정리했다.
CAP 이론에 담긴 우려 사항을 해결 할 수 있는지? 간헐적인 네트워크 연결 문제가 발생했을때 오래된 데이터로 작업이 가능한지?
- Consumer는 각각 메모리에 데이터 셋의 전체 복사본을 가지고 있기 때문에 가용성은 타의 추정을 불허한다.
- 일관성에 대해서는 변화하는 데이터 셋에 대한 Timeline을 개별 데이터 상태로 분해해야 하며, 각 상태는 특정 시점의 데이터에 대한 완벽한 Snapshot을 의미한다.
Hollow는 주로 작은 메타 데이터에서만 활용되는 것인가? Local 서버의 메모리 리소스가 고갈 된 경우는 어떻게 되는가?
- Hollow는 주로 중소 규모의 데이터 세트를 대상으로 한다. Hollow는 Tera Byte, Peta Byte가 아닌 Mega byte, Giga byte에 대한 경험을 제공한다. 일반적으로 JSON형태의 문서 저장소보다 Hollow의 인코딩을 활용하여 저장할 경우 사용하는 용량이 훨씬 작다. 그래서 Tera Byte이상의 데이터 셋을 중형 데이터 셋으로 전환 하는 것을 고려할 수 있다.
- 데이터 모델링이 중요하다. 데이터가 구조화 되는 방식은 Holloww가 데이터 집합을 중복 제거 할 수 있는지, 압축률이 어떤지에 따라 영향을 미친다. 일반 압축 알고리즘은 허프만 트리를 사용하여 데이터의 패턴을 찾는 반면 Hollow는 데이터 모델의 코드 구조를 사용하여 패턴을 지정한다.
POJO에서 멀어지는 전략은 어떤 효과가 있는가?
- Hollow의 경우 중복 제거, 인코딩, 패킹 및 Java 객체의 Overhead 제거와 같은 다양한 방식으로 압축을 수행한다. 중복 제거의 방법과 범위는 주로 Zeno에서 가져왔지만, POJO에서 벗어나지 않으면 인코딩, 패킹 및 Object Overhead 제거가 불가능했다.
- Hollow는 데이터 셋의 데이터에 Access할때 CPU 영향을 최소화하고 해당 데이터를 저장하는데 필요한 Heap 공간을 최소화해야 했다.
비 Java 어플리케이션이 Hollow를 활용할 수 있는가?
- 비디오 메타 데이터용 시스템은 JVM 기반 언어를 사용하여 제작되었기에 Java용 Hollow를 구축했다. 비 JVM 기반 언어는 현재 Hollow를 활용할 수 없다.
참고: https://github.com/Netflix/hollow