본문 바로가기
소프트웨어개발

Java Daemon 백그라운드 프로세스 구현

by 보이드메인 2020. 10. 23.

Daemon Process 

Daemon 이란 백그라운드로 실행되면서,  사용자의 인터페이스(tty)가 없는 프로그램을 말한다.

주기적인 서비스 요청을 처리하기 위해서 커널상에 백그라운드 모드로 실행되는 프로세스이다.

우리가 흔히 사용하는 리눅스 서비스들은 대부분 데몬으로 동작하며, -d로 끝나는 프로세스 바이너리(예: sshd, syslogd)들이 모두 해당된다.

 

리눅스 명령인 nohup으로 백그라운드 구동은 가능하지만, kill 명령으로 종료해야 한다.

따라서 비정상 종료시의 처리를 하려면, OS로부터 signal을 받아야 하므로 데몬으로 구동시켜야 한다. 

단독데몬 

항상 백그라운드 모드로 실행되고 메모리를 상대적으로 많이 소비한다. 서비스(응답속도)가 빠르다.

httpd와 같은 웹서비스 데몬이 대표적.

 

xinetd/inetd(슈퍼데몬)

요청이 있을때마다 xinetd가 서비스를 실행시켜주므로 메모리 소모가 적다. 단독데몬에 비해 상대적으로 서비스 속도가 느리다. 


터미널이 종료될 때(쉘이 종료될 때) 프로세스가 죽는 이유는 해당 프로세스가 쉘의 자식 프로세스가 되기 때문이다.

따라서, 부모 프로세스가 죽을때 던지는 SIGHUP을 자식 프로세스가 받게 된다.

nohup은 부모 프로세스가 죽을때 자식 프로세스에게 SIGHUP을 던지지 않게 해야 한다.

 

아래 명령을 보자.

 

$ nohup java 클래스명 &

 

사용하기 편한 장점은 있다. 

그러나 문제는 프로세스를 중지시킬수 없다.

해당 프로세스 ID를 찾아내 kill 해야한다. 

 

파일에 플래그를 설정해서 체킹하는 방법이나, 소켓으로 메시지로 제어 방법등도 고려되지만,

구현해야 하는 번거로움이 있다.

 

apache commons daemon 이용하기

Java는 UNIX의 시그널 처리를 할수 없기때문에, 중지 신호(TERM signal)를 처리하기 위해서는 따로 구현을 해야한다.

이런 번거로움을 해결하기 위해 자카르타의 하위 프로젝트중의 commons daemon을 이용한다.

commons daemon은 중지 신호를 받으면 미리 지정된 메소드를 실행한다.

 

Apache Commons Daemon에서 제공하는 Jsvc를 이용하여, 간단한 데몬 프로그램을 작성해 보자.

 

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

 

tomcat 도 JSVC 를 사용한다.

- UNIX/LINUX 용 Jsvc와

- 윈도우용 Procrun 있다.

 

아래 블로그에 잘 정리되어 있다.

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

 

gcc 및 make가 설치되어 있지 않다면, 아래 명령을 이용해 한방에 설치하자.

$ yum install build-essential   ( 우분투 에서 : $ sudo apt-get install build-essential )

$ yum install autoconfig   ( 우분투에서  $ sudo apt-get install autoconf )

명령어로 역시 centos에서 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

tar zxvf commons-daemon-1.0.5-src.tar.gz

cd commons-daemon-1.0.5-src/src/native/unix/

support/buildconf.sh    

./buildconf.sh 

./configure --with-java=/usr/local/jdk1.7.0_51/  

make

mv  jsvc  /root/commons-daemon

 

위와 같이 실행하면, 작업할 경로(/root/commons-daemon)에 jar과 jsvc파일이 생성되어 있을 것이다.

 

실행할 JAVA 클래스

jsvc에 의해서 실행되는 JAVA 클래스는 Daemon 인터페이스를 구현해야 한다.

또한 스레드로 실행되어야 하므로, Runnable도 구현해야 한다.

만약 스레드로 구동하지 않을 경우, 종료처리가 제대로 되지 않으며, "Service exit with a return value of 143"라는 오류를 표시할 것이다.

 

테스트를 위해, 1초마다 숫자를 하나씩 증가시키면서 찍는 JAVA code 이다.

TestDaemon.java

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로 묶어서 soft.jar 라는 파일을 만들고 작업경로(/root/commons-daemon/)에 저장.

 

실행/종료

/root/commons-daemon/TestDaemon.sh start

/root/commons-daemon/TestDaemon.sh stop

 

제대로 처리 되는지는 daemon.out의 내용을 확인하면 된다.

init(), start(), stop(), destroy()  메소드가 모두 수행되면 정상이다.

'소프트웨어개발' 카테고리의 다른 글

Process 프로세스  (0) 2024.02.06
C 언어 cat 명령구현  (0) 2020.12.16
C 데몬프로세스 만들기  (0) 2020.10.16
opensource VoIP,IP-PBX : asterisk  (0) 2020.06.02
C, File I/O, open(), fopen() 그리고 dup()  (0) 2020.03.30

댓글