In Memory Data Grid

Network/Network 2016. 8. 4. 16:31

IMDG의 특징

저장소로 디스크 대신 메인 메모리를 사용하는 것은 전혀 새로운 시도가 아니다. 디스크보더 더 빨리 수행 결과를 얻기 위해 MMDB(Main Memory DBMS)를 사용하는 사례는 일상에서도 찾을 수 있다. 대표적인 예는 휴대 전화를 사용할 때이다. SMS나 통화를 시도할 때 상대방 정보를 빠른 시간 안에 찾기 위해 대부분의 통신사는 MMDB를 사용하고 있다.

IMDG(In Memory Data Grid)는 메인 메모리에 데이터를 저장한다는 점에서 MMDB와 같지만 아키텍처가 매우 다르다. IMDG의 특징을 간단히 정리하면 다음과 같다.

  • 데이터가 여러 서버에 분산돼서 저장된다.
  • 각 서버는 active 모드로 동작한다.
  • 데이터 모델은 보통 객체 지향형(serialize)이고 non-relational이다.
  • 필요에 따라 서버를 추가하거나 줄일 수 있는 경우가 많다.

즉, IMDG는 데이터를 MM(Main Memory)에 저장하고 확장성(Scalability)을 보장하며, 객체 자체를 저장할 수 있도록 구현됐다. 오픈 소스와 상용 제품을 구별하지 않으면 다음과 같은 IMDG 제품이 있다.

이 글에서는 제품의 기능과 성능을 비교하지는 않고, IMDG의 아키텍처를 살펴보고 어떻게 활용할 수 있을지 검토해 볼 것이다.

왜 메모리?

2012년 6월 현재 SATA(Serial ATA) 인터페이스를 사용하는 SSD(Solid State Drive)의 성능은 약 500MB/s 정도이고, 고가의 PCI Express를 사용하는 SSD는 약 3,000MB/s에 이른다. 10,000 RPM SATA HDD의 성능이 약 150MB/s 정도니까 SSD가 HDD보다 4~20배 정도 빠르다고 할 수 있다. 하지만 이에 반해 DDR3-2500의 성능은 20,000MB/s에 이른다. 메인 메모리의 처리 성능은 HDD보다 800배, 일반적인 SSD보다 40배, 가장 빠른 SSD보다 약 7배 빠르다. 게다가 요즘의 x86 서버는 서버 하나당 수백 GB 용량의 메인 메모리를 지원한다.

Michael Stonebraker에 따르면 전형적인 OLTP(online transaction processing) 데이터 용량은 약 1TB 정도이고, OLTP 처리 데이터 용량은 잘 증가하지 않는다고 한다. 만약 1TB 이상의 메인 메모리를 사용하는 서버 사용이 보편화된다면, 적어도 OLTP 분야에서는 모든 데이터를 메인 메모리에 둔 채 연산을 하는 것이 가능해진다.

컴퓨팅 역사에서 '좀 더 빠르게'는 언제나 최고의 덕목으로 추구해야 할 가치였다. 이렇게 메인 메모리 용량이 증가하게 된 만큼 영구 저장소 대신 메인 메모리를 저장소로 사용하는 플랫폼이 등장할 수 밖에 없게 된 것이다.

IMDG 아키텍처

메인 메모리를 저장소로 사용하려면 극복해야 하는 약점 두 가지가 있다. 용량의 한계와 신뢰성이다. 서버의 메인 메모리의 최대 용량을 넘어서는 데이터를 처리할 수 있어야 하고, 장애 발생 시 데이터 손실이 없도록 해야 한다.

IMDG는 용량의 한계를 분산 아키텍처를 이용하여 극복한다. 여러 기기에 데이터를 나누어 저장하는 방식으로 전체 용량 증가를 꾀하는 Horizontal Scalability 방식을 사용한다. 또한 신뢰성은 복제 시스템을 구성해 해결한다.

제품마다 세세한 차이가 있지만 IMDG 아키텍처를 일반화하면 그림 1과 같이 나타낼 수 있다.

imdg1

그림 1 IMDG 아키텍처

애플리케이션 서버(AS)에는 IMDG가 제공하는 클라이언트 라이브러리가 있고, 이 라이브러리를 이용해 IMDG에 접근한다.

많은 IMDG 제품이 데이터를 RDBMS 등에 동기화하는 기능을 제공한다. 그러나 이러한 별도의 영구 저장 시스템(RDBMS 등)을 반드시 구성해야 하는 것은 아니다. 일반적으로 IMDG에서는 직렬화를 통해 객체를 저장할 수 있도록 한다. Serializable 인터페이스를 구현한 객체를 저장할 수 있도록 한 제품도 있고, 독자적인 직렬화 방법을 제공하는 IMDG도 있다. 당연히 schemaless 구조라 사용 편의성이 매우 높다.

개념상 객체를 저장하고 조회할 수 있도록 한 In Memory Key-Value Database로 이해할 수 있다. IMDG에서 사용하는 데이터 모델은 Key-Value 모델이다. 그래서 이 키(key)를 이용해 데이터를 분산시켜 저장할 수 있다. NHN에서 사용하는 분산 메모리 캐싱 시스템인 Arcus와 같이 Consistency Hash 모델을 사용하는 것부터Hazelcast와 같이 단순한 modulo 방식을 사용하는 것까지 다양한 방식이 있다. 이렇게 저장할 때 반드시 하나 이상의 다른 노드를 복제 시스템으로 삼아서 장애 발생에 대처할 수 있도록 한다.

인터페이스는 제품별로 다양하다. 어떤 제품은 SQL-like한 형태의 문법을 제공하여 JDBC를 통해 접근하는 제품도 있고, Java의 Collection을 구현한 API를 제공하는 경우도 있다. 즉 여러 노드를 대상으로 하는 HashMap이나 HashSet을 사용할 수 있는 것이다.

IMDG는 Arcus와 같은 캐시 시스템과는 사용과 목적이 다르다. 그림 2는 Arcus의 아키텍처를 간단하게 표현한 것이다.

imdg2

그림 2 캐시 시스템인 Arcus의 아키텍처

Arcus와 같은 캐시 시스템도 메인 메모리를 저장소로 사용하고 Horizontal Scalability를 확보했다는 점에서는 IMDG와 같다. 하지만 그림 1과 그림 2에서와 같이 사용 형태와 목적은 크게 다르다. 캐시 시스템에서 영구 저장소의 사용은 필수이지만, IMDG에서 영구 저장소의 사용은 선택이다.

표 1 캐시 시스템과 IMDG의 읽기, 쓰기 성능 비교

 캐시 시스템IMDG
읽기캐시 안에 데이터가 있다면 데이터 베이스에서 읽어오지 않는다. 
캐시 안에 데이터가 없을 때는 데이터베이스에서 읽어온다.
언제나 IMDG에서만 읽어온다. 항상 메인 메모리에서 읽어오기 때문에 빠르다.
쓰기영구 저장소에 쓰기 때문에 캐시 시스템 적용과 쓰기 성능 향상은 관계 없다.영구 저장소에 데이터를 동기화하도록 구성하더라도, 제품에 따라 비동기 쓰기를 지원하는 제품이 있다. 비동기 쓰기를 지원하는 경우에는 매우 높은 수준의 쓰기 성능을 기대할 수 있다.

이외에도 데이터를 마이그레이션할 수 있는지, 신뢰성을 보장하는지, 복제 기능을 제공하는지 등의 차이가 캐시 시스템과 IMDG의 차이다.

IMDG의 기능

다음은 IMDG 제품 가운데 하나인 Hazelcast의 기능이다. HazelCast는 더블 라이선스 정책을 취하고 있는 제품으로, ElasticMemory와 같은 기능을 사용하려면 상용 라이선스를 구입해야 한다. 그러나 많은 기능이 오픈소스라서 별도의 비용 없이 사용할 수 있으며, 사용 레퍼런스 정보를 찾아 보기가 매우 쉽다.

HazelCast의 기능이 다른 모든 IMDG에서 제공하는 일반적인 기능이라고 할 수는 없지만 IMDG의 기능을 살펴보기에는 매우 좋은 예라서 간단하게 소개하겠다.

DistributedMap & DistributedMultiMap

Map<?, ?>을 구현한 클래스다. 여러 IMDG 노드에 Map 데이터가 분산 배치된다.

RDBMS의 테이블(table)은 Map<Object key, List<Object>>로 표현할 수 있기 때문에, RDBMS를 샤딩해서 쓰는 것과 비슷한 데이터 분산 효과를 얻을 수 있다. 더구나 HazelCast는 DistributedMap에서 SQL-like한 기능을 사용할 수 있도록 했다. Map에 있는 value를 검사할 때 WHERE 구문이나 LIKE, IN, BETWEEN 같은 SQL-like 구문을 사용할 수 있다.

HazelCast는 모든 데이터를 메모리에 두는 것뿐만 아니라 영구 저장소에 저장하는 기능도 제공한다. 이렇게 영구 저장소에 데이터를 저장하면 캐시 시스템으로 사용하도록 구성할 수 있다. LRU(Least Recently Used) 알고리즘이나 LFU(Least Frequently Used) 알고리즘을 선택해, 꼭 필요한 데이터만 메모리에 두고 상대적으로 잘 찾지 않는 나머지 데이터는 영구 저장소에 두게 할 수도 있다.

또한 MultiMap을 분산 환경에서 사용할 수 있도록 했다. 어떤 key를 조회하면 Collection <Object> 형태의 value 목록을 얻을 수 있다.

Distributed Collections

DistributedSet이나 DistributedList, DistributedQueue 등을 사용할 수 있다. 이런 Distributed Collection 객체에 있는 데이터는 어느 하나의 IMDG 노드가 아니라 여러 노드가 분산 저장된다. 그렇기 때문에 여러 노드에 저장된 단 하나의 List 객체 또는 Set 객체 유지가 가능하다.

DistributedTopic & DistributedEvent

HazelCast는 publish 순서를 보장하는 Topic 읽기가 가능하다. 즉 분산 Message Queue 시스템으로 이용할 수 있다는 뜻이다.

DistributedLock

말 그대로 분산 Lock이다. 여러 분산 시스템에서 하나의 Lock을 사용해 동기화할 수 있다.

Transactions

DistributedMap, DistributedQueue 등에 대한 트랜잭션을 사용할 수 있다. 커밋/롤백을 할 수 있기 때문에 더 신중한 연산이 필요한 곳에서도 IMDG를 사용할 수 있다.

대용량 메모리 사용과 GC

앞에서 소개한 대부분의 제품은 구현 언어로 Java를 사용한다. 수십 GB 크기의 힙을 사용해야 하는 만큼 Full GC에 필요한 시간도 상당히 오래 걸릴 수 있다. 그렇기 때문에 IMDG에서는 이런 제약을 극복할 수 있는 방법을 마련해 적용하고 있다. 바로 Off-heap 메모리(Direct Buffer)를 사용하는 것이다.

JVM에 Direct Buffer 생성을 요청하면 JVM은 힙 바깥의 공간에서 메모리를 할당해 사용한다. 이렇게 할당한 공간에 객체를 저장하도록 하는 것이다. Direct Buffer는 GC 대상 공간이 아니기 때문에, Full GC 문제가 발생하지 않게 된다. 보통 Direct Buffer에 대한 접근은 Heap Buffer보다 느리다. 하지만 큰 공간을 할당할 수 있고 Full GC에 대한 부담을 줄일 수 있기 때문에 매우 큰 용량의 메모리 공간을 사용할 때 Full GC 시간을 없앨 수 있어 항상 일정한 처리 시간을 확보할 수 있다는 것이 장점이다.

imdg3

그림 3 Heap Buffer와 Direct Buffer 디스크 비교(이미지 출처: Terracotta)

그러나 Direct Buffer를 이용해 객체를 저장하고 조회하는 데는, Memory Allocator를 만드는 것과 같은 매우 전문적인 기술이 필요하다. 그렇기 때문에 이러한 Off-heap 메모리를 사용해 객체를 저장하는 기능은 상용 IMDG에서만 제공하고 있다.

마치며

현재까지 IMDG를 주로 사용하는 곳은 캐시 시스템이다. 그러나 IMDG는 주저장소로 발전될 가능성이 매우 높은 플랫폼이다. 많은 경우 분산 Map은 충분히 RDBMS의 테이블을 대신할 수 있다. 제품에 따라 분산 Lock을 제공하는 제품이 있는데, 이런 분산 Lock을 바탕으로 정합성(Integrity Constraint) 기능을 제공할 수 있다면, 본격적으로 RDBMS를 대체할 수 있다.

이렇게 할 경우 백엔드 시스템으로 RDBMS를 사용해 통계 처리에 대응할 수 있을 것이다. 인터넷 서비스에서 RDBMS 사용이 보조 목적으로 바뀌는 것이다. 정합성 기능이 제공된다면 빠른 속도를 바탕으로 한 쾌적한 사용자 경험은 물론, 빠른 처리 속도를 바탕으로 그동안 제공하기 어려웠던 기능을 제공할 수 있는 기회가 생기는 것이다.

imdg4

그림 4 정합성을 지원하는 IMDG


출처 - http://d2.naver.com/helloworld/106824

: