Category Archives: Uncategorized
[입 개발] Redis Internals : PubSub
오늘은 Redis 를 사용하는 큰 이유중에 하나인 Publish/Subscribe 에 대해서 알아보려고 합니다.
먼저 Redis에서 사용하는 pubsub 관련 command 들은 다음과 같은 것들이 있습니다.
- subscribe
- unsubscribe
- psubscribe
- punsubscribe
- publish
사실 publish 관련 명령은 하나 뿐이니 간단하게 이해할 수 있을 것이고, 앞에 p가 붙느냐 아니냐는 이게 pattern 으로 등록을 하느냐, 정확한 채널명인가를 지정하게 됩니다. 예를 들어서 subscribe 는 그냥 채널명과 일치하는 것의 데이터를 가져오게 되고, 앞에 p가 붙는 psubscribe 는 패턴을 등록해서 그 패턴과 일치하면 데이터를 전달하게 됩니다.
pub/sub의 구현을 위해서 redisServer 구조체 안에는 다음과 같은 구조체가 2개가 있습니다. key변경에 대한 notification 부분이 추가되었는데, 이 부분은 그냥 pub/sub을 이용하기 때문에 일단 생략하도록 하겠습니다.
/* Pubsub */ dict *pubsub_channels; /* Map channels to list of subscribed clients */ list *pubsub_patterns; /* A list of pubsub_patterns */
보면 채널은 dict 고 pattern은 list인걸 알 수 있습니다. 이건 channel은 같은 이름을 hash로만 찾으면 되는데, pattern은 해당 pattern이 모두 일치하는 지를 확인해야 하기 때문에 그렇습니다. 즉 여기서 pattern을 많이 사용하면, 느려질꺼라는 것을 예상할 수 있습니다.
subscribe 와 psubscribe에서 등록 과정은 각각 dict 에 넣거나 list에 넣는 것이 전부라 크게 볼 부분이 없고, publish 부분을 살펴보도록 하겠습니다. publish 과정은 두 단계로 이루어집니다.
- channel 에 있는 것중에 일치하는 것을 dictFind 로 찾아서 있으면 해당 등록된 클라이언트에게 모두 전송
- pattern 에 일치하는 것을 찾아서 해당 등록된 클라이언트에게 모두 전송
코드는 간단합니다. 다음과 같습니다.
/* Publish a message */
int pubsubPublishMessage(robj *channel, robj *message) {
int receivers = 0;
struct dictEntry *de;
listNode *ln;
listIter li;
/* Send to clients listening for that channel */
de = dictFind(server.pubsub_channels,channel);
if (de) {
list *list = dictGetVal(de);
listNode *ln;
listIter li;
listRewind(list,&li);
while ((ln = listNext(&li)) != NULL) {
redisClient *c = ln->value;
addReply(c,shared.mbulkhdr[3]);
addReply(c,shared.messagebulk);
addReplyBulk(c,channel);
addReplyBulk(c,message);
receivers++;
}
}
/* Send to clients listening to matching channels */
if (listLength(server.pubsub_patterns)) {
listRewind(server.pubsub_patterns,&li);
channel = getDecodedObject(channel);
while ((ln = listNext(&li)) != NULL) {
pubsubPattern *pat = ln->value;
if (stringmatchlen((char*)pat->pattern->ptr,
sdslen(pat->pattern->ptr),
(char*)channel->ptr,
sdslen(channel->ptr),0)) {
addReply(pat->client,shared.mbulkhdr[4]);
addReply(pat->client,shared.pmessagebulk);
addReplyBulk(pat->client,pat->pattern);
addReplyBulk(pat->client,channel);
addReplyBulk(pat->client,message);
receivers++;
}
}
decrRefCount(channel);
}
return receivers;
}
위의 소스 코드를 보면 실제 pubsub_channels 과 pubsub_patterns 가 전부 내부에 리스트로 클라이언트를 관리하고 있는 것을 알 수 있습니다. Redis 안에서 pub/sub은 굉장히 쉽게 구현되어 있습니다.
[돌머리] 돌머리를 깨기 위한 간단한 알고리즘 문제 – 매트릭스 90도 회전하기
Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees. Can you do this in place?
solve) Draw the mapping table. and easy you can find the rule
after 90 degrees rotation, map[y*n+x] ==> new_map(n-1-x)*n+y
and just write!!
#include <stdio.h>
#include <stdlib.h>
void printMap( int *map, int n ) {
printf("=====map====\n");
for( int y = 0; y < n; y++ ) {
for( int x = 0; x < n; x++ ) {
printf("%d ", map[y*n+x]);
}
printf("\n");
}
}
void transform( int *map, int *new_map, int n )
{
for( int y = n-1; y >= 0; y-- ){
for( int x = 0 ; x < n; x++ ) {
new_map[y*n+x] = map[(n-1-x)*n+y];
}
}
}
int main( int argc, char *argv[] ) {
int n = atoi(argv[1]);
int *map = new int[n*n];
for( int i = 0; i < n*n; i++ ) {
map[i] = i;
}
printMap(map, n);
int *new_map = new int[n*n];
transform(map, new_map, n);
printMap(new_map, n);
return 0;
}
[발 번역] Leveled Compaction in Apache Cassandra
해당 블로그는 KT Ucloud의 지원을 받고 있습니다.
해당 글은
http://www.datastax.com/dev/blog/leveled-compaction-in-apache-cassandra
의 글을 발 번역한 것입니다. HBase 나 Cassandra의 경우 Compaction이라는 단계가 있습니다. Write 속도를 빠르게 해주기도 하고 Locality를 높일 수 있으므로 성능을 높여주는 요소이기도 하지만, 또한 자바의 GC 처럼, 한번 Major Compaction이 일어나면, 시스템에 큰 부담을 주는 기능이기도 합니다. HBase의 경우 내부적으로 HDFS를 사용하고 있고, Cassandra의 경우는 로컬 파일시스템을 사용합니다. mongodb 역시 로컬 파일시스템을 사용합니다. GC가 꾸준히 발전하는 것처럼 Cassandra에서도 Leveled Compaction 이라는 기능을 추가했습니다.(다만, 아직까지 Major Compaction 일 때 큰 성능 저하는 피할 수 없는 듯 합니다.) 그럼 Apache Cassandra에서 사용하는 Leveled Compaction에 대해서 간략하게 알아보도록 하겠습니다. 오역에 주의하세요.
Leveled Compaction in Apache Cassandra
Introduction to Compaction
카산드라의 로그 스토리지 엔진은 모든 업데이트를 sstables 이라는,순차적으로 디스크에 저장하는 방식을 이용하여, 놀라운 성능과 application-transparent compression 같은 기능을 가능하게 합니다. 이미 쓰여진 데이터를 업데이트 하지 않고( 이것은 Random I/O를 요구하기 때문에 ), 새로운 sstable 에 새로운 버전의 컬럼을 삽입하거나 업데이트 정보를 추가합니다.(역자 주, sstable 은 딱 한번만 쓰여지기 때문에, 컬럼의 업데이트 역시 insert 같이 처리됩니다. 그래서 하나의 컬럼 내용을 여러 sstable에서 읽어와서 최종 버전의 값을 확인해서 보여주게 됩니다. )
Figure 1: adding sstables with size tiered compaction
그래서, 시간이 지나면, 많은 버전의 row 가 다른 sstable 들에 존재할 수 있습니다. 각 버전들은 각각 다른 부분의 컬럼을 가지고 있습니다. 하나의 row를 읽기 위해서는 많은 파일을 찾아서 그 결과를 합쳐서 보내야만 합니다.
읽기 속도 악화를 방지하기 위해서, sstable들을 합치는 compaction 이 백그라운드로 동작합니다.( 각 sstable들에 들어있는 row들이 primary key로 정렬되어 있어서 Random I/O 없이, 해당 작업을 효과적으로 수행할 수 있습니다. )
Tiered Compaction
Figure 2: sstables under size-tiered compaction after many inserts
카산드라의 size-tiered compaction 전략은 Google’s Bigtable paper 에 묘사된 것과 매우 유사합니다. 비슷한 사이즈의 sstable들이 충분히 있으면(기본적으로 4개), 카산드라는 그 sstable 들을 합칠 것입니다. figure 1 에서 각 녹색 바는 하나의 sstable을 나타내고, 화살표는 compaction을 의미합니다. 새로운 sstable이 생성되고, 처음에는 아무일도 발생하지 않습니다. 4개가 되고 나면, 서로 합치기 시작합니다. 그리고 다시 새로운 4개가 발생하면 다시 반복하게 됩니다. Figure 2는 나중에 기대할 수 있는 결과를 보여줍니다. 2 tier의 sstable 들이 합쳐져서 3 tier의 sstable을 생성하고, 3 tier들이 합쳐져서 4 tier sstable을 생성합니다. 이게 계속 됩니다.
size-tiered compaction 는 update 가 많은 환경에서 3가지 문제점이 있습니다.
- 성능이 일정하지 못합니다. 하나의 row 가 얼마나 많은 sstable에 걸쳐있을지 모르기 때문에, 최악의 경우에는, 모든 sstable 에서 해당 row를 찾아야 할지도 모릅니다.
- 안쓰는 컬럼에 대해서 얼마나 빨리 병합해서 없앨지에 대해서 보장하지 않기 때문에, 상당한 양의 공간이 낭비될 수 있습니다. 특히 높은 비율로 삭제가 발생하면, 특별히 발생하기 쉽습니다.
- 반복되는 Compaction으로 인해서 쓸모 없는 sstable이 병합되어 완전하게 쓰여지기 전까지, 너무 커지는 것도 공간에 문제가 됩니다. 최악의 경우에는 굉장히 큰 하나의 sstable 이 지울 수 있는 삭제된 row들이 없을 수 있습니다. 카산드라는 compaction이 진행될 때, 병합된 sstable을 쓰기 위해서 그 만큼의 빈 공간이 필요합니다.
Leveled Compaction
Figure 3: adding sstables under leveled compaction
카산드라 1.0에서는 구글의 Chromium 팀에서 개발한 LevelDB 에 기반한 Leveled Compaction 전략을 제공하고 있습니다.(역자 주: 저도 이래서 이름이 그런건 처음 알았네요.)
Leveled compaction 은 sstable을 “levels” 로 그룹화되는 고정된 크기에 상대적으로 적은 크기(기본적으로 5MB)로 생성합니다. 그리고 각 레벨 내에서는 데이터가 겹치지 않는 다는 것을 보장하고, 각 레벨은 이전 레벨보다 10배 크기가 큽니다.
Figure 3에서 새로운 sstable이 첫번째 레벨에 저장이 됩니다. 그리고 L1에서 즉시 sstable 들은 compaction 됩니다.(파란색) L1이 가득 찼을 때, 추가된 sstable들이 L2로 올라가게 됩니다.(보라색). 상당 수의 L1에서 생성된 sstable 들이 compaction 되면서 L2 로 올라가게 됩니다.(이 때, 데이터가 겹칠 수 있습니다.) 데이터가 더더욱 추가되면, leveled compaction의 결과로 Figure 4 처럼 되게 됩니다.
Figure 4: sstables under leveled compaction after many inserts
tiered compaction 을 이용해서 위의 문제를 해결할 수 있습니다.
- Leveled compaction 은 모든 읽기의 90%를 하나의 sstable 에서 히트시킬 것입니다.( 거의 같은 크기의 row 라고 가정했을 때 ), 최악의 경우에도 레벨의 최대 수에 한정됩니다. 예를 들어, 10TB 데이터를 위해서 7레벨 정도 입니다.
- 삭제된 row 에 의해서 10% 정도 공간이 낭비될 수 있습니다.
- compaction을 위해서 임시로 사용되는 공간을 위해서 오직 sstable의 10배 크기만 남아있으면 됩니다.
compaction_strategy 옵션을 LeveledCompactionStrategy로 설정하고, Column Family를 생성하면(업데이트 함으로써) Leveled compaction 을 활성화 할 수 있습니다. 존재하는 Column Family를 수정할 때 백그라운드로 현재 존재하는 sstable들의 레벨링이 수행되는 동안 , 읽기와 쓰기는 정상적으로 수행됩니다.
Considerations
leveled compaction이 위의 얘기들을 보장해주도록 해주기 때문에, size-tiered compaction 보다 대략 2배 정도 많은 i/o를 수행합니다. 주로 쓰기 중심의 작업에서, 거기에 삭제된 row 가 거의 포함되지 않았다면, 이 추가적인 i/o는 어떠한 도움도 되지 않습니다.
Leveled compaction 은 concurrent_compactors 옵션을 무시합니다. 병렬 compaction은 compaction 시스템이 큰 sstable 셋을 처리한다고 바쁜 동안에, 백로그에 작은 compaction 셋들이 임시적으로 멈추어 있는 tiered compaction의 문제를 피하기 위해서 디자인되었습니다. Leveled compaction에는 모든 compaction이 거의 같은 사이즈를 가지기 때문에 이러한 문제가 발생하지 않습니다. Leveded compaction은 하나의 스레드가 몇개의 sstable을 처리할 것인지를 결정하는 multithreaded_compaction 옵션을 compaction의 속도 향상을 위해서 이용합니다. 그러나, 대부분의 compaction 튜닝은 compaction_throughput_mb_per_sec 을 이용해서(기본: 16) compaction의 속도를 조절합니다.
[Setting] Nginx + Tornaldo + Django + python 2.7.2
까먹을까봐 기록해두자.
1] python
apt-get install zlib1g-dev
apt-get install libbz2-dev
apt-get install libssl-dev
wget http://www.python.org/ftp/python/2.7.2/Python-2.7.2.tar.bz2
tar jxvf Python-2.7.2.tar.bz2
./configure
make; make install
ln -sf /usr/local/bin/python2.7 /usr/bin/python
2] setuptools, pip
wget http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz#md5=7df2a529a074f613b509fb44feefe74e
tar zxvf setuptools-0.6c11.tar.gz
python setup.py build
python setup.py install
ezsy_install pip (이후론 전부 pip)
3]virtualenv
pip install virtualenv
virtualenv –no-site-packages project1
./project1/bin/activate
pip install pycurl
pip install simplejson
pip freeze > pip-req.txt
4] django
pip install django
5] tornaldo
pip install http://github.com/downloads/facebook/tornado/tornado-2.1.1.tar.gz
6]nginx
sudo apt-get install libpcre3 libpcre3-dev
wget http://nginx.org/download/nginx-1.0.11.tar.gz
tar zxvf nginx-1.0.11.tar.gz
./configure
make; make install
[nginx.conf]
worker_processes 1;
events {
worker_connections 1024;
use epoll;
}
http {
upstream tornadoserver {
server 127.0.0.1:8888;
}
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#gzip on;
include /usr/local/nginx/conf.d/*.conf;
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8888;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
[발 번역] MongoDB Best Practices
해당 글은
http://www.engineyard.com/blog/2011/mongodb-best-practices/
의 MongoDB Best Practice 를 발 번역한 글입니다. 오역에 주의하세요.
MongoDB Best Practices
안녕하세요. Engine Yard Data Team 입니다. 지난번에 블로깅한 이후로 무슨 일이 있었는지 알려드리길 바랍니다.
데이터 팀은 올해 초에 만들어진 후, 첫번째 작업은 MongoDB stack을 확장하는 것이었습니다. 그러나, 관계형 DB의 업데이트 없이 NoSQL 저장소를 추가한다면, 고객에게 몹쓸짓을 하게 된다는 것을 느꼈습니다. 그래서 MongoDB 개발을 멈추고 MySQL과 PostgreSQL 의 업데이트 하기로 결정했습니다. 최근에 MySQL 5.5 베타가 출시되었고 PostgresSQL 9.1 베타는 곧 나올 것입니다. 그리고 2012년 1분기쯤 GA버전을 출시할 계획입니다.
General NoSQL best practices
NoSQL을 선택하는 방법에 대한 많은 문서들이 있습니다. Read/Write 성능, 안정성, 데이터 일관성, 네트웍 응답속도 등 여러 특징들을, 어플리케이션에서 요구하는 것을 고민해서 잘 선택해야 합니다. 해당 문제에 대해서 Nathan Hurst in가 “Visual Guide to NoSQL Systems” 에 잘 요약해두었습니다.
올바른 NoSQL을 선택하는 것은 이 문서의 범위를 넘어가므로, 직접 조사하시기 바랍니다. 모든 상황에 맞는 하나의 솔루션을 없을 것입니다. 해당 문서도 MongoDB가 요구하는 어플리케이션에 적합하다고 가정하고 넘어갑니다. Engine Yard 에서 추천하는 부분은 다음과 같습니다.
미친듯이 테스트 하라 – Test exhaustively
RDBMS를 그대로 대체할 수 있다고 가정하지 말라 – Don’t assume that what worked for your RDBMS will translate
데이터에 대한 일관성과 안전성이 필요한지 고민하라 – Think about the consistency and durability needs of your data.
EBS Volumes에서 무엇을 기대할 수 있는지 이해하십시오 – Understand what to expect from EBS volumes
MongoDB Best Practices
MongoDB를 우리의 Stack에 릴리즈 하는데 따라야 하는 지침은 다음과 같습니다.
항상 Replica Sets을 사용하라 – Always use replica sets
최신 버전을 유지하라 – Keep current with versions
MongoDB를 32bit에서 사용하지 말라 – Don’t run MongoDB on 32-bit systems
기본적으로 Journaling을 사용하라 – Turn journaling on by default
데이터 파일의 위치를 확인하라 - Mind the location of your data files
Working Set은 메모리 사이즈에 적합하게 유지하라 – Your working set should fit in memory
엄청 많이 사용한다면 Scale Up을 하라 – Scale up if your metrics show heavy use
샤딩에 주의하라 – Be careful when sharding
샤딩을 적용하는 것은 어플리케이션의 액세스 패턴에 대한 깊은 이해가 필요합니다. MongoDB가 어떻게 샤딩을 하고 정말로 샤딩이 필요한지에 대해서 시간을 드려서 고민하시기 바랍니다. 그리고 성능에 영향을 주는 좋은 샤딩 키를 선택하는 것도 중요합니다.(selecting a good sharding key) ( 역자 주: 샤딩의 경우 샤딩키를 제외하고는, Unique 속성을 줄 수 없습니다. 복합 샤딩키는 가능합니다.)
Config 서버는 클러스터 상태에 매우 중요합니다. 실서비스의 샤딩 환경에서는 3 대의 Config 서버가 필요합니다. 자주 Config 서버의 데이터를 백업하고, 그것을 확인하고, 절대로 Config 서버의 데이터를 지우면 안됩니다. 가능하면 /etc/hosts 파일에 서버 이름을 저장해두고 사용하길 바랍니다.( 클러스터를 좀 더 탄력적으로 만들 수 있습니다.)
Config 서버는 경량 프로세스이지만, 역시 64bit 장비에서 동작해야 합니다. 3개의 Config 서버를 한 장비에 몰아넣으면 안됩니다. 만약, 샤드된 설치를 고려한다면 Engine Yard Professional Services 에 컨설팅 스케줄을 잡으실 수 있습니다.
그래픽적으로 모니터링 하기 위해서 MongoMMS를 사용하라 – Use Mongo MMS to graphically monitor your service
MongoDB resource를 살펴라 – Keep up with MongoDB resources
빨리 바뀌므로, 정보를 항상 최신으로 유지하라. 다음 사이트에서 정보를 찾을 수 있습니다.
- Documentation: http://www.mongodb.org/display/DOCS/Home
- Google Group:
http://groups.google.com/group/mongodb-user
- Bugs:
https://jira.mongodb.org
- Blog: http://blog.mongodb.org/
뭔가 더 듣고 싶나요? 피드백을 주세요 – Want to hear more? Give us feedback!
http://www.mongodb.org/display/DOCS/Security+and+Authentication
여기서 보실 수 있습니다. MongoDB의 소스를 보면 MONGO_SSL을 사용할 수 있도록 들어가 있는 것 같습니다. 전체 데이터에 대한 SSL 지원인지는 좀 더 봐야겠네요 ^^)
최근의 행복에 대한 생각
먼저, 저는 상당히 행복합니다. 돈도 조금이나마 저축이 가능할 정도로 벌고 있고, 꽤 재미있는 일도 하고 있고
그런데, 최근에, 지속적인 행복 상태를 만드는데, 주변 환경도 중요하다라는 생각이 듭니다.
그래서 고민이 되는 것이 자연 환경이 좋은 “제주도” 로 옮긴다든지, 아니면, 외국을 한번 미친듯 하고 나가 본다든지, 부산으로 내려가서, 그냥 조용히, 알바하면서 사는 건 어떨까 라는 생각이 듭니다.
물론 이것들은, 중요한 전제조건이 붙습니다. “먹고 살 돈이 되느냐?” 몇년 안에 분명히 2세도 가질테고, 기본적으로 사용하는 돈들 아무리 생각해도, 어느 정도는 벌어야 가장으로서, 집안 식구들을 먹여 살릴 것 같은데, 컴퓨터 프로그래밍 말고는 재주가 없는 저로서는 지방에서 가족을 부양하한다는 것은 상당히 큰일입니다.
그렇다면, 시골이나, 지방으로 내려가게 되면, 어떻게 먹고 살아야 할 것인지에 대해서, 고민이 스멀스멀 생겨나게 됩니다. 재미난 것은, 제가 일하는 분야의 IT 쪽에서는 사실, 꼭 같은 사무실로 출근할 필요는 없다는 것입니다. 하지만, 함께 없을 때 생기는 커뮤니케이션의 비용에 대한 걱정으로, 사무실로 출근을 해야 하는 것이죠.
뭔가 세상이 바껴서, 전부 재택근무 이런 시기가 온다면 정말 좋겠지만, 아직까지 그러기는 힘들고, 나름의 좋은 방법을 계속 생각해보는 수 밖에 없을 듯 합니다.
A Walk In The Cloud
미흡한 지식으로 Cloud 를 살짝 정리해보았습니다.
과연 Developer/Operator/DBA는 Cloud 에서 어떤 포지션을 가져야 할까요?



