<< 대한 민국에서 창업이 힘든 이유 6가지 | Home | Xmemcached + Spring 기반의 Memcached 사용하기 >>

Memcached 사용하기

캐싱은 서비스의 성능 향상에 매우 큰 도움이 되며, 소프트웨어적인 방법을 통한 최적화에 최고의 도구가 Memcached입니다.
Memcached는 LiveJournal을 운영하는 Danga Interactive사에서 개발된 고성능의 분산 메모리 캐싱 시스템입니다. 주로 트래픽이 많은 동적 웹 어플리케이션에서 디비의 부하를 줄이기 위한 용도로 많이 활용됩니다
그리고 Memcached 사용하는 사이트는  facebook, Vox, LiveJournal, 위키피디어, 유투브, 아마존, 소스포지, 트위터, Google App Engine, mixi, 하테나 등에서 웹 어플리케이션의 확장을 향상하는 중요한 수단으로 사용하고 있습니다.

1. libevent 설치
 - rpm -qa libevent로 설치여부 확인
 - 미설치 경우 설치
wget http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz
tar xvfz libevent-1.4.14b-stable.tar.gz
cd libevent-1.4.14b-stable
./configure
make
sudo make install

2. Memcached 설치
wget http://danga.com/memcached/dist/memcached-1.2.8.tar.gz
tar xvfz memcached-1.2.8.tar.gz
cd memcached-1.2.8
./configure --prefix=/database/server/memcached --with-libevent=/usr/local/lib/
make
sudo make install

3. 구동 옵션
 - memcached -help 나옴
nohup /database/server/memcached/bin/memcached -d -m 512 -l ip -p 11211 -u k2  -vv 2>>$LOG_FILE &

4. Python 클라이언트 샘플
 - 라이브러리 설치 : easy_install python_memcached
 - 샘플(memcachesample.py)
import memcache

class memcachesample():
    hostname = ""
    server   = ""
    def __init__(self, hostname="127.0.0.1", port="11211"):
        self.hostname = "%s:%s" % (hostname, port)
        self.server   = memcache.Client([self.hostname])

    def set(self, key, value, expiry=900):
        self.server.set(key, value, expiry)

    def get(self, key):
        return self.server.get(key)

    def delete(self, key):
        self.server.delete(key)

if __name__ == '__main__':
    sample = memcachesample("127.0.0.1");
    sample.set("username", "mimul");
    result = sample.get("username");
    print 'username=', result 

 - 샘플 실행 결과
python memcachesample.py
username= mimul

5. memcached benchmark 테스트
 - bmt tool : http://www.interdb.jp/techinfo/mcb/index-e.html
 - 컴파일  : gcc -Wall -lpthread -lnsl -o mcb mcb.c
 - 사용법
usage: mcb -c {set|add|get} [OPTIONS]
           -c command_type {set|add|get}
           -a server_address[127.0.0.1]
           -f unix socket path
           -p server_port[11211]
           -T connection Type {TCP|UDP|UNIX_SOCKET}[TCP]
           -t number_of_thread[1] <1-1024>
           -n number_of_command[1] <1-65535>
           -m max_key[1000] <1-65535>
           -l average data_length[1024] <1-40960>
           -v :verbose
           -s :send and disconnect each command
            (Default => send all commands per one session)
           -h :help

 - TCP 테스트 커맨드 : ./mcb -c set -a 127.0.0.1 -p 11211 -t 10 -n 1000 -l 100
./mcb -c set -a 127.0.0.1 -p 11211 -t 10 -n 1000 -l 100
condition =>
        connect to 127.0.0.1 TCP port 11211
        command = set
        10 thread run
        send 1000 command a thread, total 10000 command
        data length = 100
result =>
        interval =  0.246238 [sec]
        performance =  40611.117190 [command/sec]
        thread info:
          ave. = 0.219247[sec], min = 0.204866[sec], max = 0.243017[sec]

 - UDP 테스트 커맨드 : ./mcb -c set -a 127.0.0.1 -p 11211 -t 10 -n 1000 -l 100 -T UDP
./mcb -c set -a 127.0.0.1 -p 11211 -t 10 -n 1000 -l 100 -T UDP
condition =>
        connect to 127.0.0.1 UDP port 11211
        command = set
        10 thread run
        send 1000 command a thread, total 10000 command
        data length = 100
result =>
        interval =  0.220273 [sec]
        performance =  45398.206717 [command/sec]
        thread info:
          ave. = 0.217655[sec], min = 0.198494[sec], max = 0.220058[sec] 

6. Memcached 모니터링 스크립트
 - 스크립트 소스
import memcache

NODES = ('127.0.0.1:11211',)
mc = memcache.Client(NODES)
for mc_stats in mc.get_stats():
    server, stats = mc_stats
    print '-----------------------------------------'
    print server
    print '-----------------------------------------'
    for stat_name, value in sorted(stats.iteritems()):
        if not stat_name.startswith('ep'):
            if stat_name not in ('libevent', 'version'):
                print stat_name.ljust(25), value.rjust(15)

 - 스크립트 구동 결과
-----------------------------------------
127.0.0.1:11211 (1)
-----------------------------------------
accepting_conns                         1
bytes                              153962
bytes_read                       10147732
bytes_written                     3699740
cmd_flush                               0
cmd_get                              6304
cmd_set                             46101
connection_structures                  12
curr_connections                        2
curr_items                           1001
evictions                               0
get_hits                             6297
get_misses                              7
limit_maxbytes                  536870912
listen_disabled_num                     0
pid                                 31110
pointer_size                           32
rusage_system                    1.000000
rusage_user                      0.280000
threads                                 2
time                           1302249309
total_connections                      34
total_items                         46101
uptime                              13727
-----------------------------------------

7. Memcached에 대한 클라이언트에 대한 생각
 - 사용중인 클라이언트 라이브러리가 Memcached 서버가 죽었을 때 정확하게 에러를 내뱉는  확인이 필요함
 - 여러 클라이언트가 하나의 값을 변경할 때 race condition을 피하기 어려운데 이부분을 잘 처리하는지 데이터의 정합성은 유지되는지 테스트 필요
 - parallel mutli_get에서 성능이 제대로 발휘되는지 확인 필요
 - Memcached는 text protocol을 사용하기에 트래픽이 많을 경우 CPU점유율이 높거나 튀는지 확인 필요
 - 많은 패킷이 올 때 Network bottleneck이 없는 지 확인 필요
 - 그래서 개인적으로 클라이언트 라이브러리는 binary protocol을 사용해서 클라이언트를 짜는게 좋을 거 같은데 이는 버그 패치 등 안정화 기간이 걸리는 단점이 있음
 - 커넥션 풀 기능 지원여부 확인



Add a comment Send a TrackBack