http://ir.bagesoft.com/640
1. 데몬(Daemon)이란
Daemon 이란 백그라운드로 실행되면서, 사용자의 인터페이스(tty)가 없는 프로그램을 말한다. 우리가 흔히 사용하는 리눅스 서비스들은 대부분 데몬으로 동작하며, -d로 끝나는 프로그램(예: sshd, syslogd)이 모두 해당된다. 리눅스 명령인 nohup으로 백그라운드 구동은 가능하지만, kill 명령으로 종료해야 한다.따라서 비정상 종료시의 처리를 하려면, OS로부터 signal을 받아야 하므로 데몬으로 구동시켜야 한다.( 참고 : http://ir.bagesoft.com/640 )
> 단독데몬
항상 백그라운드 모드로 실행되고 메모리를 상대적으로 많이 소비한다. 그러나 서비스(응답속도)가 빠르다. httpd와 같은 웹서비스 데몬이 대표적.
> xinetd(슈퍼데몬)
요청이 있을때마다 xinetd가 서비스를 싱행시켜주므로 메모리 소비가 적다. 그러나 단독데몬에 비해 상대적으로 서비스 속도가 느리다.
2. 간단한 자바 데몬 만들기
nohup을 이용해서 java를 실행시킨다.
터미널이 종료될 때(쉘이 종료될 때) 프로세스가 죽는 이유는 해당 프로세스가 쉘의 자식 프로세스 이기 때문이다. 따라서, 부모 프로세스가 죽을대 던지는 SIGHUP을 자식 프로세스가 받게 된다.
nohup은 부모 프로세스가 죽을때 자식 프로세스에게 SIGHUP을 던지지 않는 프로세스를 말한다.
$ nohup java 클래스명 &
사용하기 편한 장점은 있으나, 문제는 중지를 시킬수 없다. 즉, 해당 프로세스 ID를 찾아내 kill하는 수 밖에 없다. 물론 파일 체크 기법, 소켓을 이용한 제어 방법등을 사용할 수 있지만 스스로 구현해야 하는 번거로움이 있다.
Java는 UNIX의 시그널 처리를 할수 없기때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야한다. 이런 번거로움을 해결하기 위해 자카르타의 하위 프로젝트중의 commons daemon을 이용한다. commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.
** 다운로드: http://commons.apache.org/daemon/
UNIX용 Jsvc와 윈도우용 Procrun 있다.
여기서는 Jsvc를 이용해보도록 하겠다.
근데 여기서 잠깐!
(참고 : http://heartdev.wordpress.com/2013/06/22/apache-commons-daemon-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC/ )
JSVC를 깔기 위해서는 다음과 같은 4가지 것들이 필요하다.
- GNU AutoConf (at least version 2.53)
- An ANSI-C compliant compiler (GCC is good)
- GNU Make
- A Java Platform 2 compliant SDK
위의 4가지를 깔기 위해서는 어떤 명령어가 필요할까?
먼저 JDK가 설치되어 있지 않다면 JDK를 설치한다.
gcc 및 make가 설치되어 있지 않다면, 아래 명령을 이용해 한방에 설치하자.
$ yum install build-essential ( 원래는 우분투 에서 : $ sudo apt-get install build-essential )
centos의 경우 yum을 사용하므로 이게 맞을꺼다. (지금 기억이 가물;;) 여튼 근데 정작 문제는 이 명령어가 안 먹는다는거! 그래서 gcc랑 make가 설치가 안되는데 음..... 모르겠다. 일단 이거 없이도 성공은 했었었다.
$ yum install autoconfig ( 원래는 우분투에서 $ sudo apt-get install autoconf )
명령어로 역시 centos에서 Autoconf설치를 끝낸다.
mkdir /root/commons-daemon
cd /root/commons-daemon
wget http://archive.apache.org/dist/commons/daemon/binaries/commons-daemon-1.0.5.jar
wget http://archive.apache.org/dist/commons/daemon/source/commons-daemon-1.0.5-src.tar.gz
(위 소스는 경로가 변경되어서 내가 수정하였다.)
support/buildconf.sh --> 사실 이부분이 잘 안되는데 이유를 모르겠고 그냥 일단 넘어갔다. 이 폴더까지 가서 ./buildconf.sh 라고 쳐도 된다. (음... 어떤데는 sh buildconf.sh 라고 씌여있는걸 보기도 했는데 같은 방법인지 확실하지 않다....ㅠ)
make
위와 같이 실행하면, 작업할 경로(/root/commons-daemon)에 jar과 jsvc파일이 생성되어 있을 것이다.
아래부터는 또 가져왔다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 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++; } } } |
위의 클래스를 jar로 묶어서 BageSoft.jar 라는 파일을 만들고 작업경로(/root/commons-daemon/)에 저장했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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 |
진심으로 웹에 정보를 올려주신 분들께 감사하다.
도움이 되셨나요?^^