21.1 설치 환경
먼저 JBoss 인스턴스를 어떻게 구성할 것인지를 결정하여야 한다. 장애에 대비하기 위하여 같은 서비스를 제공하는 여러 개의 인스턴스를 클러스터로 구성한다. 이때 인스턴스들은 서로 다른 머신에 배치하여 하드웨어 장애에도 대비할 수 있도록 구성하는 것이 좋다.
Java의 힙 메모리를 많이 사용하면 JVM이 멈추는 Full GC 시간이 길어지기 때문에 1G2G정도의 힙 메모리를 사용하여야 한다. 12G 정도의 메모리만 사용하면 하드웨어의 메모리가 남기 때문에 한 머신에 여러 인스턴스를 구성하여야 한다.
이번 장에서는 다음 그림과 같이 3대의 머신에 1대는 JBoss EWS 웹 서버를 설치하고, 2대에는 JBoss EAP 6를 2개 스탠드얼론 모드의 인스턴스를 설치하여 클러스터를 구성하는 예제를 살펴보자.
예를 들어 각각의 머신은 다음과 같은 IP를 사용한다고 가정하자.
| 용도 | HOSTNAME | IP |
|---|---|---|
| 웹 서버 | WEB01 | 192.168.0.201 |
| WAS 서버 | WAS01 | 192.168.0.101 |
| WAS 서버 | WAS02 | 192.168.0.102 |
표 1. 머신 구성의 예
아래 그림과 같이 웹 서버와 JBoss EAP 6 서버 인스턴스를 구성한다고 가정하자.

디렉터리 구조
주요 설치 디렉터리
제품이 설치되는 디렉터리와 서비스에 사용할 인스턴스 들이 있는 디렉터리를 분리하는 것이 좋다. 또, 로그 파일이 별도의 디렉터리에 저장되도록 설정하여 디스크가 꽉 차더라도 서비스에는 영향을 미치지 않도록 설정한다. 물론 로그를 남길 디렉터리는 OS에서 다른 파티션을 사용하도록 설정하여야 한다. 또 별도의 외부 애플리케이션 배포 디렉터리를 설정하면 한 머신에 한 번만 애플리케이션을 배포하면 된다.
| 구분 | 디렉터리명 | 설명 |
|---|---|---|
| JBoss EAP 6 제품설치 디렉터리 | /svc/test/was/jboss-eap-6.2 | JBoss EAP 6를 설치할 디렉터리이다. |
| JBoss인스턴스 디렉터리 | /svc/test/was/domains | 서비스에 사용할 JBoss 인스턴스들을 구성할 디렉터리이다. |
| 로그 디렉터리 | /logs/was/ | 인스턴스의 로그 파일들을 저장할 디렉터리이다. |
| 애플리케이션 디렉터리 | /svc/test/was/domains/applications | 애플리케이션 배포 디렉터리이다. |
| JBoss EWS 2 제품설치 디렉터리 | /svc/test/web/jboss-ews-2.0 | JBoss EWS 2를 설치할 디렉터리이다. |
표 2. 설치 디렉터리
인스턴스 디렉터리 구성
JBoss EAP 6를 설치한 디렉터리의 파일들은 수정하지 않고, 별도의 인스턴스 디렉터리를 설정하여 서비스한다.
/svc/test/was/domains 이라는 디렉터리 하위에 인스턴스 들을 구성한다. domains 하위에 서버 인스턴스 이름으로 디렉터리를 만든다. 인스턴스의 이름은 다음 그림과 같이 서버의 이름 + 머신번호 + 인스턴스 번호와 같은 규칙을 사용하는 것이 좋다.
실제 서버의 이름은 서비스를 나타내는 고유명칭으로 변경하여 사용하면 된다. 머신 번호는 JBoss에 사용할 머신에 1번부터 차례대로 붙인 번호를 사용하고, 인스 턴스 번호는 같은 머신 내의 인스턴스 개수를 1번부터 번호를 붙인다.
이렇게 인스턴스 이름을 지정하면 모든 인스턴스가 고유한 이름을 갖게 된다. 이 고유한 인스턴스 이름은 클러스터링에서 세션ID, 로그 파일의 이름, nohup 로그 파일의 이름 등에 사용하게 된다. 장애 상황이나 로그 파일를 확인하는 등 어떤 상황에서도 서버 이름만 보면 어떤 머신의 어떤 인스턴스의 것인지 금방 구분할 수 있게 된다.

또, 포트 오프셋 번호는 ‘인스턴스의 번호 * 100’을 사용하면, 포트를 구분하기 쉽다. 기본 포트셋 + 포트오프셋으로 사용하는 포트가 지정되는데, 사용하는 대부분의 포트 번호가 100번대가 0이기 때문에 해당 인스턴스가 사용하는 번호를 기억하기 쉽다.
예를 들어 인스턴스 이름이 ‘frontSvr24’이라면, 2번째 JBoss 머신의 4번째 인스턴스를 의미하며, 이 인스턴스가 사용하는 HTTP 포트는 8480(8080 + 400) 포트를 사용하고, AJP 포트는 8409(8009 + 400) 포트를 사용한다.
예제에서는 다음과 같이 WAS 머신 2대에 각각 2개의 인스턴스를 구성한다.
| 머신명 | 디렉터리명 | 포트 오프셋 | HTTP포트 | AJP포트 |
|---|---|---|---|---|
| WAS01 (192.168.0.101) | /svc/test/was/domains/server11 | 100 | 8180 | 8109 |
| /svc/test/was/domains/server12 | 200 | 8280 | 8209 | WAS02 (192.168.0.102) |
| /svc/test/was/domains/server21 | 100 | 8180 | 8109 | /svc/test/was/domains/server22 |
표 3. 머신 별 인스턴스 구성
JBoss EAP 6운영 스크립트
JBoss EAP 6가 설치된 디렉터리가 아닌 다른 디렉터리에서 JBoss 인스턴스를 실행하려면 몇 가지 옵션을 지정해야 한다. 가장 중요한 옵션은 ‘-Djboss.server.base.dir’로 서버 인스턴스의 디렉터리를 지정하는 데 사용된다. 이 외에도 여러 가지 옵션들을 변경하여 위치를 변경하여야 한다.
JBoss 운영 환경을 구축하기 위해서는 많은 작업이 필요하다. JBoss를 시작할 때도 백그라운드 프로세스로 실행하여야 하며, nohup 로그를 남겨두어야 스레드 덤프를 받을 때 파일에 남게 된다. 백그라운드로 실행 중인 JBoss를 종료하는 방법도 필요하다.
운영환경에 사용할 수 있도록 JBoss EAP 6 스크립트를 github 에 올려두었다. 이 파일을 다운로드받아 사용하면 된다. 스탠드얼론 모드용 스크립트와 도메인 모드용 스크립트를 모두 제공하고 있다.
- JBoss EAP 6 스크립트 다운로드
https://github.com/nameislocus/jboss-eap-6-scripts
$ git clone https://github.com/nameislocus/jboss-eap-6-scripts
git가 설치되어 있지 않으면, 다음 명령으로 git를 설치한다.
$ sudo yum install git
github에 있는 주요 스크립트 파일은 아래 표와 같다. 인스턴스를 시작, 종료, kill, 로그 tail, 프로세스 확인, 스레드 덤프 등 JBoss 인스턴스를 운영하는 데 필요한 대부분의 스크립트를 제공하고 있다.
이 스크립트파일들은 모두 환경설정 파일인 env.sh 파일을 참조하여 실행된다. 따라서, 위에서 설명한 JBoss 설치 디렉터리, 인스턴스 구성 디렉터리, 로그 디렉터리 등의 설정은 모두 env.sh 파일의 내용만 수정하면 된다.
| 스크립트 파일 | 설명 |
|---|---|
| env.sh | JBoss 운영환경 주요 환경 설정 스크립트 |
| start.sh | JBoss Standalone 인스턴스 실행 스크립트 |
| shutdown.sh | JBoss Standalone 인스턴 스 정상 종료 스크립트 |
| kill.sh | JBoss 강제 종료 스크립트 |
| nohup.sh | nohup 로그의 tail 보기 스크립트 |
| tail.sh | JBoss server.log 파일 tail 보기 스크립트 |
| status.sh | JBoss 인스턴스가 실행중인지 체크하는 스크립트 |
| jboss-cli.sh | JBoss CLI 모드로 접속하는 스크립트 |
| jconsole.sh | JConsole로 접속하여 JMX MBean 정보를 확인하기 위한 스크립트(GUI 환경 필요) |
| add-user.sh | 사용자를 추가하기 위한 스크립트 |
| dump.sh | 인스턴스 장애시 Java 프로세스의 스레드 덤프를 받기 위한 스크립트 |
| env.properties | 자바 시스템 프로퍼티를 설정하는 파일이다. 인코딩 설정이 정의되어 있다. |
표 4. JBoss EAP 6 운영 스크립트
-
env.sh 파일
env.sh는 JBoss EAP 6환경설정을 위한 파일이다. 각 인스턴스의 모든 설정은 이 파일에서 하면 된다. 4개의 JBoss 인스턴스마다 각각의 인스턴스의 이름, 디렉터리의 이름, 포트 오프셋 등을 설정하면 된다. 또 이 파일에는 JVM의 메모리 옵션, GC 옵션, OufOfMemory 오류가 발생할 때 Heapdump를 출력하는 옵션 등이 설정되어 있다.
스탠드얼론 인스턴스가 사용할 프로파일을 변경하려면, CONFIG_FILE=standalone-full-ha.xml 과같이 프로파일 파일명을 지정하면 된다.
#!/bin/shDATE=`date +%Y%m%d%H%M%S`##### JBOSS Directory Setup #####export JBOSS_HOME=/svc/test/was/jboss-eap-6.2export DOMAIN_BASE=/svc/test/was/domainsexport SERVER_NAME=server11export JBOSS_LOG_DIR=/logs/was/server11if [ e$JBOSS_LOG_DIR = "e" ]thenexport JBOSS_LOG_DIR="$JBOSS_HOME/log"fiif [ e$JBOSS_LOG_DIR != "e" ]thenexport JBOSS_LOG_DIR="$JBOSS_LOG_DIR"fi##### Configration File #####export CONFIG_FILE=standalone-ha.xmlexport EXTERNAL_DEPLOYMENT=/svc/test/was/domains/applicationsexport HOST_NAME=masterexport NODE_NAME=$SERVER_NAMEexport PORT_OFFSET=100export JBOSS_USER=jboss##### Bind Address #####export BIND_ADDR=192.168.0.101export MULTICAST_ADDR=230.1.1.1export JMS_MULTICAST_ADDR=231.7.1.1export MODCLUSTER_MULTICAST_ADDR=224.1.1.105export MGMT_ADDR=192.168.0.101export CONTROLLER_IP=$MGMT_ADDRlet CONTROLLER_PORT=9999+$PORT_OFFSETexport CONTROLLER_PORTexport LAUNCH_JBOSS_IN_BACKGROUND=true##### JBoss System module and User module directory #####export JBOSS_MODULEPATH=$JBOSS_HOME/modules# JVM Options : Serverexport JAVA_OPTS="-server $AGENT_OPTS $JAVA_OPTS"# JVM Options : Memory – 자바 힙 메모리 옵션을 설정한다.export JAVA_OPTS=" $JAVA_OPTS *-Xms1024m -Xmx1024m -XX:MaxPermSize=256m*"export JAVA_OPTS=" $JAVA_OPTS -XX:+PrintGCTimeStamps "export JAVA_OPTS=" $JAVA_OPTS -XX:+PrintGCDetails "export JAVA_OPTS=" $JAVA_OPTS -Xloggc:$JBOSS_LOG_DIR/gclog/gc_$DATE.log "export JAVA_OPTS=" $JAVA_OPTS -XX:+UseParallelGC "#export JAVA_OPTS=" $JAVA_OPTS -XX:+UseConcMarkSweepGC "export JAVA_OPTS=" $JAVA_OPTS -XX:+ExplicitGCInvokesConcurrent "export JAVA_OPTS=" $JAVA_OPTS -XX:-HeapDumpOnOutOfMemoryError "export JAVA_OPTS=" $JAVA_OPTS -XX:HeapDumpPath=$JBOSS_LOG_DIR/heapdump "# Linux Large Page Setting#export JAVA_OPTS=" $JAVA_OPTS -XX:+UseLargePages "#export JAVA_OPTS=" $JAVA_OPTS -verbose:gc"export JAVA_OPTS=" $JAVA_OPTS -Djava.net.preferIPv4Stack=true"export JAVA_OPTS=" $JAVA_OPTS -Dorg.jboss.resolver.warning=true"export JAVA_OPTS=" $JAVA_OPTS -Dsun.rmi.dgc.client.gcInterval=3600000 "export JAVA_OPTS=" $JAVA_OPTS -Dsun.rmi.dgc.server.gcInterval=3600000"export JAVA_OPTS=" $JAVA_OPTS -Djboss.modules.system.pkgs=org.jboss.byteman,com.khan"export JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true"export JAVA_OPTS=" $JAVA_OPTS -Djboss.server.base.dir=$DOMAIN_BASE/$SERVER_NAME"export JAVA_OPTS=" $JAVA_OPTS -Djboss.server.log.dir=$JBOSS_LOG_DIR"export JAVA_OPTS=" $JAVA_OPTS -Djboss.external.deployments=$EXTERNAL_DEPLOYMENT"export JAVA_OPTS=" $JAVA_OPTS -Djboss.socket.binding.port-offset=$PORT_OFFSET"export JAVA_OPTS=" $JAVA_OPTS -Djboss.node.name=$NODE_NAME"export JAVA_OPTS=" $JAVA_OPTS -Djboss.bind.address.management=$MGMT_ADDR"export JAVA_OPTS=" $JAVA_OPTS -Djboss.bind.address=$BIND_ADDR"#export JAVA_OPTS=" $JAVA_OPTS -Djboss.default.jgroups.stack=tcp"export JAVA_OPTS=" $JAVA_OPTS -Djboss.default.multicast.address=$MULTICAST_ADDR"export JAVA_OPTS=" $JAVA_OPTS -Djboss.messaging.group.address=$JMS_MULTICAST_ADDR"export JAVA_OPTS=" $JAVA_OPTS -Djboss.modcluster.multicast.address=$MODCLUSTER_MULTICAST_ADDR"export JAVA_OPTS=" $JAVA_OPTS -Dorg.jboss.as.logging.per-deployment=false "echo "================================================"echo "JBOSS_HOME=$JBOSS_HOME"echo "DOMAIN_BASE=$DOMAIN_BASE"echo "SERVER_NAME=$SERVER_NAME"echo "CONFIG_FILE=$CONFIG_FILE"echo "BIND_ADDR=$BIND_ADDR"echo "PORT_OFFSET=$PORT_OFFSET"echo "MULTICAST_ADDR=$MULTICAST_ADDR"echo "CONTROLLER=$CONTROLLER_IP:$CONTROLLER_PORT"echo "================================================" -
start.sh 파일
JBoss 인스턴스를 시작하는 스크립트이다. 이 파일에서는 JBoss 인스턴스가 이미 실행되어 있는지 조사하여 다시 실행되지 않도록 하며, env.sh 파일에서 JBOSS_USER로 JBoss 프로세스를 관리하는 사용자로 지정한 사용자만 JBoss 인스턴스를 시작할 수 있도록 한다.
GC 로그를 남길 디렉터리나 로그 디렉터리, Heap dump를 남길 디렉터리가 없으면 생성한다.
JBoss 인스턴스는 nohup 로그를 남기며 백그라운드로 실행된다. 기존의 nohup로그는 현재 실행 시각을 확장자로 하여 백업하고 새로운 nohup 로그를 남긴다.
#!/bin/shDATE=`date +%Y%m%d%H%M%S`. ./env.shPID=`ps -ef | grep java | grep "=$SERVER_NAME " | awk '\{print $2}'`echo $PIDif [ e$PID != "e" ]thenecho "JBoss SERVER - $SERVER_NAME is already RUNNING..."exit;fiUNAME=`id -u -n`if [ e$UNAME != "e$JBOSS_USER" ]thenecho "Use $JBOSS_USER account to start JBoss SERVER - $SERVER_NAME..."exit;fiecho $JAVA_OPTSif [ ! -d "$JBOSS_LOG_DIR/nohup" ];thenmkdir -p $JBOSS_LOG_DIR/nohupfiif [ ! -d "$JBOSS_LOG_DIR/gclog" ];thenmkdir -p $JBOSS_LOG_DIR/gclogfiif [ ! -d "$JBOSS_LOG_DIR/heapdump" ];thenmkdir -p $JBOSS_LOG_DIR/heapdumpfimv $JBOSS_LOG_DIR/nohup/$SERVER_NAME.out $JBOSS_LOG_DIR/nohup/$SERVER_NAME.out.$DATEnohup $JBOSS_HOME/bin/standalone.sh -DSERVER=$SERVER_NAME -P=$DOMAIN_BASE/$SERVER_NAME/env.properties -c $CONFIG_FILE >> $JBOSS_LOG_DIR/nohup/$SERVER_NAME.out 2>&1 &if [ e$1 = "enotail" ]thenecho "Starting... $SERVER_NAME"exit;fi#tail -f log/server.logtail -f $JBOSS_LOG_DIR/nohup/$SERVER_NAME.out -
shutdown.sh
shutdown CLI 명령을 사용하여 JBoss 인스턴스를 종료하는 스크립트이다. shutdown명령을 사용하여 종료하기 때문에 작업 중이던 처리를 모두 완료한 후 종료한다.
#!/bin/sh. ./env.sh$JBOSS_HOME/bin/jboss-cli.sh --connect --controller=$CONTROLLER_IP:$CONTROLLER_PORT --command=:shutdown -
status.sh
JBoss 인스턴스가 실행 중인지 프로세스를 체크하는 스크립트이다.
#!/bin/sh. ./env.shps -ef | grep java | grep "SERVER=$SERVER_NAME " -
kill.sh
kill -9 <pid>로 JBoss 인스턴스를 강제 종료하는 스크립트이다. 서버를 실행하는 start.sh 스크립트에서$SERVER_NAME환경변수를 지정하였기 때문에 해당 자바 프로세스만 kill 한다. grep시 맨 뒤에 있는 공백이 꼭 필요하니 주의하여야 한다. 예를 들어$SERVER_NAME이 front1인 프로세스와 front12인 프로세스가 실행 중이면, 공백이 없으면 두 프로세스 모두 kill 된다.#!/bin/sh. ./env.shps -ef | grep java | grep "SERVER=$SERVER_NAME " | awk \{'print "kill -9 " $2'} | sh -x -
nohup.sh
JBoss 인스턴스의 nohup로그를 tail로 보는 스크립트이다.
#!/bin/sh. ./env.shtail -f $JBOSS_LOG_DIR/nohup/$SERVER_NAME.out -
jboss-cli.sh
해당JBoss 인스턴스에 CLI로 접속하는 스크립트이다. 스크립트를 실행하면 env.sh 파일에 정의된 컨트롤러로 자동으로 접속한다.
#!/bin/sh. ./env.shexport JAVA_OPTS=" -Djava.awt.headless=false $JAVA_OPTS"$JBOSS_HOME/bin/jboss-cli.sh --controller=$CONTROLLER_IP:$CONTROLLER_PORT --connect $@ -
jconsole.sh
JConsole을 실행하는 스크립트이다. 이 스크립트를 실행하면 해당 JBoss 인스턴스에 접속하는 remoting-jmx URI를 화면에 출력하고 JConsole을 실행한다. 원격에서 접속하려면 화면에 출력되는 JMX URL을 사용하면 된다. JMX의 사용법에 대해서는 ‘19장. JBoss EAP 6 모니터링’에서 자세히 설명하고 있다.
#!/bin/sh. ./env.shecho "======================================================="echo " JMX URL : service:jmx:remoting-jmx://$MGMT_ADDR:$CONTROLLER_PORT"echo "======================================================="$JBOSS_HOME/bin/jconsole.sh -
dump.sh
이 스크립트를 실행하면 자동으로 3초 간격으로 5회 스레드 덤프를 nohup에 출력한다.
#!/bin/sh. ./env.shfor count in 1 2 3 4 5; doecho "Thread Dump : $count"for i in `ps -ef | grep java | grep "SERVER=$SERVER_NAME " | awk '\{print $2}'`;doecho "+kill -3 $i"kill -3 $iecho "sleep 1 sec"sleep 1doneecho "done"sleep 3done