날짜 작성/수정 내용
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분 정도 벌어줄수 있다는 계산이 나옴(조금 애매한 수치)

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

  • 이 문서의 목적은 아파치 및 이클립스 등 에서 사용자 정의 확장자를 추가하는 방법을 다룬다.
  • 아래 내용들은 모두 PHP 의 확장자로 .kp 를 추가로 등록하는 방법을 설명한다.

Apache Server 에서 추가하기

  1. httpd.conf 파일을 vi 등의 에디터로 열어준다.
  2. "AddType application/x-httpd-php .php" 라는 줄 밑에 "AddType application/x-httpd-php .kp" 를 추가해준다. (설마 큰따옴표 까지 넣는 사람은 없겠지?)
  3. 아파치 서버를 재 시작 시켜주면 적용된다.

Eclipse 에서 추가하기

  1. 메뉴중 Window -> Preferences 로 들어간다.
  2. 좌측 트리에서 General -> Content Types 를 선택한다.
  3. 우측 트리에서 Text -> PHP Content Type 를 선택한다.
  4. "Add..." 버튼을 클릭한다.
  5. "Add Content Type Association" 창이 열리면 "Content type:" 란에 "*.kp" 를 입력하고 OK 버튼 클릭
  6. Preferences 창에서 OK 버튼 눌러주면 끝

 

'기술노트' 카테고리의 다른 글

윈도우즈에서 SVN 저장소 GIT 로 옮기기  (0) 2015.02.23
Predis pipeline 효용 연구  (0) 2012.06.12
REDIS 연구노트  (5) 2012.05.17
드래곤퀘스트 던전 R

"드래곤퀘스트 던전R" 입니다. 20주년 기념판 이라네요.



조용한 던전에서 아름다운 공주와 평화롭게 살고 있는 대마왕에게 시련이 닥쳤습니다. 어떤 몹쓸 놈이 우리 던전을 약탈하고 공주를 납치하고 심지어 착한 대마왕과 부하(몬스터) 들을 살륙하러 온 것이지요.
알고 보니 이 놈은 이웃 던전의 보스(감히 스스로 대마왕이라 칭하고 있다고 합니다)에게 고용되서 쳐들어 온 놈이라고 합니다.

당하고 있을 수 만은 없습니다. 착한 우리의 진짜 대마왕도 용사를 고용해 이 나쁜 가짜 대마왕의 처치를 의뢰 하게 됩니다.

이제 플레이어들은 착한 대마왕과 용사를 도와 던전을 지키면서 이 극악한 가짜 대마왕을 해치워야 합니다.
먼저 상대방의 보스를 해치우기만 하면 우리 던전에 쳐들어온 몹쓸 놈도 알아서 물러날 것 입니다.(어차피 용병인데 고용주 없으면 싸울 필요가 없죠)

그럼 대마왕 잡으러 ㄱㄱ~

이런 나쁜 놈들! 가짜(?) 대마왕 군단 입니다.


먼저 각자 던전을 만들어야 합니다. 서로 보지 못하게 칸막이를 친 뒤에 게임보드, 28개의 벽, 대마왕, 몬스터 7마리, 공주 1명, 보물상자 6개, 함정, 사다리, 지하1층 입구, 지하2층 입구로 이쁘게 꾸며 봅시다.

던전 만들 때는 다음 규칙만 지키면 됩니다.

1. 보드 한칸엔 하나의 컴포넌트만 놓읍시다. 친구랑 게임 하는데 벽위에 몬스터를 올려놓았더군요 -_-;
2. 지하1층 입구와 함정은 지하 1층에 놓아야 합니다.
3. 지하2층 입구와 사다리는 지하 2층에 놓아야 합니다.
4. 이게 제일 중요합니다! 보스를 지나치지 않고 들어갈수 없는 곳에 다른 보물상자, 공주, 몬스터, 함정 을 놓아서는 안 됩니다.

게임보드 좌측의 지하 1층 부분 입니다.


G4 에 위치한 보라색 용이 대마왕(보스) 입니다.
저 멀리 나쁜놈 에게 잡혀 갈까 오들오들 떨고 있는 가련한 공주의 모습이 보이는 군요. ㅎㅎ
우측 상단의 3단짜리 계단이 입구 이고 맨 좌측 하단에 있는 것은 함정으로 밟으면 지하 2층으로 떨어지게 됩니다.

게임보드 우측의 지하 2층 부분 입니다. 



용사 피규어는 던전에 놓는게 아니라 지하 2층 부분 위에 공격력 5라고 쓰인 곳에 두면 됩니다. 이는 우리 용사의 공격력이 5 라는 걸 표시 하는건데 나중에 공주를 구출하면 6으로 레벨업이 됩니다.

위에서 찍어 봤습니다.



실제 만들 때는 최대한 길을 꼬아서 만들어 주세요~ ^_^

가리개를 하고 멀리서 찍어보았습니다.(물론 설정샷 입니다.)



각도를 바꿔 옆에서도 한 컷.



각자 던전을 완성 하였다면 상대방에게 자기 던전의 지하 1층 입구와 보스의 위치를 알려 줍니다. 즉 시작 지점 뿐만 아니라 최종 목표 지점까지 알고 시작하는 것 입니다. 탐험 용지 에 상대방 던전의 스타트 지점(지하1층 입구) 과 보스의 위치를 표기 합니다.

탐험 용지. 이렇게 생겼습니다.



근데 B 열과 D 열이 왜 없냐구요? 게임 메뉴얼에 보면 B와 D는 발음이 비슷해서 뺐다고 나와있군요 ^^;

이제 주사위를 굴리던 가위바위보를 하던 나이로 따지던 먼저 시작할 사람을 정합니다.(원래는 주사위였던가?)

본격 적인 던전 약탈 아니 탐험을 나서기 전에 우선 탐험 용지에 표기 하는 방법을 알아 봅시다. 기본적으로 가본 장소는 O 를 벽으로 막힌 곳은 X 를 표기 합니다. 게임을 처음 시작한 직후 라면 스타트 지점인 던전 1층 입구에만 O 가 그려져 있겠지요.

자 당신의 턴이 되었나요? 그럼 이제 상대방의 던전을 탐험 합니다. 물론 어디가 막혀있고 어디에 몬스터가 숨어있는지 보물상자와 공주의 위치등은 전혀 모르는 상태 입니다.

이동 방법은 간단 합니다. 탐험 용지에 쳐져 있는 O 들 중 아무 곳 이나 하나 를 골라 상하좌우 인접한 곳(대각선 방향은 안됩니다)들 중 아직 가보지 않은 좌표로 이동 하겠다고 상대방에게 알려주면 됩니다.
즉, S가 시작 지점이라고 할 때 현재 탐험 용지에 다음과 같이 그려져 있다면

A C E F
1 X
2 S
3 O X
4 O O
5 X



이동 시도가 가능한 장소는 A2, A3, A4, E2, E5, F4 의 6군데 인 것 입니다.

자 아뭏든 한 칸을 골라 좌표를 상대방에게 불러 주면 상대방은 그 곳에 뭐가 있는지를 알려 줍니다. 다음과 같은 상황이 나올때 까지 당신의 턴은 유지되고 계속 해서 O 등의 표시를 하면서 이동이 가능 합니다.

턴이 끝나는 경우는 다음과 같습니다.

1. 벽에 부딪친 경우
2. 몬스터를 만나서 전투를 벌였는데 졌을 경우
3. 보물상자를 발견해서 열기로 했는데, 보물상자 괴물인 "미믹" 이 나와 전투를 했는데 진 경우
4. 보스를 만나서 전투를 벌였는데 졌을 경우

단 1.의 경우는 "시간의 모래" 카드로 2. 나 3. 의 경우는 "세계수의 잎" 카드로 턴이나 전투를 계속 할 수 있습니다.

던전을 탐험하다 보면 함정을 밟을 수도 있습니다. 함정을 밟을 시 지하 2층으로 떨어지게 되고 상대방은 지하 2층 입구의 좌표를 불러 줍니다. 함정에 떨어져도 턴은 끝나지 않고 계속 이어 집니다. 다만 사다리를 찾기전에는 지하 1층으로 올라오지 못하게 됩니다. 지하 2층을 헤매다 사다리를 찾게 되면 이후 지하 1층, 2층을 마음대로 오갈 수 있습니다.

게임 시작시 우리 용사의 공격력은 5 입니다. 만약 탐험 중 공주를 만나면 레벨업을 하여 공격력이 6이 됩니다. 상대방 던전에서 공주 피규어를 곱게 보드에서 제거하고 울 편 용사 피규어를 공격력 5에서 6으로 이동 합니다.

보물 상자는 6개가 있는데 이중 2개에는 선배 용사인 로토가 사용하던 무구 "로토의 검" 과 "로토의 갑옷" 이 숨겨져 있고 나머지 4개는 보물상자 괴물인 "미믹" 이 숨어 있습니다. 보물 상자를 발견시 열지 말지 정할 수 있습니다.

1. 안 열기로 결정한 경우
탐험 용지에 보물상자 위치만 표시해 두고 계속 턴을 진행 합니다.
이렇게 발견만 하고 열지 않은 보물상자는 자신의 턴 아무때나 몇 개 든지 열어볼 수 있습니다.
2. 열었는데 용사의 무구가 나온 경우
그 보물상자 컴포넌트를 가져와서 자기 앞에 두고 계속 턴을 진행 합니다.
3. 열었는데 "미믹"이 나와 싸웠는데 이긴 경우
보물 상자를 보드에서 제거하고 턴을 계속 진행 합니다.(몬스터를 잡았을때와는 달리 카드를 받지 않습니다.)
4. 열었는데 "미믹"이 나와 싸웠는데 진 경우
턴을 멈추고 그 보물상자는 상대방 보드에서 제거 합니다.

몬스터나 미믹 또는 대마왕 을 만났을 경우는 반드시 전투를 벌여야 합니다.(도망 못가요~)

각 몬스터 피규어 아래쪽에는 방어력이 표시되어 있습니다. 8이 셋, 9가 셋, 10이 하나, 그리고 미믹은 11 이고 대마왕은 15 입니다. 전투방법은 간단 합니다. 주사위를 굴려서 나온수에 용사의 공격력을 더해 합한 수가 적의 방어력 이상이면 이깁니다.

만약 방어력이 9인 몬스터와 싸울 경우 :
공주를 구하기 전이라면 용사의 공격력이 5 이므로 주사위 수가 4,5,6 이면 이기고 1,2,3 이면 지는 겁니다.
공주를 구한 뒤라면 공격력이 6 이므로 주사위 수가 5,6 이면 이기겠죠.
미믹은 방어력이 11 이므로 공주를 구하지 않았다면 6이 나왔을 경우만 간신히 이길 수 있습니다.

물론 아이템 카드를 이용해 적을 일격사 하거나 공격력 +1 등이 가능 합니다. 단 아이템 카드는 대마왕에게 절대 사용하지 못 합니다.

일반 몬스터나 미믹과 싸워 이긴 경우 아이템 카드 한장을 받고 턴을 계속 진행 합니다.
패배인 경우 턴이 끝납니다. 몬스터나 보물상자 피규어는 던전에서 제거 합니다. 즉 전투는 1회인 것이지요.

아이템 카드는 모두 9 종류 입니다.



근데 가만 보니 대마왕은 방어력이 무려 15 입니다. 공주를 구하고 주사위 눈이 6이 나오더라도 6+6은 12 절대 못이깁니다;; 그래서~ 선배 용사 로토의 무구 가 필요한 것 입니다. "로토의 검" 과 "로토의 갑옷" 은 각각 용사의 공격력을 3씩 올려줍니다. 오우 강력하죠. 다만 로토의 무구는 일반 몬스터나 미믹과 전투시에는 효과가 없습니다. 온리 대 대마왕 병기 인 것 이지요.

대마왕과 싸워 이긴 경우는 게임에 승리 합니다. 지면 그냥 턴을 넘기면 됩니다.

게임이 끝난 후 탐험 용지 입니다.



리뷰를 쓰려 했는데 써놓고 보니 그냥 준 메뉴얼을 쓴 듯한 느낌이군요.

회사분께서 겜 한판 하자고 꼬시셔서 쭐래쭐래 쫓아갔다니 요런 귀여운 놈이 있는거 아니겠습니까?(컴포넌트가 넘 이뻐요~ >.<) 룰 설명 듣고 즉시 한판 했지요. 처음 던전 만드는데 조금이라도 더 사악하게 만들어 보려고 이리 저리 궁리 했는데 결국 이도 저도 아니게 만들었다는 암울한 상황이
ㅠ.ㅠ 결국 졌죠.

가벼운 룰의 게임 이지만 자신만의 던전을 꾸미는 재미와 나름대로 저 사람이 어딜 막고 어디로 길을 뚫어 놨을까 고민하는 맛이 쏠쏠 합니다. 설마 이런 뻔한 곳에 길이 있진 않겠지 그럼.. 여기닷! 하고 A7 하면 "네~ 벽입니다" (-_-;;)

그리고 길 꼬아 놓는 다고 지그재그로 벽을 놔두는데 상대방이 요리 조리 잘도 피해서 울 이쁜 대마왕에게 접근할때의 허무함이라니

둘 이서 가볍게 한 겜 하고 싶을 때 좋은 게임 같습니다.

게임시에 한가지 더 유의할 점은 상대방이 부르는 좌표에 답할 때 내 던전을 보고 알려줘야지 탐험 용지를 보고 알려주시면 안 됩니다~ ^^

 

+ Recent posts