2019년 7월 7일 일요일

jmap 을 사용하여 java process 상태 모니터링

모든 WAS의 경우 jvm에 의해 기동이 된다. (java로 기동되기 때문)
기동 된 이후에는 Xms 값만큼 사용하였다가 메모리가 더 필요할 경우 Xmx 값까지 사용한다. Xms, Xmx값은 동일 값으로 설정 해 주는 것이 좋다. 왜냐면 minimum 에서 maximum 까지 도달하는데까지 오버헤드가 발생한다. (실제 이슈가 있었던 경험도 있음)


그럼 jvm에 의해 기동 된 프로세스를 모니터링하고 싶은 경우, 여러 방법이 있지만, 단순 메모리 사이즈 또는 힙에 대한 내용을 확인 하고 싶을 경우 jmap이 가장 직관적이였다. (주관적인 기준)


명령어는 단순한다.
ps -ef| grep java 로 pid 및 프로세스 상태를 확인 한 후


jmap -heap [PID] 로 확인이 가능한다.


하지만, 아래와 같은 메시지가 발생한다.






더 자세한 내용을 확인하고 싶다.


이럴경우 OpenJDK에 debuginfo 를 설치 해주어야 한다.
http://debuginfo.centos.org/7/x86_64/


시스템 환경에 맞는 버전을 다운로드 후 설치 해준다.



다시 동일하게 실행 했을 경우, 명령어가 잘 실행 된다.



2019년 7월 4일 목요일

Tomcat start.sh 스크립트

 Tomcat instance 구성한 후 번들로 제공되는 Tomcat home에 있는 startup.sh 맘에 들지 않을 뿐더러 기능이 적다.

기존에 갖고 있던 스크립트에서 update 했다


#!/bin/bash

export CATALINA_BASE=$(dirname $(dirname $(realpath $0)))  # 절대경로를 설정(상대 경로의 경우 스크립트 실행 시 cd 를 넣어 주어야 함)

. $CATALINA_BASE/bin/env.sh >> /dev/null # 환경변수 적용

DATE=`date +%Y%m%d%H%M%S`

# Process Check ---------------------------------------
PID=`ps -ef | grep java | grep "=$SERVER_NAME" | awk '{print $2}'`

if [ e$PID != "e" ]; then
  echo "# [ERROR] Tomcat ($SERVER_NAME) is already RUNNING..."
  exit;
fi
# WAS User Check----------------------------------------
UNAME=`id -u -n`
if [ e$UNAME != "e$TOMCAT_USER" ]; then
  echo "# [ERROR] $TOMCAT_USER USER to start this SERVER! - $SERVER_NAME..."
  exit;
fi

# Make LOG Directory------------------------------------
# 로그홈 설정이 없으면 또는 권한이 없는 경우 바로 exit!!
if [ -z $LOGHOME ]; then
  echo "# [ERROR] $LOGHOME/$SERVER_NAME No Such Directory or Permission denied!!! Please check $CATALINA_BASE/bin/env.sh file "
  echo ""
  exit ;
else
  [ ! -d "${LOG_DIR}" ]      &&  mkdir -p "${LOG_DIR}";     
  [ ! -d "${ACCESS_DIR}" ]   &&  mkdir -p "${ACCESS_DIR}"; 
  [ ! -d "${GC_LOG_DIR}" ]   &&  mkdir -p "${GC_LOG_DIR}";
  [ ! -d "${HEAP_LOG_DIR}" ] &&  mkdir -p "${HEAP_LOG_DIR}";
fi

# -------------------------------------------------------
# rotate 기능이 필요 없을 때 
# -------------------------------------------------------
rm -rf $CATALINA_BASE/work/*;
mv ${LOG_DIR}/$SERVER_NAME.log ${LOG_DIR}/$SERVER_NAME.$DATE;

nohup $CATALINA_HOME/bin/catalina.sh run >> ${LOG_DIR}/$SERVER_NAME.log 2>&1 &
# -------------------------------------------------------

# rotate 기능이 필요한 경우 (하지만 logrotate 기능이 더 안전함) 경험상 rotatelogs는 비정적으로 프로세스가 죽는다. 아무런 흔적없이.......
# -------------------------------------------------------
mv $LOG_DIR/$SERVER_NAME.log.`date '+%Y-%m-%d'` $LOG_DIR/$SERVER_NAME.log.$DATE;

nohup $CATALINA_HOME/bin/catalina.sh run 2>&1 |/usr/sbin/rotatelogs -l $LOG_DIR/$SERVER_NAME.log.%Y-%m-%d 86400 &


# ------------------------------------------------------
# Do not want to log stdout, stderr (ex ./start.sh nolog)
# tail을 통해서 로그가 올라오는 것을 보고 싶을 수도 있지만 그렇지 않은 경우엔 인자값을 nolog 또는 notail을 입력하면 tail 없이 기동
# ------------------------------------------------------
if [ "$1" == "nolog" ] || [ "$1" == "notail" ] ; then
  echo "Starting... $SERVER_NAME"
  exit;
fi

# -----------------------------------------------------
$CATALINA_BASE/bin/tail.sh

2019년 7월 3일 수요일

Tomcat multi instance 구성 준비 (shell script) update version

이전 포스트에서 작성한게 있는데 아무리 봐도 아쉬운 부분이 많았다.
그래서 맘잡고 업데이트를 하였다. 
소스는 최대한 적게 작성하려고 했지만, 이정도가 적당한지 모르겠다.

#!/bin/bash

VERSION=8.5              # (필수)버전을 선택
DIR=$(pwd)               
INSTANCE_NAME=       # 인스턴스 생성시 확인 해야할 이름이 필요
LOGHOME=/logs/tomcat

if [ -z $INSTANCE_NAME ]; then  # 인스턴스명을 프롬프트로 받을 수 있음
  echo -n "Input unique INSTANCE_NAME(or SERVER_NAME) (ex tomcat-svr-11, tomcat-11): ";
  read word;
  if [ -z $word ]; then
    echo "# [ERROR]  have to Input INSTANCE_NAME(or SERVER_NAME)!!! "
    exit ;
  fi
    INSTANCE_NAME="$word";
    SVR_NAME=$INSTANCE_NAME;
    SVR_PATH=$DIR/$SVR_NAME;
    echo "INSTANCE_NAME = $SVR_NAME";
    echo "INSTANCE_PATH = $SVR_PATH";
    `mkdir -p $SVR_PATH`;    # 인스턴스명을 지정했다면 이제 directory 생성
  else
    SVR_PATH=$DIR/$INSTANCE_NAME;
    `mkdir -p $SVR_PATH`;
fi

if [ ! -z $LOGHOME ]; then   # 심볼릭 링크를 걸고 싶다면 위쪽 LOGHOME을 지정
  `ln -s $LOGHOME $DIR/$INSTANCE_NAME/logs`
fi

# -----------------------------------------------------------------
# Make Directory # 로그 경로들을 생성
# -----------------------------------------------------------------
[ ! -d "$INSTANCE_NAME/bin" ]     &&  mkdir -p $INSTANCE_NAME/bin;
[ ! -d "$INSTANCE_NAME/conf" ]    &&  mkdir -p $INSTANCE_NAME/conf;
[ ! -d "$INSTANCE_NAME/lib" ]     &&  mkdir -p $INSTANCE_NAME/lib;
[ ! -d "$INSTANCE_NAME/temp" ]    &&  mkdir -p $INSTANCE_NAME/temp;
[ ! -d "$INSTANCE_NAME/webapps" ] &&  mkdir -p $INSTANCE_NAME/webapps;
[ ! -d "$INSTANCE_NAME/work" ]    &&  mkdir -p $INSTANCE_NAME/work;

# -----------------------------------------------------------------
# XML Copy # tomcat 엔진이 설치 되어 있는지 확인 없으면 설치 해야함
# -----------------------------------------------------------------

value=`find ../ -type f -name "catalina.sh" 2>/dev/null | wc -l`
#echo $value

if [ -z ${value} ]; then
  echo "# [ERROR] Can not Found Tomcat Engine"
  else
  if [ ! -d $CATALINA_HOME ]; then
    echo "# [ERROR] Can not find CATALINA_HOME"
  else
    CATALINA_HOME=$(find ../ -type d -name "*$VERSION*" 2>/dev/null -exec readlink -f {} \;)
    cp -r $CATALINA_HOME/conf/* $SVR_PATH/conf/;
  fi
fi

# -----------------------------------------------------------------
# PORT, jvmRoute Translation # 경로하고 설정파일만 복사한다고 끝이 아니다 바로 기동하면 포트가 쫑(충돌)난다. 아마 address already use 라고 나올 것 같다. 
java system properties로 설정하기 위해 문자 치환
혹시 세션 클러스터 사용시 필요할 jvmRoute도 설정
# -----------------------------------------------------------------
DIFF=$(diff $CATALINA_HOME/conf/server.xml $SVR_PATH/conf/server.xml)
if [ "$DIFF" ]; then

  echo "# [WARNING] $CATALINA_HOME/conf/server.xml and $SVR_PATH/conf/server.xml are different "
else
  sed -i 's/8005/\$\{shutdown.port\}/' $SVR_PATH/conf/server.xml;
  sed -i 's/8080/\$\{http.port\}/' $SVR_PATH/conf/server.xml;
  sed -i 's/8009/\$\{ajp.port\}/' $SVR_PATH/conf/server.xml;
  sed -i 's/8443/\$\{ssl.port\}/' $SVR_PATH/conf/server.xml;
  sed -i 's/8443/\$\{ssl.port\}/' $SVR_PATH/conf/server.xml;
  sed -i 's/"localhost">/"localhost" jvmRoute="${server}">/' $SVR_PATH/conf/server.xml;
fi

2019년 7월 1일 월요일

centos tomcat multi instance 구성 준비 (shell script)


리눅스(centos 기준)서버 한대에 tomcat 인스턴스를 여러개 구성이 필요할 경우
이를 tomcat multi instances(?)라고 하는 것 같다.

tomcat을 multi instances 구성을 하려면 디렉토리도 생성해줘야 하고 scripts, xml 파일 등등 복사해와야 한다.

수작업이 시간이 오래 걸리고 error도 많기 때문에 스크립트로 만들어봤다.

#!/bin/bash

# -----------------------------------------------------------------
# Make Directory (필수 디렉토리 생성)
# -----------------------------------------------------------------
if [ ! -d ./bin ]
    then
    echo "create bin directory."
    mkdir -p ./bin;
fi

if [ ! -d ./conf ]
    then
    echo "create conf directory."
    mkdir -p ./conf;
fi

if [ ! -d ./lib ]
    then
    echo "create lib directory."
    mkdir -p ./lib;
fi


if [ ! -d ./temp ]
    then
    echo "create temp directory."
    mkdir -p ./temp;
fi

if [ ! -d ./webapps ]
    then
    echo "create webapps directory."
    mkdir -p ./webapps;
fi

if [ ! -d ./work ]
    then
    echo "create work directory."
    mkdir -p ./work;
fi

# -----------------------------------------------------------------
# XML Copy (CATALINA_HOME 톰캣엔진에서 xml을 copy)
# -----------------------------------------------------------------
# catalina.sh 파일은 tomcat을 실행하기 위한 필요한 스크립트이기 때문에 이 script 기준으로 설정
value=`find ../../ -type f -name "catalina.sh" 2>/dev/null | wc -l`
#echo $value

if [ ${value} -ne 1 ];
    then
        echo "Can not Found Tomcat Engine"
    else

    if [ ! -d $CATALINA_HOME ]
        then
            echo "Can not find CATALINA_HOME"
        else
        CATALINA_HOME=$(find ../../ -type d -name "*8.5*" 2>/dev/null -exec readlink -f {} \;)
            cp -r $CATALINA_HOME/conf/* ./conf;

        fi

fi

# 기존 port 또는 기본 port 와의 충돌을 피하기 위해서 system properties로 넘길 것 (JAVA_OPTS -D option)
# -----------------------------------------------------------------
# PORT Translation
# -----------------------------------------------------------------
find . -type f -name "server.xml" -exec sed -i "s/8005/\$\{shutdown.port\}/" {} \;
find . -type f -name "server.xml" -exec sed -i "s/8080/\$\{http.port\}/" {} \;
find . -type f -name "server.xml" -exec sed -i "s/8009/\$\{ajp.port\}/" {} \;
find . -type f -name "server.xml" -exec sed -i "s/8443/\$\{ssl.port\}/" {} \;

# -----------------------------------------------------------------
# jvmRoute
# -----------------------------------------------------------------
find . -type f -name "server.xml" -exec sed -i "s/defaultHost=\"localhost\"/defaultHost=\"localhost\" jvmRoute=\"\$\{server\}\"/" {} \;

2019년 6월 28일 금요일

apache tomcat deployments 방식

apache tomcat deployments 방식은 archive or unarchive(exploded) 형태이다.

eclipse에서 Export 선택할수 있다. (이 내용은 skipped)

deployments 방식에 잠시 가물가물해서 확인해봤더니 내용이 너무 방대하고 구체적인 설명이 없는 것 같이 테스트를 해보았다.

1. webapps 에 파일을 복사 ( archive or unarchive 상관없이) tomcat server.xml default 설정

기본적으로 tomcat을 설치한 후 webapps에 application을 복사하면 기동 될때 배포가 된다.

INFO: Deploying web application archive [/was/servers/tomcat8/webapps/test2.war]
INFO: Deployment of web application archive [/was/servers/tomcat8/webapps/test2.war] has finished in [823] ms

여기서 호기심,
webapps는 어떻게 인식을 하는 것일까?
apache.tomcat 엔진 홈 경로에 bin/catalina.sh 파일을 보면
CATALINA_BASE라는 환경변수가 있고 이 CATALINA_BASE 하위에 webapps경로를 바라보고 있다 

      <Host name="localhost"  appBase="webapps"  <<- CATALINA_BASE/webapps 라는 뜻(full path)
            unpackWARs="true" autoDeploy="true">
      </Host>

이렇게 deploy를 하게 되면 application 명을 따라 간다.
CATALINA_BASE/webapps 경로를 확인해보면 archive 파일이 unarchive 파일이 되어있다.
내가 만든 application 명은 test2.war이고, context는 test2가 된다. 
예를 들어 호출해보면 위와 같이 deploy 했을 경우 http://localhost:8080/test2/index.jsp 


2. 다른 경로에 파일을 deploy하고 싶고 archive 파일인 경우
 Context를 추가해주면 된다. 간단하다.

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="false">
      <Context path="" docBase="/app/test2.war" /> ( "/"  </Context> 와 동일)
      </Host>
위와 같은 경우에는 webapps(정확히는 CATALINA_BASE/webapps) 파일을 복사하지 않고
CATALINA_BASE/webapps 이외 별도 file or exploded 형태 application을 사용 하겠다는 의미이다.

/app/test2.war 파일을 확인해 보니 archive 는 있는데 unarchive는 없다.
unarchive가 없는 게 아니라 <host>에 appBase="webapps"가 기본적으로 설정되어 있기 때문에 ROOT 라는 directory 가 있을 것이고 unpackWARs="true" 이기 때문에 unarchive 파일이 만들어 졌다.

이 driectory가 ROOT 인 것은 path=""
즉, context가 필요 없는 경우 이렇게 설정 한다.
호출 예) http://localhost:8080/index.jsp 

3. deploy는 하는데 archive 파일만 사용하고 싶은 경우

      <Host name="localhost"  appBase="webapps"
            unpackWARs="false" autoDeploy="false">
      <Context path="" docBase="/app/test2.war" />
      </Host>

 unpackWARs="false" 하면 된다.
 unarchive 파일(ROOT)은 어디에도 없다. 하지만 deploy는 잘된다. 

tomcat에 Context 설정은 문서를 참고하면 많은 옵션을 확인 할 수 있다.

http://tomcat.apache.org/tomcat-8.5-doc/config/context.html






2019년 6월 25일 화요일

shell script 자동 배포 (auto deploy)

목적
1. 첫 번째(이하 배포서버) 서버에 배포를 한 후 순차적으로 늘어나는 서버에들에 대해서는 자동 배포
2. 자동 배포하였을 시에 ip 기반으로 순차적으로 늘어 난다는 가정
3. 배포 완료 후 재기동 까지 해야 정상 처리

아래에 스크립트를 보면 복잡해 보이지만 그렇지 않다. (단순 tomcat deploy)
단순히 배포 서버에 디플로이가 정상이 되면 그 이후부터는 ping테스트하여 복제되는 서버에 대해서는 자동으로 배포 후 끝나는 것이 목표 였다.

주석을 쉬운 영어로 표기 했으니 이정도면 이해가 어렵진 않을 것 같다. 


#/bin/bash

DATE=`date +%Y%m%d%H%M%S`
sub1=192; sub2=168; sub3=15; sub4=100
USER=wasuser
PASSWD=wasuser
WARNAME="test.war"

APPDIR="/opt/was/app"
SERVER_BASE="/opt/was/servers/tomcat8_21"
SSHOPTION="-oStrictHostKeyChecking=no"

SOURCE=$sub1.$sub2.$sub3.$sub4;
TARGET=$SOURCE
echo "#############################################################";
echo "# INFO result [0] = SUCCESS or result [NOT 0] = FAIL ";
echo "# 0-0 $SOURCE SERVER APPLICATION GET THIS SERVER";
sshpass -p $PASSWD scp $USER@$SOURCE:/tmp/$WARNAME /tmp/$WARNAME ;
echo "# 0-0 Result: $?";
echo ""
echo "#############################################################";
echo "# CHECK WITH PING TO TARGET SERVER ";
echo "#############################################################";

while true
do
  cnt=1;
  sub4=`expr $sub4 + 100`;
  TARGET=$sub1.$sub2.$sub3.$sub4;
    ping -c 1 -w 1  $TARGET >/dev/null 2>&1;
    if [ $? -ne 0 ]; then
    echo "#############################################################";
    echo "# NO LONGER TARGET: $TARGET ";
    echo "#############################################################";
        sleep 1;
      break;
    else
    echo "# TARGET [$cnt]: $TARGET ";
    echo "";
   
    echo "# TASKS Start ";
   
    echo "# 1-1 TARGET $TARGET [$cnt] APPLICATION BACKUP[move] ";
    sshpass -p $PASSWD  ssh $SSHOPTION $USER@$TARGET mv $APPDIR/test.war $APPDIR/test.war.$DATE;
    echo "# 1-2 Result: $?";
    echo ""
   
    echo "# 2-1 THIS SERVER to $TARGET [$cnt] SERVER APPLICATION COPY ";
    sshpass -p $PASSWD  scp /tmp/$WARNAME $USER@$TARGET:$APPDIR/$WARNAME;
    echo "# 2-2 Result: $?";
    echo ""
   
    echo "# 3-1 $TARGET [$cnt] SERVER Shutdown ";
    sshpass -p $PASSWD  ssh -t $SSHOPTION $USER@$TARGET "cd $SERVER_BASE/bin; sudo -u $USER ./kill.sh";
    echo "# Result: $?";
    echo ""
   
    echo "# 4-1 $TARGET [$cnt] SERVER Startup ";
    sshpass -p $PASSWD  ssh -t $SSHOPTION $USER@$TARGET "cd $SERVER_BASE/bin; sudo -u $USER ./start.sh notail";
    echo "# Result: $?";
    echo ""
    echo "# TASKS END";
        sleep 1;
      cnt=$((cnt + 1));
    fi
  echo "-------------------------------------------------------------";
    sleep 1;
   
done

2019년 6월 24일 월요일

shell script ip address 순차 증가 후 리모트서버 실행 스크립트

내가 원하는 것은 2가지 였다

1. ip address 를 입력해서 순차적으로 ip address 시퀀스를 하나씩 증가
2. ip address가 연결이 가능할 경우 스크립트를 실행 하도록 명령어 실행

 #!/bin/sh

suba=192
subb=168
subc=23
subd=100

ipaddr=$suba\.$subb\.$subc\.$subd     # ip addr 이 잘 찍히는지 확인

echo "##########################" # 스크립트 시작 알림

while true  # ip addr 가 얼만큼 있을지 모르니 계속 증가
do

  subd=`expr $subd + 1`;    # 변수 초기화에서 늘어 나는 ip submask로 증가
  ipaddr=$suba\.$subb\.$subc\.$subd
  echo "subd = $subd";
  echo "ipaddr = $ipaddr";
  sleep 1;
  PING="`ping -c 1 -w 1 $ipaddr`";   # 핑 테스트 결과가 0 or 1 (0이 성공)

  if [ $? -eq 0 ]; then              # 핑 테스크가 성공 했을 경우
    ipaddr=$suba\.$subb\.$subc\.$subd
    echo "Prepared $ipaddr";
    CMD=`sshpass -proot scp ./ip_get.sh root@$ipaddr:/tmp/`;  # 원격서버에 파일 복사 (put)임
    $CMD
    sleep 1;
    echo "deployed $ipaddr";
  else
    echo "stopped  $ipaddr";   
    break        # 핑 테스크가 실패 했을 경우 빠저나옴
  fi

done

 echo로 디버깅을 해서 프로그램에 문제점을 찾았다


--------------------------------------------------------------------------------------------------
지난 버전
--------------------------------------------------------------------------------------------------
#!/bin/sh

suba=192 # subnet a
subb=168 # subnet b
subc=23  # subnet c
subd=100 # subnet d

ipaddr=$suba\.$subb\.$subc\.$subd   # ip address를 하나로 묶는다.

#echo $ipaddr
echo "##########################"

#CMD=`sshpass -proot scp ./ip_get.sh root@$ipaddr:/tmp/`

while true         # ip adress 를 계속 증가 시키기 위한 반복문
do
  echo "$ipaddr OK"
  NETTEST=`ping -c 1 -w 1 $ipaddr`  # ping을 통해서 서버가 살아 있는지 죽었는지 확인 한다.
  if [ $? -ne 0 ]; then             # ping에 대한 결과 값을 0, 1로 확인이 가능하고 0일 경우(정상) 반복 실행
    echo "NO $ipaddr "
    break
  fi
    subd=`expr $subd + 1`;         # 1씩 증가
    sleep 1;
    ipaddr=$suba\.$subb\.$subc\.$subd  # ip address 증가
    CMD=`sshpass -proot scp ./ip_get.sh root@$ipaddr:/tmp/` #scp를 통해서 리모트서버에 파일 복사
    $CMD

done

이게 정답이 아닌거 같은 느낌이 들지만

그래도 일단 써보고 개선 해야 겠다.