본문 바로가기
서버구축 (WEB,DB)

Apache + mod_jk + JBoss/Tomcat 연동

by 날으는물고기 2009. 4. 10.

Apache + mod_jk + JBoss/Tomcat 연동

JBoss/Tomcat은 Jakarta Connector를 사용해 아파치, IIS, Sun One 등의 웹서버와 연동이 가능하다. Jakarta Connector는 웹서버에 따라 모듈명이 다른데 다음과 같다.

- 아파치: mod_jk

- IIS: isapi_redirect

- Sun Java System Web Server: nsapi_redirect

 

mod_jk를 사용해 아파치와 JBoss/Tomcat을 연결할 때 필요한 작업은 다음과 같다.

1) 아파치 mod_jk 설치 및 설정

   - httpd.conf에 Include mod_jk.conf 추가

   - mod_jk.conf 작성

   - workers.properties 작성

   - uriworkermap.properties 작성

   (*) 물론 별도로 mod_jk.conf, workers.properties, uriworkermap.properties를 작성하지 않고 httpd.conf에다 설정할 수도 있으나, 설정을 분리하는 것이 관리하는데 유리하다.

2) JBoss/Tomcat 설정

   - jvmRoute 및 AJP connector 설정

   - UseJK 설정

   (*) jvmRoute와 UseJK 설정은 sticky session 로드 밸런싱을 위한 것으로 JBoss를 하나만 띄울 경우에는 별도로 설정하지 않아도 된다.

 

일반적인 mod_jk 연동 설정에 관한 글들은 웹 상에서 많이 찾을 수 있으므로 여기서는 운영환경에서 필요한 설정을 위주로 설정 항목들을 하나씩 살펴보자.

 

1. mod_jk 다운로드 및 설치

 mod_jk는 Tomcat 홈페이지에서 소스 또는 바이너리를 다운받을 수 있다.

 http://tomcat.apache.org

 

바이너리를 다운로드 받아 설치할 경우에는 아파치 웹서버 버전과 운영체제 버전에 맞는 mod_jk를 받아야 한다. 특히 mod_jk-1.2.26-httpd-2.2.6.so와 같이 웹서버 minor 버전이 명시된 경우에는 반드시 동일한 버전 또는 그 이후 버전의 웹서버에서만 사용 가능하므로 주의가 필요하다.

 

바이너리를 받았다면 이를 $APACHE_HOME/modules 디렉터리로 복사한다. 보통 mod_jk.so로 파일명을 변경하는데 그보다는 원래 파일명을 그대로 유지하는 것이 좋다.

 

소스를 받았다면 http://wiki.jboss.org/wiki/Wiki.jsp?page=CompilingMod_jk 을 참조해 컴파일한 후 $APACHE_HOME/modules 디렉터리로 복사한다.

 

2. httpd.conf 설정

 $APACHE_HOME/conf/httpd.conf 파일을 열어 Include conf.d/mod_jk.conf를 추가한다.

Red Hat Enterprise Linux 5.x는 이미 Include conf.d/*.conf가 포함되어 있으므로 별도로 추가할 필요가 없다.

 

3. mod_jk.conf 작성

 여기에서 mod_jk 모듈을 로드하고 worker 파일 및 uri mapping 파일을 설정한다.

 <IfModule !mod_jk.c>
  LoadModule jk_module modules/mod_jk-1.2.23-apache-2.2.x-linux-i686.so
</IfModule>

 

# jk 로그파일 위치 지정
JkLogFile logs/mod_jk.log

# jk 로그레벨 설정 [debug|error|info]     연동이 잘 안되면 로그 레벨을 debug로 설정해서 로그를 확인할 것
JkLogLevel info

# jk 로그 포맷 설정
JkLogStampFormat  "[%a %b %d %H:%M:%S %Y] "
JkRequestLogFormat "%w %V %T"

 

# JkOptions 지정

JkOptions +ForwardKeySize +ForwardURICompatUnparsed -ForwardDirectories

 

# worker 파일 위치 지정, 아래는 APACHE_HOME/conf.d 아래에 위치하는 것으로 가정
JkWorkersFile conf.d/workers.properties

 

# uri 매핑 파일 위치 지정, 아래는 APACHE_HOME/conf.d 아래에 위치하는 것으로 가정
JkMountFile conf.d/uriworkermap.properties

 

# 로드 밸런싱을 위해 shared memory 설정

# SELinux를 사용할 경우에는 문제가 발생할 수 있으므로, 이 때는 run/jk.shm으로 변경

# https://bugzilla.redhat.com/show_bug.cgi?id=225452

JkShmFile logs/jk.shm

 

# Add jkstatus for managing runtime data
<Location /jkstatus/>
    JkMount jkstatus
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Location>

 

JkOptions의 기본값은 mod_jk 버전에 따라 다를 수 있으므로 명시적으로 지정해 주는 것이 좋다.

worker나 uri mapping은 별도의 파일을 사용하지 않고 JkWorkerProperty, JkMount/JkUnMount 명령으로 직접 명시할 수 있다. 하지만, 별도의 파일로 분리하는 것이 알아 보기 좋으며, 특히 JkMountFile로 명시하면 60초 마다 매핑 파일 변경 여부를 체크하므로 웹 서버를 재기동하지 않고 웹 어플리케이션에 대한 매핑을 추가할 수 있어 편리하다.

 

- JkLogFile

   로그 파일 위치를 설정

   웹 서버 프로세스 실행 계정이 해당 디렉터리에 쓰기 권한을 가지고 있어야 함

- JkLogLevel

   로그 레벨을 설정 (error, warn, info, debug, trace)

   기본값은 info

- JkLogStampFormat

   로그상의 날짜 포맷

- JkRequestLogFormat

   기본값이 없으며, 이 포맷이 설정되지 않은 경우 request는 로그 파일에 기록되지 않음

   보통  "%w %V %T"를 설정

     %w - JBoss/Tomcat worker name

     %V - server name

     %T - 요청 처리 시간 (초단위)

     출력예)  [목   1월 31 07:21:54 2008] host1 localhost 0.100840

- JkOptions

   request 전달시 적용할 옵션

   +option - enable

   -option - disable

   ForwardURICompatUnparsed - 요청에 포함된 URI를 원래 그대로 전달.

- JkWorkersFile

   worker 정의 파일 위치를 설정

   별도 파일로 분리하지 않고 JkWorkerProperty 지시어를 사용해 바로 worker를 설정할 수도 있음

- JkMountFile

   URI 매핑을 정의한 파일의 위치

   파일이 변경되면 mod_jk는 내용을 리로드함

  

4. workers.properties 작성

 mod_jk에서 각 JBoss/Tomcat instance별로 worker를 설정하게 된다.

worker는 worker.<worker_name>.<directive>=<value> 형식으로 정의된다.

 

worker.list=wlb,jkstatus

 

worker.node1.host=192.168.110.1

worker.node1.port=8009

worker.node1.type=ajp13

worker.node1.connect_timeout=5000

worker.node1.prepost_timeout=5000

worker.node1.socket_keepalive=True

worker.node1.socket_timeout=10

#worker.node1.connection_pool_size=25

#worker.node1.connection_pool_timeout=600

 

worker.node2.host=192.168.110.2

worker.node2.port=8009

worker.node2.type=ajp13

worker.node2.connect_timeout=5000

worker.node2.prepost_timeout=5000

worker.node2.socket_keepalive=True

worker.node2.socket_timeout=10

#worker.node2.connection_pool_size=25

worker.node2.connection_pool_timeout=600

 

# jk 1.2.7 이전 버전에서는 balanced_workers를 사용

# balance_workers에 명시된 worker는 worker.list에는 명시하지 않아야 함

worker.wlb.type=lb

worker.wlb.balance_workers=node1,node2

 

worker.jkstatus.type=status

 

worker는 ajp13, lb, status 등의 type이 있으며, JBoss/Tomcat worker는 ajp13 type으로 설정된다.

JBoss/Tomcat worker 설정시 기본으로 host와 port를 설정하게 되는데, host에는 DNS lookup을 하지 않도록 ip로 설정하는 것이 좋다.

 

여러 개의 JBoss/Tomcat instance를 띄워 로드 밸런싱 및 fail over를 구성할 경우에는 connect_timeout과 prepost_timeout을 설정해 준다. 이들 값은 ms 단위로, 처음 ajp connection 후나 요청 전달 전에 ajp protocol 상의 CPING/CPONG 메시지를 주고 받아 연결에 이상이 없는지 확인한다. 이와 별도로 socket_timeout으로 물리적인 socket의 timeout을 초단위로 설정할 수 있다.

 

웹 서버와 JBoss/Tomcat 사이에 방화벽이 있는 경우에는 connection_pool_timeout과 socket_keepalive를 설정해 준다. 이 때 connection_pool_timeout 값은 방화벽의 세션 타임아웃 시간 보다 작게 설정해야 하며, JBoss/Tomcat AJP connector의 connectionTimeout과 동일한 시간으로 설정한다.

 

주의할 점은 connection_pool_timeout은 초 단위이나 AJP connector의 connectionTimeout은 ms 단위이므로, 위의 예제와 같이 connection_pool_timeout을 600 (10분)으로 설정했다면 connectionTimeout은 600000으로 설정해야 한다.

 

connection_pool_size는 코멘트 처리해 놓았는데 아파치 Prefork 모델을 사용할 경우에는 이 값을 설정하지 않거나 1로 설정해야 한다. Worker 또는 Thread 모델을 사용할 경우에는 connection_pool_size의 기본값이 자동으로 ThreadsPerChild 값으로 설정된다. 이 값은 JBoss/Tomcat AJP connector의 thread 개수와 아파치의 connection pool 개수를 맞출 때 사용된다.

 

(*) 아파치 웹서버의 전체 connection pool 개수가 JBoss/Tomcat AJP connector thread의 개수를 초과해서는 안된다.

     --> Prefork 모델의 경우 전체 connection pool 개수는 MaxClients

           Worker 모델의 경우 전체 connection pool 개수는 (MaxClients / ThreadsPerChild) * connection_pool_size

           NT thread 모델의 경우 전체 connection pool 개수는 connection_pool_size

     --> 전체 connection pool 개수가 JBoss/Tomcat AJP connector의 maxThreads 보다 크다면?

           일부 요청은 새로 ajp connection을 연결하느라 hang 상태에 걸리게 된다.

 

 

5. uriworkermap.properties 작성

 # /myapp와 그 하위를 wlb worker로 매핑

/myapp=wlb

/myapp/*=wlb

 

# /jmx-console과 그 하위를 wlb worker로 매핑 - |/*

/jmx-console|/*=wlb

 

# /myapp 아래의 *.jpg는 웹서버에 있으므로 매핑에서 제외

!/myapp/*.jpg=wlb

 

# *.jsp와 *.do는 wlb worker로 매핑

/*.jsp=wlb

/*.do=wlb

 

Reference Guide에는 확장자 매핑시 /로 시작하지 않으나, mod_jk 버전에 따라 /로 시작하지 않으면 에러를 내기도 한다.

 

 

6. jvmRoute 및 AJP connector 설정

 mod_jk를 사용해 아파치와 JBoss/Tomcat과 연동할 경우 AJP 프로토콜을 사용하므로 AJP connector를 반드시 활성화해야 한다. 만약 코멘트 처리되어 있다면 이를 해제해준다.

 

 $JBOSS_HOME/server/<jboss_instance_name>/deploy/jboss-web.deployer/server.xml

      <!-- A AJP 1.3 Connector on port 8009 -->
      <Connector port="8009" address="${jboss.bind.address}"
         emptySessionPath="true" enableLookups="false" redirectPort="8443"

         maxThreads="250" connectionTimeout="600000"
         protocol="AJP/1.3"/>

 

      <Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1" >

          ... ...

 

 

Tomcat은 기본 설정 시 Thread per Connection 모델을 지원한다. 쉽게 얘기하면 connection 마다 thread가 하나씩 전담으로 붙어서 서비스를 한다. 따라서, maxThreads는 다르게 보면 최대 연결 개수가 된다. 이에 따라 앞서 "4. workers.properties 작성" 항목에서 언급했듯이 maxThreads 이상의 연결은 만들어질 수 없으므로 아파치 단에서 만들 수 있는 ajp connection 개수를 제한해야 한다.

 

참고로, 로드 밸런싱을 구성한 경우에는 로드 밸런싱의 오차를 감안해서 한 아파치에서의 최대 ajp connection 개수보다 maxThreads를 20% 정도 더 크게 잡는게 좋다.

 

(*) maxThreads 값은 성능 테스트 결과 최대 TPS를 내는 개수로 잡는다. 그리고, 이를 기준으로 아파치 웹서버에 JBoss/Tomcat으로 연결 가능한 ajp connection 개수 (기본 설정시 MaxClients 값)를 설정한다. 단순히 아파치에서 JBoss/Tomcat으로 연결이 안된다고 AJP connector의 maxThreads 값을 잔뜩 늘리면 이제는 JBoss/Tomcat에서 처리가 늦어져서 또 다른 문제가 발생하게 된다.     

 

(*) JBoss/Tomcat native 모듈 (APR)을 사용하면 Thread per Connection 모델이 아닌 Thread per Request 모델을 사용하므로 위의 제약을 회피할 수 있다.

 

7. UseJK 설정

 클러스터링을 구성할 경우에는 sticky session을 사용하도록 jvmRoute와 함께 UseJK 설정을 해준다.

 

 $JBOSS_HOME/server/<jboss_instance_name>/deploy/jboss-web.deployer/META-INF/jboss-service.xml
      <attribute name="UseJK">true</attribute>

 

 

8. Buddy Replication 설정

  참고로, 4개 instance 이상 대규모로 클러스터를 구성할 경우에는 전체 노드로 세션을 복제하는데 따른 오버헤드가 커지게 된다. 이럴 때는 Buddy Replication을 사용해 설정한 만큼의 백업 노드로만 세션을 복제하도록 해 성능 저하를 막을 수 있다.

 $JBOSS_HOME/server/<jboss_instance_name>/deploy/jboss-web-cluster.sar/META-INF/jboss-service.xml

         <attribute name="BuddyReplicationConfig">
            <config>
                <buddyReplicationEnabled>true</buddyReplicationEnabled>
                <buddyLocatorClass>org.jboss.cache.buddyreplication.NextMemberBuddyLocator</buddyLocatorClass>
                <buddyLocatorProperties>
                    numBuddies = 1
                    ignoreColocatedBuddies = true
                </buddyLocatorProperties>

 

                <buddyPoolName>buddyPool1</buddyPoolName>
                <buddyCommunicationTimeout>2000</buddyCommunicationTimeout>

 

                <autoDataGravitation>false</autoDataGravitation>
                <dataGravitationRemoveOnFind>true</dataGravitationRemoveOnFind>
                <dataGravitationSearchBackupTrees>true</dataGravitationSearchBackupTrees>

            </config>
        </attribute>

 

buddy replication을 사용하려면 buddyReplicationEnabled를 true로 변경하고, 친구로 묶을 노드들의 buddyPoolName을 동일하게 설정해준다.

 

 

참고자료

http://wiki.jboss.org/wiki/Wiki.jsp?page=UsingMod_jk1.2WithJBoss

http://wiki.jboss.org/wiki/Wiki.jsp?page=UsingMod_jk1.2WithAFirewall

http://wiki.jboss.org/wiki/Wiki.jsp?page=OptimalMod_jk1.2Configuration

http://wiki.jboss.org/wiki/Wiki.jsp?page=UsingMod_jk1.2WithJBossAndIIS

 

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

http://tomcat.apache.org/connectors-doc/reference/workers.html

http://tomcat.apache.org/connectors-doc/reference/uriworkermap.html

 

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

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

728x90

댓글