날짜 작성/수정 내용
2012-06-12 김광훈 주제 생성

Summary

  • 이 문서는 predis 를 사용 복수개의 명령을 순차적으로 실행하는 경우와 Class Predis\Pipeline\PipelineContext 를 이용한 경우의 실행 속도에 대한 비교 테스트 이다.
  • 접속은 "단일 redis 서버 접속" 인 경우와 "3대의 redis 서버로 이루어진 cluster" 에 접속한 경우를 각각 측정
  • 테스트 항목은 접속 방법 별로 아래 3가지를 각각 5회씩 수행.
    • 단일 key 업데이트 테스트 : 단일 key 에 대하여 10000회의 incrby 실행
    • 복수 key 에 set 테스트 : 10000개의 새로운 key 에 set 하기
    • 복수 key 업데이트 테스트 : 3개의 key 의 값들을 구한후 변경하여 다시 set 하기 를 10000회 반복
  • 각 테스트 시작 전에는 flushdb 를 실행하여 db 를 비웠다.
  • 시간 측정은 php 의 microtime() 를 사용하였고 redis 서버 접속 직후 부터 시간을 측정했다.

pipeline 프로세스

  • predis 에서 지원하는 pipeline 은 다음과 같이 구현된다.
    1. 클러스터를 이루는 redis 서버들 중에서 해당하는 key 들에 필요한 서버들에 모두 접속을 한다.( class Predis\Network\ConnectionBase 의 함수인 tcpStreamInitializer() 에서 실제 접속 처리를 한다. )
    2. 모든 명령들을 php 의 배열 변수에 저장한다. ( class Predis\Pipeline\PipelineContext 의 멤버변수인 $pipeline 에 저장됨)
    3. class Predis\Pipeline\PipelineContext 의 함수 flushPipeline 에 의해 redis 명령 실행기에 클러스터 접속 정보와 배열 $pipeline 을 전달한다.
    4. 여기서 명령 실행기는 class Predis\Pipeline\StandardExecutor 의 객체가 된다. 이 객체의 함수 execute 에 의해 배열의 명령들이 실행되게 된다.
  • 위에서 살펴본 실행 구조상, 배열에 있는 명령들 실행중에 웹서버가 죽게되면 그 전까지의 명령들만 실행이 되고, 나머지 명령들은 실행이 되지 않게 된다.

단일 key 업데이트 테스트

  • 소스
// pipeline 사용
$pipe = $m->predis->pipeline();
for($i=0;$i<10000;$i++) {
	$pipe->incrby('counter', 10);
}
$pipe->execute();


// 순차적 실행
for($i=0;$i<10000;$i++) {
	$m->predis->incrby('counter', 10);
}
  • 결과(seconds)
회차 1 2 3 4 5
pipeline 사용(단독접속) 0.6191 0.6413 0.8552 0.8497 0.6428
순차적 실행(단독접속) 4.7250 4.6734 4.7344 4.6071 4.6769
pipeline 사용(멀티접속) 0.7360 0.6427 0.7284 0.7145 0.6962
순차적 실행(멀티접속) 4.8469 4.9195 4.8138 4.8543 4.8286

복수 key 에 set 테스트

  • 소스
// pipeline 사용
$pipe = $m->predis->pipeline();
for($i=0;$i<10000;$i++) {
	$pipe->set("testkey:" . $i, $i);
}
$pipe->execute();


// 순차적 실행
for($i=0;$i<10000;$i++) {
	$m->predis->set("testkey:" . $i, $i);
}
  • 결과(seconds)
회차 1 2 3 4 5
pipeline 사용(단독접속) 0.5373 0.4848 0.4698 0.4656 0.4815
순차적 실행(단독접속) 4.7094 4.7027 4.6585 5.2510 4.7227
pipeline 사용(멀티접속) 1.6480 1.9329 1.8257 1.8132 1.8297
순차적 실행(멀티접속) 4.9077 5.0084 4.9053 4.8194 4.9204

복수 key 업데이트 테스트

  • 소스
// pipeline 사용
$m->predis->set("testkey:0", 10);
$m->predis->set("testkey:1", 10);
$m->predis->set("testkey:2", 10);
for($i=0;$i<10000;$i++) {
	
	$pipe = $m->predis->pipeline();
	
	$pipe->get("testkey:0");
	$pipe->get("testkey:1");
	$pipe->get("testkey:2");
	$replies = $pipe->execute();
		
	$testkey0 = $replies[0] + 5;
	$testkey1 = $replies[1] + 5;
	$testkey2 = $replies[2] + 5;
	
	$pipe->set("testkey:0", $testkey0);
	$pipe->set("testkey:1", $testkey1);
	$pipe->set("testkey:2", $testkey2);
	$pipe->execute();
}

// 순차적 실행
$m->predis->set("testkey:0", 10);
$m->predis->set("testkey:1", 10);
$m->predis->set("testkey:2", 10);
for($i=0;$i<10000;$i++) {

	$testkey0 = $m->predis->get("testkey:0");
	$testkey1 = $m->predis->get("testkey:1");
	$testkey2 = $m->predis->get("testkey:2");

	$testkey0 += 5;
	$testkey1 += 5;
	$testkey2 += 5;

	$m->predis->set("testkey:0", $testkey0);
	$m->predis->set("testkey:1", $testkey1);
	$m->predis->set("testkey:2", $testkey2);
}
  • 결과(seconds)
회차 1 2 3 4 5
pipeline 사용(단독접속) 14.0392 15.1118 15.2008 14.6502 14.8247
순차적 실행(단독접속) 28.8113 29.9251 28.4175 28.7168 28.8193
pipeline 사용(멀티접속) 19.4469 19.8281 19.5141 19.1568 18.7124
순차적 실행(멀티접속) 29.7012 29.5887 29.4990 29.7207 29.7363

정리

  • predis 에서 제공하는 pipeline 은 다음과 같이 이루어진다.
    1. php 단에서 배열변수에 redis 명령들을 저장한다.
    2. redis 명령들의 저장이 끝나면, 소켓을 통해 명령을 순서대로 서버에 보내 실행한다.
    3. redis 명령들의 실행이 끝나면, 소켓을 통해 결과를 순서대로 읽어온다.
    • 즉, 명령이 모이는 곳은 웹서버(PHP) 단 이므로 배열에 저장된 명령들이 실행되는 중간에 웹서버가 crash 되버리거나 웹서버와 redis 서버와의 접속이 끊어지면 아직 실행되지 않은 명령들은 유실되어 버린다.
  • 복수개의 redis 명령들을 pipeline 을 사용하여 실행하는 방법의 장단점은 (절차적으로 실행하는 경우에 비교할 때) 다음과 같다.
    • 장점 : 명령실행 속도가 조금이라도 빠르며, 특히 명령이 아주 많은 경우는 압도적으로 빨라진다. 이에 서비스 용으로 보다는 DB 관리등의 목적으로 쓰는것이 더 유용하다.
    • 단점 : 결과를 나중에 한꺼번에 받아오기 때문에 중간에 실행된 redis 명령의 결과를 이용하여 redis 명령을 실행하는 것은 불가능하다. 명령의 결과를 이용하기 위해서는 일단 pipeline 의 버퍼에 쌓인 명령들을 다 처리한 후 다시 pipeline 을 사용하던가 해야 한다.
  • 약간 억지로 효율 계산
    • 홍콩 웹서버 5대에서 12/Jun/2012 하루 처리한 명령의 수가 대략 1,570,000 건
    • redis 멀티서버 접속으로 "복수 key 업데이트 테스트" 의 효율을 적용하면 API 명령 10,000 건당 10초의 시간을 아낄수 있음
    • API명령 10,000 건 : 10 sec = 1,570,000 : ? 하면 대충 1,570 sec 즉 26분 정도의 시간이 나옴
    • 파이프라인 사용시 (절자척 명령 실행에 비해) 일일 웹서버들 의 시간을 26분 정도 벌어줄수 있다는 계산이 나옴(조금 애매한 수치)

+ Recent posts