캠핑과 개발

1. 데몬(daemon) 이란?
 주기적인 서비스 요청을 처리하기 위해서 커널상에 백그라운드 모드로 실행되는 프로세스로, 메모리 관리 방법에 따라 단독 데몬과 xinetd로 분리된다.

단독데몬
 항상 백그라운드 모드로 실행되고 메모리를 상대적으로 많이 소비한다. 그러나 서비스(응답속도)가 빠르다. httpd와 같은 웹서비스 데몬이 대표적.
xinetd(슈퍼데몬)
 요청이 있을때마다 xinetd가 서비스를 싱행시켜주므로 메모리 소비가 적다. 그러나 단독데몬에 비해 상대적으로 서비스 속도가 느리다.


 2. 간단한 자바 데몬 만들기
 nohup을 이용해서 java를 실행시킨다.

 터미널이 종료될 때(쉘이 종료될 때) 프로세스가 죽는 이유는 해당 프로세스가 쉘의 자식 프로세스 이기 때문이다. 따라서, 부모 프로세스가 죽을대 던지는 SIGHUP을 자식 프로세스가 받게 된다.

 nohup은 부모 프로세스가 죽을때 자식 프로세스에게 SIGHUP을 던지지 않는 프로세스를 말한다.
$ nohup java 클래스명 &

  
 사용하기 편한 장점은 있으나, 문제는 중지를 시킬수 없다. 즉, 해당 프로세스 ID를 찾아내 kill하는 수 밖에 없다. 물론 파일 체크 기법, 소켓을 이용한 제어 방법등을 사용할 수 있지만 스스로 구현해야 하는 번거로움이 있다.


 3. apache commons daemon 이용하기
 Java는 UNIX의 시그널 처리를 할수 없기때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야한다. 이런 번거로움을 해결하기 위해 자카르타의 하위 프로젝트중의 commons daemon을 이용한다. commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.

 ** 다운로드: http://commons.apache.org/daemon/

 UNIX용 Jsvc와 윈도우용 Procrun 있다.
 여기서는 Jsvc를 이용해보도록 하겠다.

 

 commons daemon을 다운로드해 압축을 해제하면 위 그림과 같다.
 commons-daemon.jar 파일은 Java프로젝트 lib폴더에 복사해둔다.

 


 bin폴더의 압축파일을 해제하면 jsvc-src라는 폴더가 나온다.
 폴더의 내용은 위와 같다.
 commons daemon을 사용하기 위해서는 바로 여기서 jsvc를 빌드해줘야 한다.
 빌드환경은 다음과 같다.(리눅스에서 빌드해야한다.)

GNU AutoConf(at least 2.53)
ANSI-C compliant compiler(GCC is good)
GNU Make
A Java Platform 2 compliant SDK

 여기서부터는 ubuntu 8.10 환경에서 진행하도록 한다.

 먼저 JDK가 설치되어 있지 않다면 JDK를 설치한다.
 $ sudo apt-get install sun-java6-jdk


 JDK가 설치되는 경로는 /usr/lib/jvm/java-6-sun 이다.

 gcc 및 make 가 설치되있지 않다면 아래 명령를 이용해 한방에 설치한다.
 $ sudo apt-get install build-essential


 AutoConf가 설치되있지 않다면 AutoConf를 설치한다.
 $ sudo apt-get install autoconf


 Jsvc를 빌드하는 방법은 다음과 같다.

support/buildconf.sh
./configure --with-java=/usr/lib/jvm/java-6-sun
make


참고 방법

mkdir /root/commons-daemon

cd /root/commons-daemon

wget http://www.apache.org/dist/commons/daemon/binaries/1.0.5/commons-daemon-1.0.5.jar
wget http://mirror.apache-kr.org//commons/daemon/source/commons-daemon-1.0.5-src.tar.gz
tar zxvf commons-daemon-1.0.5-src.tar.gz
cd commons-daemon-1.0.5-src/src/native/unix/
support/buildconf.sh
./configure --with-java=/opt/jdk1.6.0_24/
make
mv jsvc /root/commons-daemon

 

 빌드가 성공적으로 이루어졌다면 위 그림과 같이 jsvc가 만들어진것을 확인할 수 있다. 이후 이 파일을 가지고 Java 데몬을 실행한다.

 Java 데몬을 만들려면 org.apache.commons.daemon.Daemon 인터페이스의 init, start, stop, destory 메소드를 구현해야 한다.


샘플

package com.bagesoft.test.daemon;
 
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
 
public class TestDaemon implements Daemon, Runnable {
    private String status = "";
    private int no = 0;
    private Thread thread = null;
 
    @Override
    public void init(DaemonContext context) throws DaemonInitException,
            Exception {
        System.out.println("init...");
        String[] args = context.getArguments();
        if (args != null) {
            for (String arg : args) {
                System.out.println(arg);
            }
        }
        status = "INITED";
        this.thread = new Thread(this);
        System.out.println("init OK.");
        System.out.println();
    }
 
    @Override
    public void start() {
        System.out.println("status: " + status);
        System.out.println("start...");
        status = "STARTED";
        this.thread.start();
        System.out.println("start OK.");
        System.out.println();
    }
 
    @Override
    public void stop() throws Exception {
        System.out.println("status: " + status);
        System.out.println("stop...");
        status = "STOPED";
        this.thread.join(10);
        System.out.println("stop OK.");
        System.out.println();
    }
 
    @Override
    public void destroy() {
        System.out.println("status: " + status);
        System.out.println("destroy...");
        status = "DESTROIED";
        System.out.println("destroy OK.");
        System.out.println();
    }
 
    @Override
    public void run() {
        while (true) {
            System.out.println(no);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (no > 1000) {
                break;
            }
            no++;
        }
    }
}


init에서 초기화, start에서 처리할 작업을 별도의 쓰레드로 생성해서 실행한다. start 메소드 호출후 반드시 return 되어야 데몬이 시그널 처리를 제대로 할 수 있다.
 stop, destroy 는 중지 신호가 오면 차례되로 호출된다.


 이제 실행/중지 스크립트를 작성한다.
 Jsvc를 싱행하는데 필요한것은 실행하는 계정(user), JAVA_HOME(-home), 프로세스ID 파일(-pidfile), 출력지정(-outfile, -errfile), 클래스파일(-cp) 등이 있다.


JAVA_HOME=/opt/jdk1.6.0_24
JSVC=/root/commons-daemon/jsvc
USER=root
 
DAEMON_HOME=/root/commons-daemon
PID_FILE=$DAEMON_HOME/daemon.pid
OUT_FILE=$DAEMON_HOME/daemon.out
#ERR_FILE=$DAEMON_HOME/daemon.err
 
CLASSPATH=\
$DAEMON_HOME/commons-daemon-1.0.5.jar:\
$DAEMON_HOME/BageSoft.jar
 
MAIN_CLASS=com.bagesoft.test.daemon.TestDaemon
case "$1" in
  start)
    #
    # Start Daemon
    #
    rm -f $OUT_FILE
    $JSVC \
    -user $USER \
    -java-home $JAVA_HOME \
    -pidfile $PID_FILE \
    -outfile $OUT_FILE \
    -errfile $OUT_FILE \
    -cp $CLASSPATH \
    $MAIN_CLASS
    #
    # To get a verbose JVM
    #-verbose \
    # To get a debug of jsvc.
    #-debug \
    exit $?
    ;;
 
  stop)
    #
    # Stop Daemon
    #
    $JSVC \
    -stop \
    -nodetach \
    -java-home $JAVA_HOME \
    -pidfile $PID_FILE \
    -outfile $OUT_FILE \
    -errfile $OUT_FILE \
    -cp $CLASSPATH \
    $MAIN_CLASS
    exit $?
    ;;
 
  *)
    echo "[Usage] TestDaemon.sh start | stop"
    exit 1;;

esac 

 

이제 Java 데몬을 실행하기 위한 모든 준비를 마쳤다.

위에서 작성한 스크립트 파일을 이용해 Java 데몬을 실핸한다.
 정상적으로 데몬이 시작된다면 PID_FILE에 지정한 파일이 생성된것을 확인할 수 있다.

 

 

데몬을 중지하려면 start 대신 stop을 입력으로 스크립트를 실행하면 된다.


[출처] http://ultteky.egloos.com/10877963

'개발 > Java' 카테고리의 다른 글

자바 정규표현식  (0) 2012.05.17
대용량 데이터 처리를 위한 JAVA Tunning(튜닝)  (0) 2012.05.17
Quartz 문서  (0) 2011.07.13
[JAVA] 동적 캐스팅  (0) 2011.06.10
log4jdbc를 활용하여 쿼리 로그 남기기  (0) 2011.06.01