블로그 이미지
JEEN

서울에 사는 꽃청년의 IT찌질모험기

Rss feed Tistory
IT/Perl 2008.12.04 17:05

[ Perl, PHP ] Job Queue 를 통해 친해지길 바래?


  현재 진행중인 프로젝트의 구성에서... Web 은 PHP 로 다른 사람에 의해 만들어 지고 있고, 백그라운드에서 작동하는 녀석은 제가 Perl 로 쓰고 있습니다.

2008/11/18 - [IT] - [ Selenium ] 웹서비스 테스트 자동화와는 별 상관없는 작업을 위해...
2008/11/18 - [IT] - [ Selenium ] Selenium RC 를 사용해보자. I
2008/11/19 - [IT] - [ Selenium ] Selenium RC 를 사용해보자. II

  이전 Selenium 을 소개했을 때, Test용이 아닌 용도로 사용한다고 했던 게 이것을 위해서 인데요. 웹에서 어떤 파라메터를 날리면 Selenium 쪽에서 그 파라메터를 받아서 백그라운드에서 열심히 달리는 구조입니다.
  그럼 웹에서 어떻게 Selenium 쪽으로 파라메터를 넘겨줄까요?
  제일 간단하게 생각할 수 있는 것이...
  Web 에서 직접 Selenium 을 기동하는 것, 하지만 한번 움직이면 Selenium 으로 5초 이상의 딜레이가 생기는 것은 어쩔 수 없겠죠. Web 에서 이 5초이상 이란 시간은 참 기다려주기 애매할 수 있습니다. 심하면 30초까지 생각할 수 있으니까요.
  다른 방법이 있습니다. 좀 하드코어한 방식으로는 PHP에서 system 으로 ...

  system('perl selenium-work-1.pl doSomething saillinux see fate_stay_night &');

  이렇게 날리는 방법...

  하지만 이런 식이라면 제대로된 파라메터를 날리기 힘듭니다. 예를들어, 다단계 배열이나 해쉬(연상배열) 같은 것을 어떻게 넘기느냐 하면 좀 애매하죠. 뭐 더 하드코어하게 간다면... 매번 파라메터를 JSON 으로 변환해서 이걸 파일로 덤프합니다. 그리고 파일이름을 지정해줄 수도 있겠죠?
 ...
 ...
 설마 이렇게 할 것이라고 생각하는 것은 아니시겠죠?

 제 해법은 Job Queue 입니다. memcached와 Live Journal 의 개발자로 유명하며, 현재 Perl 용 Google App Engine 을 만들고 있는 Brad Fitzpatrick의 Gearman 이 제 눈에 끌렸습니다. TheSchwartz 같은 경우도 생각해 볼 만하지만, TheSchwartz 의 경우라면 전용 DB 를 필요로합니다. 거기에 3-5초 정도의 작업 딜레이도 발생하게 됩니다(3-5초 정도에 한번씩 매번 DB 에 Job 이 등록되었는 지를 확인하기 때문이죠).
  Gearman 은 Client 에서 Job 을 날림과 동시에 Worker 가 움직이게 됩니다.

  Gearman 은 어떻게 입수하느냐. 당연히 CPAN 입니다.
  sudo cpan -i Gearman::Server
  sudo cpan -i Gearman::Client
  sudo cpan -i JSON

  이렇게 cpan 모듈을 인스톨합니다. 중간 중간에 나오는 의존모듈도 같이 인스톨해주시면 됩니다.  Gearman::Server 를 설치하면 gearmand 라는 gearman 데몬용 파일을 실행할 수 있습니다.

  sudo gearmand --daemon --pidfile=/tmp/gearmand.pid --debug=1

  프로세스 리스트를 확인하시면 gearmand 는 데몬으로 작동하는 것을 확인할 수 있습니다.
  그리고 Job 을 날릴 PHP 쪽도 Gearman 라이브러리를 설치해야 합니다. PHP 의 pear 로 간단하게 인스톨 할 수 있습니다.
 
   sudo pear upgrade http://bugs.joestump.net/code/Net_Gearman/Net_Gearman-0.0.4.tgz

  Net_Gearman 의 설치가 끝났다면 php 쪽의 소스는 이와 같습니다.
  client.php
  1. <?php
  2.  require_once 'Net/Gearman/Client.php';
  3.  $data = array( 'who' => 'saillinux', 'what' => 'fate_stay_night', how => 'haak' );
  4.  $pid = getmypid();
  5.  $set = new Net_Gearman_Set();
  6.  $task = new Net_Gearman_Task( 'job', $data, $pid, Net_Gearman_Task::JOB_BACKGROUND);
  7.  $client = new Net_Gearman_Client(array('localhost'));
  8.  $client->runSet($set);
  9. ?>

  짧게 코드를 설명하자면... $data 에 위와 같은 연상배열을 넣고, 6번째에 Task 를 추가합니다.   
  Net_Gearman_Task 에서 첫번째 인수는 function 이름입니다. 어떤 놈에게 일을 시킬까 하는 것인데, 물론 이 function 은 Worker 쪽에 정의되어 있어야 합니다.
  두번째 인수는 Worker 에 넘길 인수입니다. 이 인수는 JSON 으로 파싱해서 넘어가게 됩니다.
  7번째 줄에서 Net_Gearman_Client에서 배열에 localhost 를 넣었습니다. Worker 는 복수의 서버를 지정할 수 있습니다.
  그외에 대해선 문서를 참고하세요.

  위와 같은 Job 이 client 쪽에서 날아온다면, 이것을 받을 Worker 가 기동중이어야 합니다. 그리고 Worker는 아래와 같은 코드로 이루어져 있습니다.
  worker.pl
  1. use strict;
  2. use warnings;
  3. use Gearman::Worker;
  4. use JSON;
  5.  
  6. my $worker = Gearman::Worker->new;
  7. $worker->job_servers(qw/localhost/);
  8. $worker->register_function(
  9.   job => sub {
  10.     my $job = shift;
  11.     my $args = from_json( $job->arg );
  12.     print $args->{who}." ".$args->{how}." ".$args->{what}."¥n";
  13.   });
  14. $worker->work while 1;

  위의 client 에서 job 이라는 function 으로 job 을 날린 것을 $worker->register_function 으로 등록된 job 이라는 function 에서 처리합니다. JSON 으로 넘어온다고 했으니 넘어온 JSON($job->arg)을 해석합니다. 그리고 받은 인수를 찍어냅니다.

  일단 하나의 터미널에서 worker.pl 을 실행시키고, 다른 터미널에서 client 를 실행시킵니다. 그러면 client 에서 job 이 worker 로 넘어가서, worker 는 그 job 에 맞게 정의된 행동을 수행하겠죠.

  그럼 예외의 경우를 살펴보도록 하자면...
  client 에서 job 은 계속 날리는 데, worker 는 죽어있는 상태입니다(이런 상황이 걱정된다면 worker 를 여러개 띄워놓는 것도 한 방법이 될 수도 있습니다). 이렇게 되면 일하는 놈이 없으니까 당연히 일은 못하게 됩니다. job 은 계속 queue 에 쌓여 있겠죠. 그리고 worker 가 살아난다면, 쌓여있는 job 을 하나씩 처리해나가게 됩니다. gearmand 가 어느 정도 큐에 담아둘 수 있는 지는 잘 모르겠습니다. 메모리 여유분 만큼이려나요?
  그럼 gearmand 데몬 자체가 job 을 잔뜩 쌓아놓고 있는데 죽어버렸다면 어떻게 될까요? 이경우는 queue 에 쌓인 job 은 소실됩니다. 그래서 불안하시다면, TheSchwartz 나 Q4M 을 써서, DB 에 job 을 넣는 형식을 쓰는 것도 선택중의 하나가 되겠죠.
  (피드백 주신 a3r0/Luz_Luna님++)

  뭐, 제가 하려는 건 Selenium Agent 를 가동하기 위해 적당한 인수를 받아서 넘겨주는 것 밖에 없으니까요.
  아무튼 이런 식으로 Perl 과 PHP 간의 유대관계를... 쿨럭.. 아니, 그것보다 이런 식으로 Web 상에서 처리하기에는 좀 지지부진한 처리를 Job Queue 를 통해서 해결해보시는 것은 어떠실런지요?
  뭐 관리의 문제를 제외한다면(제외하기 힘들겠지만)... 여러명이 각자의 특색에 맞는 언어를 선택하는 것은 나쁘지 않다고 생각합니다. 저마다의 개성이겠죠. (물론 사람에 따라서 나쁘다고 생각하실 분도 있으시겠죠...;;)

  http://ido.nu/kuma/2008/01/20/implemented-reblogging-server-with-gearman/
 
  위의 링크를 참고로 했습니다.
신고
TOTAL 464,340 TODAY 49

티스토리 툴바