Monthly Archives: November 2011

[책 리뷰] 인생은 속도가 아니라 방향이다.

웬지 제목이 멋있어서 읽게 되 책, 지은이는 한국인이 아니지만, 한국에 오래 산 미국인, 임마누엘 페스트라이쉬 라는 경희대 교수님이시다.

 

외국인의 눈으로 우리 사회를 본다는 것이 독특한 시각일 것 같지만, 도리어, 의외로 깊은 곳까지 제대로 들여본 것 같다.

 

자신이 생각하는 교육의 모습과,  자신이 받은 교육, 그리고 자식들에게 하고 있는 교육의 방식을 보여주는데, 애기도 없는 나지만, 꽤 공감이 간다고 할까나?

 

그러면서 나도 의문이 들었다. 한국의 대학생이나 대학원생들은 MT를 가면 왜 술만 마시고 노는걸까?, 저자의 경험으로 미국의 대학생( 상위 10%는 미국이 훨씬 낫고, 하위 40%는 한국이 낫다라는 저자의 의견이 있다. ) 들은 MT를 가면, 철학적 인문학적, 기술적  내용에 대한 깊은 토론을 하면서, 시간을 보낸다고 한다. 왜 이런 차이가 나는 것일까?

 

동양의 문화는 서양을 경외시하고, 서양의 문화는 동양의 문화를 경외시하는 그런 부분도 흥미롭다.  기억에 남는 몇가지가, 우리의 문화를 누군가에게 설명할 때, 이게 국보다,  보물이다는 중요하지 않다는 것, 백제 시대의 유물에 코끼리가 있는 것을 보여주며, 이 시대에 코끼리는 국내에 없었지만, 외국 어디와 교역을 해서, 선물로 받았거나, 해당 동물에 대한 지식을 얻었고, 이 지식이 다시 일본으로 전파되었다 등의 이런 내용에 더 관심을 가진다는 것… 정말 중요한 본질을 우리는 도리어 신경쓰지 않고, “타이틀” 이라는 것에만 관심을 가지는 건 아닐까? 그리고 이 모습이 현재 우리의 모습에 여전히 남아있는 것처럼 보인다.

 

인문학, 인문학 하지만, 인문학이란, 노자가 어떻고, 장자가 어떻고, 러셀이 무엇을 말했는가가 아니라,  그들이 어떻게 사유하게 되었고, 의문을 가졌는가를 배우고, 나는 어떻게 사유해야 하는지에 대한 “영원한 물음” 이 아닐까라는 생각을 들게 해준 책이다.

Memcached 에서의 Consistent Hashing

오늘은 제가 자주 사용하는 Memcached의 Consistent Hashing 에 대해서 알아보려고 합니다.( 자주 쓰기는 하는데, 내부를 잘 알지는 못해서 헛소리를 찍찍 할 수도 있지만, 실력이 모자란거니, 저런 모자란 넘 하시면서 웃으면서 넘어가시면 좋겠습니다. 어차피 욕하셔도, 전 상처받지 아니합니다. 그냥 일기에, 그분 이름 빨간색으로 좀 적어두고, 죽을때까지 기억하기만 할꺼예요. 전 쿨하니깐요. )

제가 가장 좋아하는 기술에 접근 방법은, 왜 이런 기술이 나왔는가? 왜 필요한가? 그래서 어떻게 구현되었는가? 이런순으로 따라가는 겁니다. 왜 필요한지? 문제가 무엇인지? 그래서 어떻게 해결하는지에 알아야만, 저는 그제서야 살짝 이해를 하기 시작합니다.(머리가 나빠서 사실 제대로 이해못하는다는데 제 주둥이를 건다는 쿨럭…)

Why Need Consistent Hashing?

Wikipedia 에서 Consistent Hashing 을 찾아보면 다음과 같은 내용이 나옵니다.

History

Originally devised by Karger et. al. at MIT for use in distributed caching. The idea has now been expanded to other areas also. An academic paper from 1997 introduced the term “consistent hashing” as a way of distributing requests among a changing population of Web servers. Each slot is then represented by a node in a distributed system. The addition (joins) and removal (leaves/failures) of nodes only requires K / n items to be re-shuffled when the number of slots/nodes change.[1]

This same concept, however, appeared in 1996 within the Super Proxy Script technique created by SHARP for optimizing use by web browsers of multiple caching HTTP proxies.[2]

Consistent hashing has also been used to reduce the impact of partial system failures in large Web applications as to allow for robust caches without incurring the system wide fallout of a failure.[3]

The consistent hashing concept also applies to the design of distributed hash tables (DHTs). DHTs use consistent hashing to partition a keyspace among a distributed set of nodes, and additionally provide an overlay network that connects nodes such that the node responsible for any key can be efficiently located.

 

영어가 어렵습니다. 간단하게 바꾸면, MIT의 karger 라는 사람이 웹 서버 수가 변화하는 가운데분산 리퀘스트를 처리하기 위해서 고안했다고 합니다. 이게 무슨 소리일까요? 간단하게 설명하자면 [그림 1]과 같은 상황입니다. K는 요청하는 유저 수, N 은 웹 서버의 수입니다.

[그림 1] User Request 를 Proxy 가 각 서버로 분배하는 상황

그런데, 여기서 [그림 2] 처럼 서버가 몇 대가 장애가 나고 수시로 추가된다고 합시다.

[그림 2] 한대의 서버가 장애로 인해서 서비스 제외된 상황

이렇게 되면 계속 들어오는 리퀘스트 들은 나머지 4대로 분배되게 됩니다. 이걸 보면 이게 무슨 문제가 있냐고 생각을 하게 됩니다. 사실 별 문제 없습니다. 단순히 각각의 리퀘스트 들이 전혀 연관관계가 없다면 말입니다. 이미 세션이 연결되어 있어서 각각의 유저는 기존의 서버로 연결되기를 원하는 상황이 된다면, 조금 문제가 복잡해질 수 있습니다.( 뭐, 해당 유저가 전에 어느 서버로 갔었는지 기억해두고 있다가 매번 그곳으로 보내주는 방식도 있지만, 이건 유저 별로 여분의 추가 작업이 필요합니다. ) 즉, 전체 사용자들이 서버 수에 맞춰서 다시 재분배 된다는 겁니다. 이건 데이터가 추가될 때도 마찬가지 현상이 발생합니다.

그럼 Consistent Hashing이 어떤 기능을 하는지 유추가 되시나요?(오오, 천재시군요. 전 유추 못하는데…) 즉, Consistent Hashing 은 서버의 개수, 즉 슬롯의 개수가 변화하더라도, 전체 데이터에 대한 재분배가 필요 없고, K/N 개의 아이템만 재분배를 하면 되는 방식입니다. 앞에서 서버가 5대 였으니, 한 대당, 20000명을 처리하고 있었는데, 한대가 장애가 나면, 이 20000 명만 서버를 재분배하고 나머지 유저들은 기존 서버에서 그대로 처리가 됩니다.

오오오, 대단히 재미난 기술 인거 같지 않습니까? 그럼 어떤 방식으로 처리가 되는 것일까요? 여기에는 HashRing 이라는 개념이 들어갑니다. Ring 이라는 게, 둥근 것, 즉, 꼬리에 꼬리는 무는 해시라고 해야될까요?

Consistent Hasing

먼저 A,B,C,D 서버가 4대가 있다고 가정합니다.( 아, 그림 그리기 힘드네요. 서버 수를 더 줄이줄 좋을 것 같습니다. T.T, 4대도 많아요 )

[그림 3]과 같이 처음에는 서버 한대만 존재한다면, 모든 리퀘스트는 해당 서버로 가게 됩니다.

[그림 3] HashRing 에 A 서버가 등록된 상황

 이 상황에 서버 B, C 가 추가되어서 [그림 4] 처럼 3대가 되었다고 하겠습니다.

[그림 4] HashRing 에 A, B, C 서버가 등록된 상황

 

이제 해당 서버에 들어오는 Key 들이 해시값이 A < Key <= B 라고 한다면,(아, 수식을 다 써보는군요.) 해당 Key는 자기보다 크고, 가장 가까운 서버로 할당이 됩니다. 즉, 여기에 Key 1이 들어왔다면, A < 1 <= B 라면 1은 B 서버에 저장됩니다. [그림 5]와 같습니다.

[그림 5] HashRing 에 A < 1 <= B 인 Key 1이 들어온 상황

자 이제 Key의 해시값이 B < 2 <= C 인 Key 2가 들어왔다고 합시다. 예상대로 [그림 6]과 같습니다.

[그림 6] HashRing 에 B < 2 <= C 인 Key 2이 들어온 상황

 이제 엄청 데이터가 많이 들어와서 [그림 7]과 같은 최종 모습이 되었다고 합시다.

[그림 7] 데이터가 최종적으로 들어 온 모습

이제 여기서 장애로 서버 B가 서비스를 하지 못하는 상태가 되었다고 가정합니다. 서버 B가 장애가 났으므로, Key 1은 유실이 됩니다. [그림 8]의 상황입니다.

[그림 8] 서버 B의 장애로 인해서 HashRing에서 B가 제거된 상황

Consistent Hashing 이 아니라면 [그림 8]의 장애 상황에서 전체 Key가 재조정되어야 할 수도 있습니다. 하지만 Consistent Hashing 방식을 이용하므로 Key 5를 요구하면 5의 해시값이 A < 5 <= C 가 되므로 해당 서버가 그대로 서비스를 하게 됩니다. 그럼 이때 원래 B로 할당되어야 했던 Key 1이 다시 들어오게 되면 어떻게 될까요? 예상하듯, A < 1 <= C 가 되어 버리므로 [그림 9] 와 같이 C로 할당되게 됩니다. (전 솔직히 예상 못했었어요 T.T )

[그림 9] 서버 B의 장애 상황에서 Key 1이 들어온 경우

 

 이런 식으로 Consistent Hashing 은 서버의 추가/장애시 K/N 의 Key만 재 분배 하면 되도록 되어있는 알고리즘입니다. Memcahed 에서 이런 방식을 사용하고 있습니다. 정확하게 하자면, memcached Client Library 에서 이렇게 키를 저장할 서버를 선택합니다. 자, 예제 1의 간단한 파이선 코드를 보시죠. 현재 Local에 20001, 20002, 20003, 20004 포트를 이용하는 memcached 서버 4대를 실행시켜 두었습니다.( python-memcached 모듈이 필요하므로, pip install python-memcached 로 설치하시기 바랍니다. )

 

import memcache 

ServerList=[ '127.0.0.1:20001', '127.0.0.1:20002', '127.0.0.1:20003', '127.0.0.1:20004' ]

 

if __name__==’__main__’:

    mc = memcache.Client( ServerList );

 

    for idx in range(1,100):

        mc.set( str(idx), str(idx) )

[예제 1] 간단한 1부터 100까지 memcached 에 저장하는 예제

 

 해당 코드를 실행한 후에 각각의 memcached 서버에 붙어서 확인해보면, 1~100 까지의 값들이 서버 4대에 분배되어 있는 것을 볼 수 있습니다.(고르게는 아니더군요 ^^) 확인 하는 방법은 다음과 같습니다.

 

charsyam@ubuntu:~$ telnet 127.0.0.1 20001Trying 127.0.0.1…

Connected to 127.0.0.1.

Escape character is ‘^]’.

get 1

VALUE 1 0 1

1

END

실제로 memcached 의 c client library인 libmemcached 의 소스를 보면 memcached_send 라는 함수가 있고, 이 안에 memcached_generate_hash_with_redistribution 라는 함수 안에서 key의 해시 값을 구하고, 해당 값이 포함되어야 하는 서버의 해시 값을 알려주게 됩니다.

uint32_t memcached_generate_hash_with_redistribution(memcached_st *ptr, const char *key, size_t key_length)

{

uint32_t hash= _generate_hash_wrapper(ptr, key, key_length);

_regen_for_auto_eject(ptr);

return dispatch_host(ptr, hash);

}

Memcached 를 이용할 때의 주의 사항

일반적으로 Consistent Hasing 을 사용하면 큰 문제가 없을 것 같지만, 간혹, 장비의 추가나, 삭제 상황에서, Old Data 가 남아있어서 이 값을 가져가게 되는 이슈가 발생할 수 있습니다. 어떤 상황에서 발생하게 될까요?(똑똑하신 분들은 이미 이해하셨을 테고, 저 같은 사람은 누가 알려주고, 설명을 해줘도 이해가 안가는 경우가 쿨럭…)

이전 [그림 8,9] 에서 한대의 서버가 장애가 나면, B로 들어가야 할 데이터만 다시 C로 들어가게 된다고 했습니다. 그럼 이 상황에는 원래 B일 데이터가 C에 저장됩니다. 그런데 다시 B가 복구가 되어서 HashRing 에 들어왔다고 가정합니다. 그럼 무슨 일이 발생하게 될까요? 끔직한 일? 힘든 일? 상상도 하기 싫은 일?, 정답은 아무 문제 없습니다.(헉, 어디서 돌이!!!) 당연히 뭔가 문제가 있었다면 이거 쓸 수가 없겠죠. 장애는 언제든지 발생하는 데 말입니다.

이 때, 다시 Key 1이 들어온다면 [그림 10]과 같은 상황이 벌어집니다. 그러나 Key 1의 해시는 B에 속하게 되므로, 데이터를 요청해도 C의 1이 응답으로 나가는 문제는 당장 발생하지 않습니다. 그로 인해 서비스는 문제 없이 잘 돌아갑니다. 여기서 문제가 되는 상황은 서버 B가 또 다시 장애가 나는 [그림 11]과 같은 상황입니다. 기존에 C 서버에 Old Key 1이 남아있던 걸 기억해야 합니다.

[그림 10] 서버 B의 복구 후 다시 Key 1이 들어온 경우

[그림 11] 서버 B의 재 장애 케이스

이 경우 Key 1을 요청하면 C 서버의 Old Key 1이 반환되어서 실제로 새로운 값이 아닌 오래된 값이 나갈 수 있습니다. 다만 memcached 를 목적에 맞게 사용하면 Key의 ExpireTime 이 지나서 사라지기 때문에 전혀 문제가 없을 수 있습니다. 위와 같은 문제는 ExpireTime 이내에 같은 서버가 다시 장애가 났을 때만 발생하는 문제입니다. (혹시나 해결책을 물어보신다면, 같은 장애가 발생했을 때, memcached의 해시 코드를 가져와서 실제로 남아있어야 하는 서버 이외에는 delete 를 호출하는 방법밖에 없습니다. 아니면 ExpireTime을 짧게 가져가면 쉽게 해결될 수도 있습니다.)

정리하며…

간단하게 Memcached 에서 사용하는 Consistent Hashing 과 이로 인해 발생할 수 있는 문제점에 대해서 간단하게 살펴보았습니다. 혹시나 틀린 내용이 있으면, 저에게 알려주시기 바랍니다.

왜 아마존 AWS가 다른 경쟁사들 보다 좋은가요?

해당 내용은 Quora에 올라온 글(http://www.quora.com/In-what-ways-is-AWS-better-than-most-of-its-competitors/answer/Randy-Bias?srid=wYA) 을 발번역한 내용입니다. 오역에 주의하세요. 번역하고 보니 밑에, 다른 분들의 답변도 더 있는데 Randy Bias 씨의 답변만 번역했습니다.

 

왜 아마존 AWS가 다른 경쟁사들 보다 좋은가요?

 

Randy Bias( CloudScaling CEO – 아마존에서 AWS를 구축하고 KT의 클라우드 시스템도 구축하신 분입니다.)

아마존은 다음과 같은 이유로 다른 경쟁사들 보다 좋습니다.

1.  아마존은 전통적인 데이터 센터 환경을 재현할려고 하지 않습니다.

2. S3, EC2, SQS 등의 확장성 있고, 강건한 서비스를 이용해서 초기 서비스를 쉽고 간단하게 만들 수 있습니다.

그리고 RDS, EMR 등의 고 주수준의 서비스를 좋바할 수 있습니다.

3.  아마존의 비즈니스 모델은  고정 마진으로 아마존의 비용이 많이 들면,  비용도 비싸게 측정이 되므로, 비용이 줄어들면, 가격도 줄어들게 됩니다.

4.  2~3년 의 긴 고민과 로드맵을 가지는 엔지니어링 문화로 인해서 작업의 범위와 기능 출시 속도를 따라잡기 힘듭니다.

5.  불필요한 기능들을 피하고 간결함, 보안성, 확장성,  안전성에 집중합니다.

 

나는 1번이 나머지의 결과라고 말하고 싶습니다. AWS 경쟁자들은 클라우드 컴퓨팅은 현존하는 데이터센터안에 가상화와 자동화의 조합으로 구현된다고 믿습니다. 이게 진실이라면, 아마존과 같거나 비슷한 수준으로 성공한 경쟁자가 있어야 합니다. 불행히도, 아무도 없습니다.

 

그 이유는 클라우드 컴퓨팅은 IT의 패러다임의 변화이기 때문입니다. 이것은 메인프레임에서 클라이언트/서버 구조로 넘어간 것과 비슷합니다.  전체  IT 구조는 아마존, 구글, 페이스북과 같은 인터넷 거인들로 부터 다시 디자인되었습니다. 새롭게 디자인된 IT 구조는 차세대 어플리케이션, 확장성, 안전성 등에 초점을 맞춥니다. 좀더 통합되고 어플리케이션과 인프라에 대한 전체적인 접근입니다. 현존하는 데이터 센터와는 완전히 다르게 보입니다.

 

대부분의 아마존 경쟁자들은 미래의 구조가 아닌 과거의 구조를 구축하고 있습니다.

 

[책 리뷰] 카산드라 완벽 가이드 – 원서보다 최신의 번역서

현재 NoSQL 카산드라 책은 원서로 딱 2권이 있습니다. 한권이 Cassandra High Performacne Cookbook (http://www.amazon.com/Cassandra-Performance-Cookbook-Edward-Capriolo/dp/1849515123/ref=sr_1_2?s=books&ie=UTF8&qid=1321701626&sr=1-2) 이라는 책이고 나머지 한권이 O’relly에서 유명한 Cassandra The Definitive Guide 바로 이 책의 번역서 입니다.

사실 원서의 내용은 0.7 베타 버전을 대상으로 작성이 되어있어서( 최신버전 1.0.3이 바로 어제(2011/11/18) 릴리즈되었습니다.  사실 카산드라의 버전을 단순히 높은 것이 좋다라고 말하기는 힘들지는 현재 대세가 0.8.6( 0.8.7 까지 나오고 있고, 현재 0.7 버전은 0.7.10 까지 계속 나오고 있습니다. 버전이 높을 수록 새로운 기능이 들어가긴 하지만, 다른 버전이 무조건 나쁘다고 할 수 없는 구조입니다.) ) 원서의 내용을 그대로 역자분들이 번역을 하셨다면, 별 의미가 없는 책이 될 뻔 하였지만, 역자분들이 예제와 책의 내용을 0.8.x 버전대로 다시 바꾸고 수정하셔서 원서보다 더 최신의 번역서라고 감히 말씀드릴 수 있을 듯 합니다.

사실 0.7 베타까지는 Secondary Index(0.7에 추가) 와 CQL(0.8에 추가, Cassandra Query Language <– 일종의 SQL like) 가 없었기 때문에 이쪽 부분이 추가되는 건 쉽지 않은 번역이었을 것 같습니다. 역자분들에게 박수를~~~

일단 내용 자체는 “The Definitive Guide” 답게, 메뉴얼 같은 느낌입니다. 다만, 카산드라를 도입하고자 하는 사람들은 꼭, 3장 5장을 주의깊게 읽어보시길 바랍니다. (그렇게 심도 있게 있지는 않지만, SSTable이라든지 블룸필드라든지 기본적으로 알고 넘어가야할 내용들이 나옵니다.)

NoSQL 의 경우 현재 mongodb와 hbase가 강력한 텃세를 부리고 있긴 하지만, Cassandra도 Netflix 등의 대형 업체에서 엄청 잘쓰고 있기 때문에, 굉장히 좋은 솔루션입니다.( P2p 모델이라 hbase 와 는 또 다른 장점이 많습니다.)

이 책을 다 읽고 숙독한다고 해서, 카산드라를 완벽하게 다룰 수 있는 것은 아닙니다. 다만, 이 책의 내용 정도는 알아야, 이제 삽질할 준비가 되어있다라고 말할 수 있습니다.

간단한 mongodb 2.0.1 replSet 설정 방법(localhost 일때)

start.sh 보통 3대의 구성으로 많이 이용하는 듯 합니다.

#!/bin/sh

/home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db1 –port 10001 –replSet charsyammongo/localhost:10002 &
/home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db2 –port 10002 –replSet charsyammongo/localhost:10001 &
/home/charsyam/mongo/mongod –dbpath /home/charsyam/data/mongodb/db3 –port 10003 –replSet charsyammongo/localhost:10001,localhost:
10002 &

 

이렇게 실행만 시키면 다음과 같은 오류가 나기 시작합니다.

Sat Nov 19 00:41:48 [rsStart] trying to contact localhost:10002
Sat Nov 19 00:41:48 [rsStart] replSet can’t get local.system.replset config from self or any seed (EMPTYCONFIG)
Sat Nov 19 00:41:49 [rsStart] trying to contact localhost:10001
Sat Nov 19 00:41:49 [rsStart] replSet can’t get local.system.replset config from self or any seed (EMPTYCONFIG)
Sat Nov 19 00:41:49 [rsStart] trying to contact localhost:10001

 

이제 mongo localhost:10001 로 접속을 하고 다음과 같이 입력합니다.

config = {_id: ‘charsyammongo’, members: [
{_id: 0, host: 'localhost:10001'},
{_id: 1, host: 'localhost:10002'},
{_id: 2, host: 'localhost:10003'}]}

rs.initiate(config)

 

그러면 자기들 끼리 마스터를 선출하기 시작합니다.

이제 에러로그가 다음과 같이 바뀝니다.

 

Sat Nov 19 00:42:27 [rsHealthPoll] replSet member localhost:10001 is now in state PRIMARY
Sat Nov 19 00:42:27 [rsHealthPoll] replSet member localhost:10003 is now in state RECOVERING
Sat Nov 19 00:42:27 [rsHealthPoll] replSet member localhost:10001 is now in state PRIMARY

 

설정 끝!!!

 

AWS에서 Cassandra의 확장성 벤치마킹 – 초당 백만 Write 넘기기.

해당 내용은 http://techblog.netflix.com/2011/11/benchmarking-cassandra-scalability-on.html?showComment=1320770246977#c4531619651000909465 을 발번역한 내용입니다. 오역에 주의하세요.

(역자 주: 해당 데이터가 매우 좋은 Article이지만, 컬럼 패밀리가 여기서 사용하는 것보다 많거나( 해당 테스트는 Write당 10개의 Column Famliy를 이용합니다. ) 테스트를 오래 돌리는 경우, GC 발생, 또는 Compaction 으로 인해서 속도가 맞지 않을 수 있습니다. 카산드라를 도입하실려면, 실제 데이터로 BMT를 해보고 해당 속도를 기준으로 용량 산정을 하는 것을 권장해 드립니다.  카산드라 설정뿐만 아니라, GC등의 JVM 설정도 매우 중요합니다. )

Netflix 는 지난 6개월 이상 아파치 Cassandra NoSQL을 사용하고 있습니다.  해당 벤치마크는 최근에 진행하기로 결정된 카산드라의 성능 특성과, 우리의 툴들과 자동 확장성을 검증하기 위한 테스트의 일부분입니다. Adrian 이 지난주에 해당 결과에 대해  High Performance Transaction Systems workshop에서  발표하였습니다.

Write에 집중된 벤치마크로 Cassandra 패키지의 일부인 Standard Cassandra “Stress” Tool 을 선택했습니다. Denis는 Amazon EC2 에서 해당 테스트를 하고, 분석을 하였습니다. Read 벤치마크는 Memory Cache를 이용하는 반면에 Write 부하는 모두 Disk를 이용합니다. 해당 벤치마크의 결과는 누구나 재현할 수 있습니다. 그러나 Netflix cloud paltform automation for AWS는 이런 종류의 테스트를  더욱 쉽고 빠르게 합니다.

Netflix에서 개발한 자동화 툴은 대규모의 Cassandra cluster을 빠르게 배포할 수 있습니다. 이 경우에, 웹페이지에서 단순한 클릭 몇번으로 한 시간에 US-East 지역의 3개의 EC2 availability zones 에 각각 96개의 instance로 구성된    288 개의 중간 규모 장비의 Cassandra cluster를 구성할 수 있습니다. 그리고 초당 110만의 클라이언트 Write의 부하를 만들 테스트 프로그램을 구동하기 위해서 60개의 인스턴스를 추가합니다. 데이터가 자동으로 3개의 Zones 에서 복제되면서 330만의 Write 를 Cluster 내에서 발생합니다. 전체 테스트는 수백 달러에 2시간 정도면 완료할 수 있습니다. 그리고 이 EC2 instance 들은 테스트 기간만 존재합니다. 설정시간도 없고, datacenter의 공간에 대해 IT 관리자와 논의할 필요도 없고, 테스트가 끝나면 추가적인 비용도 들지 않습니다.(역자 주: 완전 EC2 자랑이네요 ㅎㅎ)

확장성을 측정하기 위해서, 48, 96, 144, 288 인스턴스에서 클라이언트는 10,20, 30, 60 순으로 같은 테스트를 진행했습니다.. 각 instance의 로드는 모든 케이스에서 거의 유사합니다.  그리고 처리양은 instance 수에 따라 선형적으로 증가했습니다.  이전 벤치마크와 제품 출시 때는 6대 부터 48대의 instance 로 Cassandra Cluster를 구성한 적이 있었습니다. 그래서 우리의 배포했던 최대 규모보다 6배나 증가된 규모의 결과를 볼 수 있어서 기뻤습니다. 이 벤치마크는 5일동안 다른일을 하는 사이에 비는 시간을 이용해서 Cassandra 0.8.6의 표준  설정과 테스트 계정을 이용해서 기획부터 결과까지 진행하였습니다. EC2에서 288개의 instance를 생성하는데는 전체 66분 중에 15분 정도 걸렸습니다. 나머지 시간은 Linux 실행  자동화 툴을 실행하기 위해 Apache Tomcat을 시작, Cassandra JVM 시작,  Cassandra Data Store의 ring에 참여하기 위해서 사용하였습니다.( 역자 주: Cassandra라는 DHT 방식으로 서버들끼리 Token을 가지고 이 Token 값을 이용하여 데이터의 위치를 결정합니다. 새로운 서버가 추가되면, 이렇게 Ring 을 교환하는 작업이 필요합니다.)  추가로 일반적인 12개의  instance 로 Cassandra Cluster를 구축하는데는 8분이 걸렸습니다.

Netflix cloud systems group 에서는 최근에 Cassandra의 컴포넌트 성능의 특성에 초점을 맞추는 Cloud Performance Team을 신설했습니다. 그리고 타 팀에서 그들의 코드를 작성하게 하고 AWS 사용을 효율적으로 해서 Netflix와 고객의 비용을 줄여주고 있습니다. 현재 해당 팀에서는 엔지니어를 추가로 구하고 있습니다.(http://www.netflix.com/Jobs?id=7563&jvi=oq8xVfwK)

TL;DR

이 문서의 나머지 부분은 무엇을 수행했고, 어떻게 동작했는지에 대한 자세한 내용입니다. AWS에서 Cassandra를 사용하는 다른 퍼포먼스 팀이 우리의 결과를 확장하거나, 따라할 수 있습니다.

EC2 Configuration

테스트에서 Cassandra를 구동하는 EC2 instances는 M1 Extra Large(m1.xl) 모델입니다. 4개의 중간 속도의 CPU, 15GB RAM, 그리고 각각 400GB의 디스크를 4개 가지고 있습니다. CPU의 성능은 아마존의 8Units에 해당합니다. 흔히 Cassandra에서 사용되는 다른 instance type은 m2 quadruple extra large(m2.4xl) 입니다. 빠른 8개의 CPU, 68GB RAM, 그리고 2개의 800GB 디스크를 가지고 있습니다. 총 26개의 CPU unit을 가집니다.  이 장비들은 주로 많은 데이터를 메모리에 저장해서 읽기 특화된 작업을 위해 사용합니다. 그리고 하나의 Gigabit 네트웍을 가지고 있습니다.  Cluster Compute  Quadruple Extra Large(cc.4×1) 은 빠른 8개의 CPU(총 33.5 units), 23GB RAM, 두개의 800GB 디스크를 가지고 하나의 10GigaBit 네트웍을 가집니다.  아직 이 장비는 써본 적이 없습니다. 이번 테스트에, 우리는 주로 우리의 툴을 검증하기 위해서 인스턴트 숫자를 늘리는 것에 관심을 가졌습니다. 그래서 small instance option을 선택했습니다.  4개의 Disk는 CentOS 5.6 md 와 XFS를 이용해서 함께 Stripe 되었습니다.(역자주, 레이드 구성되었다는 뜻입니다.) Cassandra commit Log와 데이터는 모두 이 파일시스템에 저장되었습니다.

client 로 부하를 주기위한 60대의 장비는 Single Availability Zone 에서 구동되는  m2.4xl 타입입니다. 그래서 30대씩 두 조로 나뉘어서 다른 Zone으로 부하를 주었습니다. 이는 client latency가 약간 증가했다는 것을 의미합니다.

모든 instance는 EC2 Auto-Scaler 특성을 이용해서 생성되었습니다.  하나의 요청은 요구한 사이즈의 하나의  Auto-Scale Group(ASG)  로 구성된다. Amazon Machine Image(AMI) 는 Cassandra 0.8.6 과 Netflix의 특별한 도구들로 구성되어 있다. 세 개의 ASG가  각각의 데이터센터가 떨어진, 1 밀리센컨 정도의 Network Latency를 가지는  Availability Zone으로 생성된다.  EC2는 자동적으로 각각의 존에 설정된 레벨만큼  instance를 생성한다. 어떠한 이유라도 instance가 죽으면, ASG는 자동적으로 대체 instance를 생성하고 Cassandra Cluster의 해당 노드를 교체한다. 모든 데이터는 3가지 방식으로 복제된다. 그 중에서 3개의 서로 다른 데이터센터를 이용하는 것이 매우 가용성을 높여준다.

작은 Cassandra ASG 설정 페이지의 스크린샷입니다. size 필드를 수정하고, 어떠한 사이즈의 클러스터도 생성할  있도록 변경 사항을 기록한다.

Netflix Automation for Cassandra -Priam

(카산드라를 위한 Netflix 자동화 – Priam )

Netflix에서는 백업을 하고 이를 S3(Simple Storage Service)에 저장하는 자동화를 구현했습니다. 그리고 다운 타임 없이 새로운 버전의 카산드라로 업그레이드 할 수 있도록 했습니다.  카산드라가 구동되는 중에, 카산드라 클러스터를 효과적으로 2배로 늘리는 것도 가능합니다. 각각의 새로운 노드들이 기존 노드들의 데이터를 나눠가질 때, 너무 많은 재섞임이 일어나지 않도록 합니다. (역자 주: 카산드라의 경우 데이터가 DHT 방식으로 나눠가지게 되는데, 새로운 노드가 들어오면,  데이터가 가야 할 서버의 키가 바뀔 수 있습니다. 이로 인해, 각 서버들이 각각의 데이터를 새로운 서버에 넘겨주는 과정이 발생하게 됩니다. 이로 인해, 여러 서버가 추가되면, 데이터가 새로운 서버에서 다시 이동하는 현상이 일어날 수 있습니다. 이를 reshuffle 이라고 합니다.) 한 노드가 장애가 발생하면, 다른 IP로 교체하게 됩니다. 그러나 우리는 새로운 장비가 같은 토큰을 가지기를 원했고,  원래의 카산드라 교체 메커니즘을 이 케이스를 명확히 다루기 위해서 확장해야만 했습니다.  그리스 신화의 카산드라 아버지의 이름에서 따와 이 자동화를 “Priam” 이라고 명했습니다. “Priam”은 각각의 Apache 톰캣 JVM에서 동작하고,  현재 Netflix 에만 맞는 코드들을 제거하는 중이며,  올해가 지난 뒤에 오픈 소스로 공개할 예정입니다.  이미 GitHub에 Curator 라는 Zpache Zookeeper interface를 공개했습니다.  Astyanax( Hector의 아들이자, 카산드라의 형제입니다. Hector는 Apache Zookeeper 의 자바 클라이언트 이름입니다. ) 라는 자바 클라이언트를 공개할 예정입니다.  우리는 그리스 신화에서 이름을 따옵니다.

Scale-Up Linearity

(선형적인 스케일 업)

선형적 확장성은 아래 차트에서 보여줍니다. 각 클라이언트 시스템은 초당 17,500  Write 요청을 생성합니다. 그리고 트래픽을 늘리는데 병목이 없습니다. 각 클라언트는 200개의 thread를 트래픽을 생성하기 위해서 이용합니다.


P er-Instance Activity

(인스턴스별 활동)

다음 과정은 병목을 찾기 위해서 각 인스턴스별 평균 활동을 살펴보는 것이다.  아래 표에 정리되어 있다.

서버별 Write 는 우리가 기대했던 것과  비슷하다.  평균 Latency는 선형적 확장이 가능하다는 것을 보여준다. 응답시간은 클라이언트에서 대략 11ms 그리고 1.2ms 정도가 네트웍 Latency 와 thrift client library 의 부하 그리고  응답을 위한 thread의 지연된 스케줄링 때문입니다. 우리의 카산드라 Cluster 에서 복잡한 읽기, 쓰기 연산의 서버의 평균 Latency는 대략 1ms 입니다. CPU Load는 가장 큰 288 Nodes의 Cluster 가 조금 높은 편입니다.  테스트를 한번만 수행했기 때문에, m1.x1 instance typ의  디테일한 스펙의 변화나, 큰 Cluster 에서의 컨넥션등의 증가로 인한 단순한 테스트의 변동성 때문입니다. 디스크 Write 는 Commit Log 쓰기와 순차적인 SSTable Writes 때문입니다. 디스크 Read는 백그라운드로  카산드라 SSTable 을 합치는 Compaction 작업 때문입니다. 네트웍 트래픽은  카산드라의 내부 replication 메시지 때문입니다.

Costs of Running This Benchmark

(해당 벤치마크 수행 비용)

벤치마크는 많은 돈과 시간을 사용합니다.  많은 테스트를 수행함에 있어서,  셋업 시간이라든지, 리소스들의 현실적인 제한등많은 테스팅에 영향을 주는 요소가 있습니다. AWS용 Netflix cloud platform 자동화를 이용하면, setup time 을 굉장히 줄여주고, 많은 테스트를 쉽게 수행하는 비용을 절감할 수 있습니다. 아래의 표에서는 테스트 기간동안 AWS 비용을 보여줍니다. 해당 비용은 Spot Instance 를 이용하거나, 안쓰고 있는 예약된 서버를 이용함으로써 낮출 수 있습니다.( 역자 주: Spot Instance 라고 해서 다른 업체에서 예약된 장비를 싼가격에 짧게 대여할 수 있습니다. )

Cassandra 0.8.6 instance 를 위한 사용할 수 있는 스토리지 영역은, 파일 시스템에서 사용할 수 있는 영역의 절반 정도입니다. 이것은 Cassandra의 현재 Compaction Algorithm 이 Compact 시에 디스크를 필요로 하기 때문입니다. Cassandra 1.0 에서 이것은 SSTable들을 디스크에 압축함으로써 좀 더 Compaction 알고리즘이 개선되었습니다. m1.x1 instance의 경우 한시간에 $0.68 정도이고, m2.4xl 은 시간당 $2.00 의 비용이 듭니다. 해당 테스트는 우리의 3개의 Availability Zone 에 복제를 해두는  설정으로, 여기서, zone을 지나는 트래픽당 1G 마다 $0.01 이 부가됩니다.  zone 을 지나는 트래픽은 전체 트래픽의 2~3배 정도,  그리고 대규모 Cluster에서는 실제 시간당 instance 사용 비용보다 네트웍 사용 비용을 더 지불하는 것으로 보입니다.

해당 테스트를 10분 정도 실행했을 때,  명확하게, 증가하는 것을 볼 수 있었습니다. 계정의 셋업 시간까지 포함해서, 가장 작은 테스트는 1시간 이내에 완료되었고, 가장 큰 테스트는 서버에서 두시간이 걸렸습니다.

전통적인 datacenter 테스트와는 다르게, 권한을 요청하거나, 시스템을 설정하는데 필요한 시간, 또는, 작은 규모의 테스트 전용 시스템을 받을 필요가 없었습니다. 동시에, 많은 테스트를 돌려볼 수 있었습니다. Denis는 create, monitor, analyze 와 테스트 결과를 그려주는 스크립트를 개발했습니다. 예를 들어, 다음은 초당 20,000 요청을 하는 클라언트 측면에서의 응답 시간을  그린 것입니다.

Detailed Cassandra Configuration

(자세한 카산드라 설정)

클라이언트의 요청은 하나의 노드에서라만 완료되었다는 메시지를 받으면 되는 Consistency Level “ONE” 을 이용하였습니다. 데이터를 쓴 후에 Consistent 한 Read 를 위해서 “LOCAL QUORUM”을 이용할 수 있습니다.  3개의 노드에서 적어도 과반수(2개 이상) 에서 응답을 받아야 하고, 이로 인해, 응답 시간이 조금 늘어납니다. 그러나 해당 작업은 Cassandra 에서 데이터의 동일함을 보장하기 위해 꼭 필요한 작업입니다. 게다가 Multi-Region 테스트에서 카산드라의 응답시간이 Europe Region이 US East 보다 Network Latency를 낮다라는 것을 발견해습니다. 이 것은 적은 규모의 배포나, 네트웍 하드웨어가 더 최신이라서 생각합니다. 우리는 다른 AWS 에 대한 네트웍 연결이 테스트이 중요한 요소라고 생각하지는 않습니다.

Stress command line
java -jar stress.jar -d “144 node ids” -e ONE -n 27000000 -l 3 -i 1 -t 200 -p 7102 -o INSERT -c 10 -r

클라이언트는 하나의 row 키로 10개의 컬럼을 쓰고, row 키는 2700만개의 ids 중에 랜덤하게 선택합니다. 각 컬럼은 10 bytes로 된 하나의 key를 가지고 있습니다. 하나의 write 에 대한 사이즈는 대략 400 bytes 입니다.

처음 30개의 클라언트는 첫 144 노드와 통신하고,  다른 30개 클라이언트는 두번째 144 노드와 통신합니다. 3개의 replica를 가지며 상세한 keyspace 설정은 다음과 같습니다.

Cassandra Keyspace Configuration
Keyspace: Keyspace1:
Replication Strategy: org.apache.cassandra.locator.NetworkTopologyStrategy
Durable Writes: true
Options: [us-east:3]
Column Families:
ColumnFamily: Standard1
Key Validation Class: org.apache.cassandra.db.marshal.BytesType
Default column value validator: org.apache.cassandra.db.marshal.BytesType
Columns sorted by: org.apache.cassandra.db.marshal.BytesType
Row cache size / save period in seconds: 0.0/0
Key cache size / save period in seconds: 200000.0/14400
Memtable thresholds: 1.7671875/1440/128 (millions of ops/minutes/MB)
GC grace seconds: 864000
Compaction min/max thresholds: 4/32
Read repair chance: 0.0
Replicate on write: true

Data Flows, Latency and Durability

(데이터 흐름과, 지연 그리고 안정성)

지연시간, 안정성을 이해하기 위해서는 카산드라 설정에 따른 데이터 흐름을 알아야 합니다.  카산드라 Client는 어떤 노드가 자신의 데이터를 저장하는지에 대해서 알지 못합니다.  그래서 랜덤으로 하나의 노드를 중재자로 뽑아서,  올바른 노드에 데이터가 복제되도록 합니다.( row key 에 대한 DHT를 통해서 복제될 노드를 선택합니다. )  가장 빠른 Write는 하나의 노드에만 데이터가 쓰여지면 응답을 보내는 것입니다. 이것은 장애가 난 memcache instances와 연관된 cold cache 이슈를 피하려고 할 때, 짧은 수명 주기를 가진 memcached 의 데이터를 카산드라에 저장할 때 유용합니다.  이것은 속도와 이용성이 Consistency 보다 더 중요할 때 사용됩니다. 거디다가 memcached 와 비교하면 추가적인 network hop이 생깁니다. eventually consistency로 인해서 write 직후에 데이터를 읽으면, 이전 데이터를 읽을 수도 있습니다.

카산드라에서 Consistent Write 를 위해서는Quorum Write 를 이용합니다. 3개의 노드 중에 2개의 노드 이상이 클라이언트가 쓰기에 대한 응답을 얻기 전에, Write에 대한 응답을 주어야 합니다. 게다가, Quorum Write 후에 Read 시에도 Quorum Read 를 이용해야 합니다.  이러면 2개 이상의 데이터의 조합으로 항상 최신의 데이터를 볼 수 있습니다.  카산드라에는 마스터 노드라는 개념이 없기 때문입니다. 어떤 노드가 장애가 나더라도 항상 read, write 가 가능합니다.

카산드라의 Commit Log는 기본적으로 매 10초마다 fsync 를 통해서 디스크에 저장됩니다. 이것은 10초 내에는 실제로 저장된 데이터가 디스크에 쓰여지지 않았다는 뜻입니다. 하지만, 해당 데이터는 세 개의 서버의 메모리에 저장되어 있어서,  세 개의 복사된 데이터가 동시에 모두 사라질 확률은 매우 낮아, 충분한 안정성과 높은 High Availabilty 그리고 낮은 지연시간을 보장해 줍니다.  각 카산드라 서버의 지연시간은 Commit Log Writer 에 저장되는 수 microsecond 입니다.

카산드라는 gossip 프로토콜을 이용해서 각각의 노드의 상태를 서로에게 알려줍니다.  만약 특정 서버에 저장되어야 할 데이터가 서버의 다운으로 저장되지 못하면, 중재가 노드가 이를 기억하고 있다가, 서버가 복구되면, gossip 프로토콜을 이용하여 해당 서버에게 데이터를 전달해줍니다. 이것이 “Hinted Handoff” 입니다.

Netflix 는 아일랜드의 AWS Europe 를 이용해서, 영국, 아일랜드의 확장을 지원하기 위한 global 카산드라 Cluster 를 셋팅하고 테스트 중입니다.  데이터에 대한 Global View 가 필요하면, 여분의 카산드라 node 가 설정되고, 각 서버에 쓰여진 모든 데이터의 복제에 대한 비동기적인 업데이트가 제공됩니다.  마스터 복제본은 존재하지 않고, 지역간 연결이 끊어지더라도, read 와 write 에 LOCAL QUORUM을 이용합니다.  외부 지역에 데이터를 보내야 할  때, 그것의 응답을 기다리지 않습니다. HA를 위해서 내부는 Consistent 한 액세스를 이용하고 외부 지역과는 eventually consistent 액세스를 이용하기 때문에, 다른 지역에 대한 지연은 별로 중용하지 않습니다.

Next Steps(다음 스텝)

카산드라 1.0의 성능 특성과 Multi-Region 에서의 reads 와 write 의 성능에 대해서 좀 더 복잡한 쿼리의 조합과 클라언트 라이브러에 대해서 수많은 테스트를 더 해봐야 합니다.

Takeaway(끝으로…)

Netflix 에서는 AWS에서 Cassandra 를 글로벌 분산 스트리밍 시스템의 중요 시스템의 일부로 사용중입니다. 요구 성능을 넘어서는 선형 확장성을 보여주고, 매우 빠르게 자동정으로 배포가 가능하며, 유지하기도 쉽습니다. 클라우드에서의 벤치마킹도 매우 빠르고, 값싸게 , 확장 가능하게 진행되었습니다. 한번 시도해 보면, 당신도 돌아가길 원하지 않을 것입니다.

만약 당신이 성능 최적화 관련 고수이며, 수분내에 거대한 테스트를 수행하는 툴을 만드는 회사의 직원이 되기를 원한다면, 우리에게 전화를 주시기 바랍니다.(역자 주: 구인광고네요 ㅎㅎ)

Redis에 심플한 key-value 로 수 억개의 데이터 저장하기

해당 글은 http://instagram-engineering.tumblr.com/post/12202313862/storing-hundreds-of-millions-of-simple-key-value-pairs 라는 instaram에서 redis를 사용한 경험에 대한 글을 “발번역”하고 제 의견을 추가한 것입니다.

과도기 적인 시스템을 운영중에는, 때때로 작은 기반 시스템을 구축해야 할 경우가 생깁니다. 인스타그램에서도,  최근에 그런 작업을 진행해야만 했습니다. 3억 개의 사진을 각각 어떤 userID 와 매핑되고, 샤딩 서버로 쿼리를 보낼 지에 대한 정보를 유지하고 만들어야 했습니다. (관련 정보는 http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram 를 보면 됩니다.)

클라이언트와 API 어플리케이션이 업데이트되고, 이에 대한 정보를 전달하는 동안에는, 여전히 이전 정보를 캐쉬하고 있었습니다. 그래서 다음과 같은 요구사항에 대한 해결책이 필요했습니다.

1. 키를 빨리 찾고, 빨리 값을 리턴해야 한다.

2. 데이터는 메모리에 저장되어야 하고, 이상적으로 EC2 high-memory types( 68GB 보다는, 17GB나 34GB   ) 이내에 들어가야 한다.

(역자 주: EC2에서 가격이 34GB는 17GB 의 2배, 68GB는 17GB의 4배 입니다.)

3. 기존 구조에 적합해야 한다.

4. 서버가 죽어도 다시 데이터를 새로 생성하지 않도록, persistent 해야 한다. (여기의 의미는, 다른 DB나 로그에서 데이터를 다시 재생성할 필요 없이, 저장된 데이터를 그대로 나중에 다시 복원할 수 있어야 한다라는 느낌입니다.)

간단한 해결책은 “Media ID”  와   “User ID” 라는 컬럼을 가지는 형태로 데이터베이스에 저장하는 것이었습니다.  그러나  SQL Database 는  insert 만 제공한다거나, 트랙잰션이 필요없을  경우,  그리고 다른 테이블과도 아무런 연관관계가 없는 이런 데이터에서는 너무 과도한 방법으로 보였습니다.

그래서 우리는 Redis 로 방향을 돌렸습니다.  Redis는  인스타그램에서 널리 사용하는 고성능 Key-Value 저장소입니다.( 예를 들어,  Redis는 인스타그램의 메인 저장소입니다.) Redis 는 일반적인 memcached에 비해서 스위스 군용 나이프 같습니다.  Redis는 sorted sets 과 list 와 같은 파워풀한 Collection을 제공합니다.

(역자 주: memcached는 단순한 키에 대한 set, get 정도만 제공합니다. 그리고 memcached는 store 라기 보다는 Cache로 생각하는 것이 좋습니다.)

그리고 Redis 는 persistence 를 설정으로 사용할 수 있습니다. 백그라운드로 지정된 시간마다, 메모리 상태를  저장합니다. 그리고 Master-Slave 형태로 동작이 가능합니다.(  역자 주: redis 에서는 현재 메모리 상태를 disk로 snapshot을 만드는 기능이 있습니다.  그리고 성능은 떨어지지만, 메모리가 부족할 때 Virtual Memory로 동작할 수 있는 기능이 존재합니다.  자세한 정보는 http://redis.io/documentation 를 참고하세요.) 우리의 모든 redis 서버는 master-slave 형태로 동작하고, Slave는 매분마다 메모리의 Snapshot을 디스크에 저장합니다.

At first, we decided to use Redis in the simplest way possible: for each ID, the key would be the media ID, and the value would be the user ID:

처음에 우리는 Redis를 최대한 간단한 방법으로 사용하기로 했습니다. 각각의 아이디는 media ID로 구성되고, 그 값은 userID가 되는 것입니다.

SET media:1155315 939 
GET media:1155315 
> 939

이 방법에 대한 프로토타이핑 중에, 우리는 redis 가 백만개의 키들을 저장하는 70MB 정도가 필요하다는 것을 알았습니다. 3억개로 확장하면, Amazon EC2의 17GB 모델 보다 큰 21GB 정도의 메모리가 필요했습니다.우리는 언제나 Redis의 코어 개발자중의 한명인 Pieter Noordhuis 문의했습니다. 그는 Redis hashes 를 제안했습니다. Redis의 Hashes는 메모리에 매우 효과적으로 인코딩된 사전 구조로 되어있습니다. Redis의 hash-zipmap-max-entries’ Setting은 효과적으로 인코딩된 해쉬를 저장하는 엔트리의 최대 개수를 설정합니다. 우리는 이 값을 대략 1000 으로 저정하는 것이 HSET 에서 가장 CPU 효율이 좋은 것을 알았습니다.
자세한 정보는 https://github.com/antirez/redis/blob/unstable/src/zipmap.c 를 보시면 됩니다.)

hash type 의 장점을 얻기 위해서, 우리는 Media ID를 1000개의 bucket 으로 나누었습니다.( 단순히 ID를 1000으로 나누고, 나머지는 버렸습니다.)hash 는 Media ID를 키로 가지고, User ID를 값으로 가집니다.예를 들어, 1155315 라는 Media ID가 주어지면, bucket 1155로 할당됩니다.( 1155315 / 1000 = 1155 ):

HSET "mediabucket:1155" "1155315" "939" 
HGET "mediabucket:1155" "1155315" 
> "939"

메모리 사이즈 차이는 꽤 충격적이었습니다. 백만개의 키의 경우( 1000 hashes 가 1000개의 subkey를 가질 때)  Redis는 오직 16MB 만 사용하였습니다. 3억개로 확장한다면, 최대 5GB 이하였습니다.  사실 상 더 싼 아마존 ec2의 m1.large type 에 맞출 수 있습니다. (역자 주:  m1.large는 7.5GB의 메모리를 제공하고 한시간에 $0.34 입니다. 아까 말한 17GB m2.xlarge는 한시간에 $0.5 입니다. 대략 30% 정도 이득입니다.) 거기다가, 우리가 필요했던 장비의(34GB 모델 기준) 1/3 정도 가격입니다. 더 좋은 것은 hashes 는 O(1)의 속도로 검색이 매우 빠릅니다. 이 조합에 대해서 관심이 있다면,  available as a Gist on GitHub( Memcached 역시 비교군으로 들어가 있습니다. memcached는 백만개에 52MB 정도를 사용합니다.) 그리고 이런 종류의 문제에 관심이 있다면, 우리는 고용중입니다.( http://instagram.com/about/jobs/)

(역자 주: 최초에는 단순 Set이 HSet 으로 바뀌면서 Key에 들어가야 하는 부분이 공통 버켓이름으로 대체되어서 데이터가 줄어든 거라고 착각하고 있었습니다. 그런데, 이런 것은 아니라  zipmap 을 통해서 실제로 해시에 저장되는 방식이, 메모리를 덜 낭비하도록 만드는 것입니다. 이 때, key 나 value 가 압축되거나 하지는 않습니다. 다만, 저장에 필요한 다른 값들을 최대한으로 적게 사용하는 것으로 보입니다.)

Follow

Get every new post delivered to your Inbox.

Join 28 other followers