Tag Archives: memcached

memcached를 이용한 grace 기능 구현

Varnish Cache의 grace 기능을 PHP/memcached로 구현했습니다.

grace 기능은 백엔드 서버가 죽더라도, 캐싱되어 있는 정보로 지속적인 서비스가 가능하도록 하는 기능입니다. 캐싱할때 여분의 시간(grace 시간)동안 더 캐시를 유지하며, 캐싱 시간이 지났을때 백엔드에 요청이 한번만 전달되게 하고, 나머지 요청에 대해서는 우선적으로 그 전에 있던 캐시로 서비스를 하도록 하여 백엔드 서버의 부하를 줄일수 있습니다.

현재는 memcached에서 expire 되면서 동시에 요청이 발생하는데, grace 기능을 구현하면 오래걸리는 페이지 생성할때 큰 효과를 발휘할수 있을거라 기대됩니다.

PHP 구현은 간단합니다. 원래 key,value 항목의 expire
시간을 grace 시간 만큼 늘리고, 다른 키(key+”_s”)에 expire 시간동안 상태값을 입력해두면, 어렵지 않게 grace 기능을
구현할수 있습니다.

초기에 캐시에 없을때는 백엔드에 동시에 여러 요청이 들어갈수 있습니다. 이미 요청이 처리되고 있을때(state=”G”), 일정시간동안 주기적으로 memcached를 조회해서 key가 있을때까지 대기하는 방법으로 어느정도 해결 가능할 거라 생각하지만 구현은 하지 않았습니다.

[CODE type=php]
array(‘127.0.0.1:11211’), ‘debug’ => false, ‘persistant’ => false));

function generate_value($key) {
sleep(5);
return “VALUE”. $key;
}

function get_value($key) {
global $mc;
$expire = 60;
$grace_timeout = 600;
$generation_timeout = 10;

$state = $mc->get($key.”_s”);
//echo(“state=$state
\n”);
if ($state == “C” || $state == “G”) {
$value = $mc->get($key);
if ($value) {
//echo(“retreive key=$key
\n”);
return $value;
}
}

$mc->set($key.”_s”, “G”, $generation_timeout); // state: Generating
$value = generate_value($key);
$mc->set($key, $value, $expire + $grace_timeout);
$mc->set($key.”_s”, “C”, $expire); // state: Cached
//echo(“insert key=$key
\n”);

return $value;
}

get_value(“hahaha”);
?>

[/CODE]

memcachedb = memcached + Berkeley DB

memcached가 메모리에만 저장되기 때문에 서버 재시작하면 내용이 모두 날라갑니다. memcached가 캐시에 최적화되어 개발되어 있기때문에 당연한 거지만… 사용법이 간단하고, 퍼포먼스가 좋다보니 memcached의 간편함과 DB의 persistence를 모두 충족할수 있는 프로그램을 찾게되는듯하네요.

memcachedb는 memcached와 Berkeley DB(오라클이 인수했더군요)를 이용하여 만들어졌으며, 클라이언트는 memcached 프로토콜을 이용하여 접속하며, key, value는 메모리가 아니라 DB에 저장됩니다. 단순한 구조로 되어 있기 때문에 복잡한 DB에 비하면 훨씬 더 빠르게 동작합니다. 또한 replication을 지원하기 때문에, read를 분산하여 처리할수 있습니다. 다만, memcached처럼 여러개의 서버를 파티션해서 사용할수는 없습니다. replication으로 연결하면 write은 모든 서버에서 일어나게 됩니다.

memcachedb와 유사한 프로젝트로 tugela cache가 있습니다. 현재 소스가 더이상 관리가 되지 않고 있지만,  tugela cache도 memcached와 Berkeley DB를 이용하여 만들어졌습니다. memcachedb와의 차이점은 persistency를 추구하지 않는다는 점입니다. 메모리보다 많은 캐시가 필요할때 디스크에 쓰는 형태입니다. replication이 없고 memcached와 마찬가지로 read/write를 모두 분산할수 있습니다. memcached에서 캐시 사이즈가 메모리보다 클때 사용하기에는 memcachedb보다는 tugela cache가 적절합니다.

회사에서 세션정보를 저장하는 데몬을 직접 작성하여, 메모리로 세션을 관리하고, 주기적으로 세션정보를 파일로 쓰고, 시작할때
파일에서 세션정보를 읽도록 해서 관리하는데 이거 작성하는것도 일이죠. 이럴 경우 memcachedb를 이용하면 좋을듯하네요…

repcached – memcached + replication

repcachedmemcached에 리플리케이션(replication) 기능을 추가한 프로그램입니다.

memcached가 cache이기 때문에 세션정보등을 저장하기는 좀 불안한 면이 있죠. 그래서 memcached(repcached)를 두개 띄워놓고, 하나가 중단되더라도 replication을 해두면 보다 안정적으로 서비스 운영이 가능합니다.

repcached 서버를 두군데 띄우고 양쪽으로 리플리케이션 되도록 세팅하면 한쪽에 key,value를 입력하면 다른 서버에도 같은 key,value가 입력됩니다. 그리고 서버 재시작할때 다른쪽 서버의 모든 key,value를 받아오도록 되어있으니, memcached를 재시작해야하거나 서버의 문제로 종료된 경우 캐시를 전부 날리지 않아도 됩니다.

그리고 memcached 클라이언트 라이브러리를 그대로 이용할수 있으므로, 클라이언튼 쪽은 서버에 양쪽 서버 주소만 등록해주면 됩니다.

repcached는 memcached의 패치입니다. 따라서 컴파일하면 memcached 파일이 생성됩니다. 저는 혹시를 위해서 실행파일명을 repcached로 변경하여 설치했습니다.

아래처럼 두개의 호스트에서 repcached를 실행하면 모든 key,value가 공유됩니다.

10.0.0.2> repcached -m 128 -l 10.0.0.2 -p 4001 -d -x 10.0.0.3

10.0.0.3> repcached -m 128 -l 10.0.0.3 -p 4001 -d -x 10.0.0.2

한가지 불편한점은 하나의 호스트에서 리플리케이션하도록 세팅이 불가능해보입니다. -X로 replication에 사용하는 포트를 지정할수는 있지만, 상대편의 replication 포트를 지정하는 옵션이 없어서 어떻게 세팅해야할지 모르겠네요. 하지만 두개의 서버에 나누어 실행하는게 더 안전하므로 실제 서비스 적용할때는 크게 문제가 되지 않을거라 생각되네요.

memcached와 성능상의 차이가 얼마나 있는지는 테스트해봐야할듯하네요.

그리고 memcached와 마찬가지로 메모리가 부족하면 임의의 key,value를 지울듯한데, 세션정보등을 repcached에만 의존해도 되는지 의문이 드네요.

캐시가 날라가면 캐시를 채울때까지의 서버 부하 감소용으로 사용하면 좋을듯하네요. 그리고 read를 분산하는 효과도 있겠죠.