IT_Server/Web_Server & WAS

[펌] TOMCAT 톰캣 멀티인스턴스 구성 방법

JJun ™ 2017. 10. 13. 02:27



 * 출처

 : https://csslab.tistory.com/124






하나의 톰캣을 여러개의 인스턴스로 구성해보자.

이는 하나의 톰캣을 여러개의 카피본을만들어 사용하는것 과 비슷하다.
하지만 톰캣 기본 모듈은 공유해서 사용하는 점에서 카피와는 다르다.

톰캣의 엔진에 해당되는 기본 모듈은  bin, lib 2개의 폴더를 뜻한다.
그외에  conf,logs,temp,work,webapps  등은 인스턴스 별로 구성이 되도록 되어 있다.

구성에 대해 설명하면

/home/suhan/tomcat8  이 기본적으로 설치한 톰캣의 위치가 되겠다.
/home/suhan/apps 라는 이름으로 톰캣의 실제 앱들에 대한 설정을 따로 관리하겠다.


1> 인스턴스 폴더 생성

/home/suhan/apps/server1   // 1번 인스턴의 위치
/home/suhan/apps/server2  // 2번 인스턴의 위치

2> 각 인스턴스의 위치에  인스턴스별 폴더인  conf,logs,temp,work,webapps/ROOT/index.jsp  를  생성한다.

webapps는 아래에 ROOT 폴더아래에  index.jsp 파일도 생성한다.
tomcat8/conf/server.xml  web.xml 2개의 파일을 각각의 인스턴스의 conf 로 복사한다.


3> server.xml 파일을 수정한다.

포트를 알맞게 변경해야 된다. 서로 충돌이 생기지 않도록...아래는 대충 예로 만들어 봤다.
인스턴스 번호를 포트에 넣어서 혼선이 생기지 않도록 했다.

1번 인스턴스

2
3
4
5
<Server port="8105" shutdown="SHUTDOWN">
<Connector port="8180" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8144" />
<Connector port="8109" protocol="AJP/1.3" redirectPort="8144" />


2번 인스턴스

2
3
4
5
<Server port="8205" shutdown="SHUTDOWN">
<Connector port="8280" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8244" />
<Connector port="8209" protocol="AJP/1.3" redirectPort="8244" />


3번 인스턴스

2
3
4
5
<Server port="8305" shutdown="SHUTDOWN">
<Connector port="8380" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8344" />
<Connector port="8309" protocol="AJP/1.3" redirectPort="8344" />



4> start , stop용 스크립트를 생성한다.

1번 인스턴스 시작

#!/bin/sh

export  CATALINA_HOME=/home/suhan/tomcat8

export  CATALINA_BASE=/home/suhan/apps/server1

export  CATALINA_OPTS="-Denv=product -Denv.servername=server1"

cd $CATALINA_HOME/bin

./startup.sh



1번 인스턴스 종료

#!/bin/sh

export  CATALINA_HOME=/home/suhan/tomcat8

export  CATALINA_BASE=/home/suhan/apps/server1

export  CATALINA_OPTS="-Denv=product -Denv.servername=server1"

cd $CATALINA_HOME/bin

./shutdown.sh


물론 생성후  chmod +x  *.sh 로 실행권한을 준다.

2번 3번도 알맞게 생성한다..
공용 스트립트에 인자로 인스턴스번호를 받는것도 가능하다..

방화벽 설정에 문제가 없다면 정상적으로 접근이 가능할 것이다.
실제 실무에선 Apache 를 통해서 AJP 를 통해서 접근하게 될 것이다.
아파치에 mod_jk 를 로딩 후 분산을 하거나 한서버에 여러개의 인스턴스로 서비스를 구성할 때이다.

아래 설정은 요길 참조한다.
http://blog.naver.com/forioso/220380005018

더보기
Apache 를 이용한 Tomcat 분산


1> 아파치 AJP Connector 다운로드 

아파치에서 tomcat 을 연동하기 위해서 필요한 모듈을 로딩해야 된다. mod_jk 로 사이트에서 다운로드 가능하다.

http://ftp.daumkakao.com/apache/tomcat/tomcat-connectors/ 

속도는 다움카카오가 빠르다.



http://tomcat.apache.org/download-connectors.cgi

http://mirror.apache-kr.org/tomcat/tomcat-connectors/jk/binaries/

http://tomcat.apache.org/connectors-doc/

http://apache.mirror.cdnetworks.com/tomcat/tomcat-connectors/jk/binaries/windows/

 

http://tkstone.blog.me/50194372579



1.2.37 64 bit 바이너리

http://lesstif.com/download/attachments/12943367/mod_jk_1.2.37-x86_64.tar.gz?version=1&modificationDate=1382662783000&api=v2



바이너리를 받지 않을거면 소스를 받어야 되는데 그렇다면 컴파일을 해야 된다.

 # yum install gcc  httpd-devel  wget 

 # wget http://ftp.daum.net/apache//tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.40-src.tar.gz

 

 # tar zxvf tomcat-connectors-1.2.40-src.tar.gz

 # cd tomcat-connectors-1.2.40-src/native

 # ./configure --with-apxs=/usr/sbin/apxs    // 오류시에는  which apxs로 찾는다.

 # make

 # make install


 # cp mod_jk.so /etc/httpd/modules/mod_jk.so

 # ls -lZs /etc/httpd/modules/ 해보면 카피한 파일이 권한이 다른걸 확인가능

 # chcon -u system_u -r object_r -t httpd_modules_t /etc/httpd/modules/mod_jk.so 

 # ls -lZ  /etc/httpd/modules/  권한이 같아진걸 확인




2> 설정

http://tomcat.apache.org/connectors-doc/generic_howto/loadbalancers.html


/etc/httpd/conf/httpd.conf    아파치에서 모듈 로딩 설정 

 LoadModule  jk_module  modules/mod_jk.so



Vitual host 상에서는 간단히 VirtualHost 에서 JkMount 로 처리


 

<VirtualHost *:80>

..


JkMount /* balancer
JkUnMount /resources/* balancer

</VirtualHost *:80>





아래처럼 디테일한 설정을 하거나. 할 수 있다.


/etc/httpd/conf.d/mod_jk.conf  jk 관련 설정

 

<IfModule mod_jk.c>
  # Where to find workers.properties
  JkWorkersFile conf/workers.properties
  
  # Where to put jk shared memory
  JkShmFile run/mod_jk.shm
  
  # Where to put jk logs
  JkLogFile logs/mod_jk.log
  
  # Set the jk log level [debug/error/info]
  JkLogLevel debug
  
  # Select the timestamp log format
  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
 
  ## url pattern 에 따른 워크연결
  #JkMount  /do/* balancer
 
  ## url pattern 에 따른 connector mapping
  JkMountFile conf/mapping.properties
</IfModule>


url 매핑설정을 별도파일을 사용해서 설정도 가능

conf/mapping.properties

## Mapping the URI /service1 under worker1
/service1/*.do=balancer
/service1/*.jsp=product
 
# /service2 요청으로 들어온 것은 worker2 로 mount
/service2/*=worker2
 
# png와 jpg 는 apache 가 처리
!/service2/*.png=worker2
!/service2/*.jpg=worker2



실설정 기본예  mapping.properties

!/resource/*=balancer    (/resource/ 폴더가 아닌 모든 컨텐츠를 balancer 로 넘겨라.

/*=balancer   (모든걸 balancer 로 넘겨라 )




/etc/httpd/conf/workers_properties


worker.list=balancer,tomcat1,tomcat2   #(balancer 가 받어서 tomcat1,tomcat2로 분배)


#lb 로드 밸런스

worker.balancer.type=lb

worker.balancer.balance_workers=tomcat1,tomcat2

#worker.balancer.sticky_session=1    or   true


worker.tomcat1.type=ajp13

worker.tomcat1.host=192.168.0.2

worker.tomcat1.port=8009

#worker.tomcat1.lbfactor=1  # 가중치

#worker.tomcat1.redirect=tomcat2  



worker.tomcat1.type=ajp13

worker.tomcat1.host=192.168.0.3

worker.tomcat1.port=8009

#worker.tomcat1.lbfactor=1



sticky_session 이란 로드분배시 한 사용자가 접근했던 서버로 다음 요청을계속적으로 보내는 것을 말한다.





WAS 설정

양 톰캐서버의 conf/server.xml 에 포트랑 네임 수정

<Server port="8005" protocol="SHUTDOWN">
..
..
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" 
URIEncoding="UTF-8"/>

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1"/>

  

<Server port="8006" protocol="SHUTDOWN">
..
..
<Connector port="8019" protocol="AJP/1.3" redirectPort="8443" 
URIEncoding="UTF-8"/>

<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2"/>

  

톰캣에서 웹을 서비스 하진 않을것이므로  <Connector port="8080" protocol="HTTP/1.1" 는 주석 처리해도 된다.


 





하나의 서버에서 2개의 포트로 테스트 할 경우 또는 톰캣 8009 기본 포트가 아닌 다른 포트로 서비스 할때는 selinux 를 설정해야만 한다.


간단힌 #setenforce 0 해서 잘 되면 selinux 문제이다.


해결을 위해서는.  


 # yum install polycycoreutils-pyton

 # semanage  port -l  | grep http_port_t 
 # semange  port -a -t http_port_t -p tcp 8019

처럼 웹 포트로 추가해죠야 한다.




위처럼 해서 테스트 해보면

1번 톰캣과 2번톰캣이 failover 가 가능하다

1번 접속하면 접속했던 서버로 계속 보낸다.그렇기에 세션문제가 없다.

하지만 접속했던 서버가 죽었을때 failover에 의해 다른 서버로 접근하게 될때 세션문제가 발생된다.

 

두 서버의 세션을 공유하도록 설정해보자.






세션공유하도록 설정추가하기..


conf/server.xml 을 수정한다.  주석처리된 Cluster 태그부분에 아래를 카피해서 넣는다.


SimpleTcp=메모리에 세션저장 이외에 DB저장,File 저장이 있음  port만 톰캣별로 다르게 설정

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"

             channelSendOptions="8">

  <Manager className="org.apache.catalina.ha.session.DeltaManager"

            expireSessionsOnShutdown="false"

           notifyListenersOnReplication="true"/>

  <Channel className="org.apache.catalina.tribes.group.GroupChannel">

   <Membership className="org.apache.catalina.tribes.membership.McastService"

    address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/>

   <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"

   address="autoport="4001autoBind="100"

     selectorTimeout="3000" maxThreads="6"/>  

    <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">

<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>

</Sender>

<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>

<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>

  </Channel >

        <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/>

        <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

        <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"

           tempDir="/tmp/war-temp/" deployDir="/tmp/war-deploy/"

             watchDir="/tmp/war-listen/" watchEnabled="false""/>

       <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>

       <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>

</Cluster


2번 서버는 ip와 포트를 서버에 맞게 변경

그리고 동작 시킬 어플리케이션의 web.xml 에서

<web-app 안에

<distributable/> 을 추가한다.


세션의 데이터는 java.io.Serializable 인터페이스를 상속받는 클래스여야 서버가 정상구동되며,

톰캣의 클러스트링은 스트링만 지원하면 클래스를 위해서는 JBoss 를 이용해야 된다.



1>  mod_jk 연동 설정

 apxs 를 설치하기 위해  httpd-devel 이 필요한다. 

# which  apxs

# yum install -y wget perl  gcc httpd-devel 

# which apxs

   /usr/bin/apxs

# wget http://ftp.daumkakao.com/apache/tomcat/tomcat-connectors/jk/tomcat-connectors-1.2.41-src.tar.gz

 # tar  zxvf tomcat-conn~

 # cd tomcat-conn~

 # cd native

 # ./configure  --with-apxs=/usr/bin/apxs

 # make

 # make install


모듈 로딩

 # cd /etc/httpd/conf.module.d

 # vi 00-mod-jk.conf

   LoadModule  jk_module  modules/mod_jk.so


mod-jk 설정

 # vi  /etc/httpd/conf,d/mod-jk.conf

<IfModule  mod_jk.c>

 JkWorkersFile   conf.d/workers.properties

 JkShmFile   run/mod_jk.shm

 JkLogFile   logs/mod_jk.log

 JkLogLevel   error

# JkMount    /do/*   l4switch

# JkMountFile   conf.d/maping.properties

</IfModule>



2> 버츄얼 로스트 설정

 <VirtualHost *:80>

        ServerName   domain.com
        Redirect   /   http://www.domain.com/

</VirtualHost *:80>

<VirtualHost *:80>

        ServerName   www.domain.com
        DocumentRoot /home/suhan/www
        # ErrorLog     /home/sunny/logs/error_log
        # CustomLog    /home/sunny/logs/access_log common

        <Directory /home/suhan/www>
                Options None
                AllowOverride None
                Require all granted                
        </Directory>

       JkMount  /* l4switch
       JkUnMount  /resources/*  l4switch
       JkUnMount  /phpMyAdmin/*  l4switch

</VirtualHost>



3>  work 설정

가장 기본적인 설정
하나의 서버만 동작.. 

 # vi /etc/httpd/conf.d/workers.properties

worker.list=l4switch


worker.l4switch.type=ajp13

worker.l4switch.host=192.168.0.2

worker.l4switch.port=8009     # AJP/1.3 포트


2. 둘 이상 서버로 로드밸런싱.

 # vi /etc/httpd/conf.d/workers.properties

worker.list=l4switch,tomcat119,tomcat200

worker.l4switch.type=lb
worker.l4switch.balance_workers=tomcat119,tomcat200
#worker.l4switch.sticky_session=true

worker.tomcat119.type=ajp13
worker.tomcat119.host=192.168.0.2
worker.tomcat119.port=8009     # AJP/1.3 포트
worker.tomcat119.lbfactor=1      #분산 가중치

worker.tomcat200.type=ajp13
worker.tomcat200.host=localhost
worker.tomcat200.port=8009     # AJP/1.3 포트

worker.tomcat200.lbfactor=2     # 로컬에 가중치 2배



3. 각각 다른 2개의 서비스

 # vi /etc/httpd/conf.d/workers.properties

worker.list=,tomcat119, tomcat200

worker.tomcat119.type=ajp13
worker.tomcat119.host=192.168.0.2    # 다른서버도 가능
worker.tomcat119.port=8109     # AJP/1.3 포트
worker.tomcat119.lbfactor=1      #분산 가중치

worker.tomcat200.type=ajp13
worker.tomcat200.host=localhost
worker.tomcat200.port=8209     # AJP/1.3 포트

worker.tomcat200.lbfactor=1     

  


4> Was 설정

WAS 설정 (여러 배포버전이 돌때..)

 # vi  conf/server.xml

<Server port="8105" shutdown="SHUTDOWN">

<Connector port="8180" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="84431" />

<Connector port="8109" protocol="AJP/1.3" redirectPort="84431" URIEncoding="UTF-8" />

<Engine name="Catalina"  defaultHost="localhost" jvmRoute="tomcat119"/>

       <Host name="www.edutotal.com"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

        <Context docBase="sample" path="" reloadable="true" privileged="true"/>

      </Host>

      <Host name="box.edutotal.com"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

        <Context docBase="cloud_box_web" path="" reloadable="true" privileged="true"/>

      </Host>

</Engine>



2번째 인스턴스  

 # vi  conf/server.xml

<Server port="8205" shutdown="SHUTDOWN">

<Connector port="8280" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="84432" />

<Connector port="8209" protocol="AJP/1.3" redirectPort="84432" URIEncoding="UTF-8" />

<Engine name="Catalina"  defaultHost="localhost" jvmRoute="tomcat200" />

      <Host name="api.edutotal.com"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

        <Context docBase="examples" path="" reloadable="true" privileged="true"/>

      </Host>

</Engine>


설정 다하고 재시작하고 포트올라온거까지 확인했는데...
화면에는 Service Unavailable 뜨고, mod_jk 로그에는 503 오류가 난다면....
십중팔구  SeLinux  때문이다. 폰트 키웠다.. 엄청 자주 발생하고 삽질하는 오류다.

대충 후 양쪽을 재시작 하자.
하지만.. 실서버에선 바로 동작 하지 않을수가 있다.  selinux 때문이다.
항상 서버 셋팅하다보면 selinux 때문에 막혀서 헤메는 경우가 많다.

AJP 포트로 설정한 8109 8209 등은 selinux 에서 열어주기 전엔 막혀 있다.

해결을 위해서는.  

 # yum install polycycoreutils-pyton

 # semanage  port -l  | grep http_port_t
 # semanage  port -a -t http_port_t -p tcp 8109

 semanage  port -a -t http_port_t -p tcp 8209

처럼 웹 포트로 추가해줘야 한다. 


JAVA 버전

가끔씩 JAVA 버전이 달라 오류가 날때가 있다.
서버는 1.7 버전인데 로컬에서 1.8 최신으로 빌더후 서버 배포시 버전차이고 로딩이 되지 않을때가 있다.
서버를 1.8로 업그레이드 하면 좋지만...운영중인 다른 서비스가 물려있다면 부담스럽다.

이럴 경우 별도로 1.8을 설치후 새로운 tomcat 만 1.8을 사용하도록 설정해 보자.

자바 파일을 다운로드한다.   jdk-8u121-linux-x64.tar.gz

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

# tar zxvf jdk-8u121-linux-x64.tar.gz
# ls -al 
   drwxr-xr-r-x 3 unisecure unisecre 4096 12월  jdk1.8.0_121


이제 Start stop 스크립트에

export  JAVA_HOME=/home/suhan/jdk1.8.0._121

을 추가해주자...

 

● https://beyondj2ee.wordpress.com/2012/07/03/%EB%A9%80%ED%8B%B0-%ED%86%B0%EC%BA%A3-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4%EB%A1%9C-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0-multiple-tomcat-instances/
● https://www.mynotes.kr/tomcat-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0/
● http://linux.systemv.pe.kr/tomcat-multi-instance-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0/