출처: 자바서비스넷

 
대충 설명드리고 조금씩 내용을 추가하도록 하겠습니다.

Solaris 8 환경에서 apache 2.0.53과 Tomcat 5.5.7로 연동테스트 하였습니다.

[설명]

- Load Balancing , Fail Over - 

머신은 2대로 각 머신은 172.16.1.79번, 172.16.1.70번으로 IP할당했습니다.
각 머신에 Apache와 Tomcat을 설치했습니다.
JK2 Connector를 사용하면 FailOver 및 LoadBalancing기능이 구현됩니다.
79번 서버의 아파치로 온 요청은 79번 서버의 Tomcat으로 전달되거나 70번 서버의 Tomcat으로 
전달될 수 있고 마찬가지로 70번 서버의 아파치로 온 요청은 70번 서버의Tomcat이나 79번 
서버의 Tomcat으로 전달될 수 있습니다. 이것이 LoadBalancing 개념입니다.
또 만약 79번 서버의 톰캣이 죽은 경우 JK2 Connector가 알아서 79번 Tomcat이 다시 구동되기
전까지는 79번쪽의 톰캣쪽으로는 요청을 보내지 않습니다. 이것이 FailOver 기능입니다.

- Session Clustering -

Session Clustering 을 구현하기 위해서는 각 Tomcat의 server.xml과 web.xml을 적당히 
수정해 주면 됩니다.

- Connection Pool -

제가 설정하는 Connection Pool은 Commons Project의 DBCP를 사용합니다.
Commons DBCP 와 Runtime에 필요한 기타 Commons Package를 다운받아
tomcat홈의 common/lib에 복사해 넣으시면 됩니다.

[Tomcat 5.5.7 설치]

Binary 버젼 다운 받아서 압축만 풀면 됩니다.
79번과, 70번서버의 /opt/tomcat5 에 각각 설치합니다.

[Apache 2.0.53 설치]

아파치 소스를 다음과 같이 /export/home/auction/httpd-2.0.53 에 풀고 
아래와 같이 진행합니다.
참고로 config.layout에 설치 Directory구조를 명시해 두면 편리합니다.
제가 추가한 Layout명칭은 "Rednics" 입니다.
이 명칭을 configure 실행시 --enable-layout 옵션값으로 설정하면 됩니다.
아래의 같이 79번서버와 70번 서버에 각각 설치합니다.

> cd /export/home/auction/httpd-2.0.53
> vi config.layout
####################################################
<Layout Rednics>
    prefix:        /opt/apache2
    exec_prefix:   ${prefix}
    bindir:        ${prefix}/bin
    sbindir:       ${prefix}/sbin
    libdir:        ${prefix}/lib
    libexecdir:    ${prefix}/libexec
    mandir:        ${prefix}/man
    sysconfdir:    ${prefix}/conf
    datadir:       ${prefix}/share
    installbuilddir: ${datadir}/build
    errordir:      ${prefix}/var/error
    iconsdir:      ${datadir}/icons
    htdocsdir:     /export/home/els/rednics/htdocs
    manualdir:     ${prefix}/manual
    cgidir:        ${prefix}/cgi-bin
    includedir:    ${prefix}/include
    localstatedir: ${prefix}/var
    runtimedir:    ${localstatedir}/run
    logfiledir:    ${localstatedir}/logs
    proxycachedir: ${localstatedir}/proxy
</Layout>
###################################################
> ./configure --enable-layout=Rednics --enable-module=so
> make
> make install

[JK2 Connector 빌드]

JK2 Connector를 설치하기 위해서는 Tomcat Binary가 아닌 Tomcat Source 파일도 
다운받아야 합니다. 그래서 저는 jakarta-tomcat-5.5.7-src.tar 를 다운받아 
/export/home/auction/jakarta-tomcat-5.5.7-src/ 에 풀었습니다.

그리고 JK Connector 빌드시에 다음과 같은 Package가 필요하므로 특정 Package가 
설치되어 있지 않은경우는 ftp://ftp.sunfreeware.com/pub/freeware/sparc/5.8/ 에서 
다운로드하여 아래와 같이 Package를 설치하여야 합니다.
저는 설치되지 않은 Package가 많아서 아래와 같이 많은 Package를 추가하였습니다.

> pkgadd -d autoconf-2.59-sol8-sparc-local
> pkgadd -d automake-1.9-sol8-sparc-local
> pkgadd -d gzip-1.3.5-sol8-sparc-local
> pkgadd -d libtool-1.5-sol8-sparc-local
> pkgadd -d m4-1.4.2-sol8-sparc-local
> pkgadd -d make-3.80-sol8-sparc-local
> pkgadd -d tar-1.15.1-sol8-sparc-local

그리고 빌드과정중 perl관련해서 에러가 발생할 수 있으므로 다음과 같이
해줍니다.

> ln -s /usr/bin/perl /usr/local/bin/perl

이제 빌드를 시작합니다.

> cd /export/home/auction/jakarta-tomcat-5.5.7-src/jakarta-tomcat-connectors/jk/native2
> ./buildconf.sh
> ./configure --with-apxs2=/opt/apache2/sbin/apxs --with-java-home=/usr/j2se --with-java-platform=2
> make
> cd ../build/jk2/apache2
> /opt/apache2/sbin/apxs -n jk2 -i mod_jk2.so


[톰캣, 아파치 설정]

JK2를 아파치와 연동하기 위해서는 아래와 같이
/opt/apache2/conf 에 mod_jk2.conf 와 workers2.properties
파일이 필요합니다.
설정파일들을 구할수 없다면 아래의 예를 복사해서 해당파일들을 만드시면 됩니다.

> cd /opt/apache2/conf
> vi mod_jk2.conf
#####################################################
<IfModule mod_jk2.c>
    #-----------------------------------------------
    # Where to find the workers2.properties file
    #-----------------------------------------------
    #
    JkSet config.file /opt/apache2/conf/workers2.properties
</IfModule>
#####################################################

아래의 worker2.properties 는 172.16.1.79 와 172.16.1.70 이라는
물리적으로 다른 2개의 머신을 LoadBalancing및 FailOver기능을 
하도록 하는 설정입니다. 
참고로 Tomcat은 위 두개의 IP에 대해서 8009 Port에 뜨도록 설정하고 있고
79번의 8009에 떠있는 Tomcat에 대해서는 TomcatID를 tc01로
70번의 8009에 떠있는 Tomcat에 대해서는 TomcatID를 tc02로
각각 명시하고 있습니다.
나중에 79번과 70번에 설치된 Tomcat의 server.xml에 이와 Mapping
되도록 포트는 8009, tomcatID는 tc01, tc02등으로 정확하게 
설정해야 합니다.

> vi workers2.properties
#####################################################
[shm]
info=Scoreboard. Requried for reconfiguration and status with multiprocess servers.
file=anonymous

# Defines a load balancer named lb. Use even if you only have one machine.
[lb:lb]
noErrorHeader=1
stickySession=1
recovery=60

# Example socket channel, override port and host.
[channel.socket:172.16.1.79:8009]
port=8009
host=172.16.1.79
graceful=0
tomcatId=tc01
group=lb

[channel.socket:172.16.1.70:8009]
port=8009
host=172.16.1.70
graceful=0
tomcatId=tc02
group=lb

# define the worker
[ajp13:172.16.1.79:8009]
tomcatId=tc01
max_connections=120
channel=channel.socket:172.16.1.79:8009
group=lb

[ajp13:172.16.1.70:8009]
tomcatId=tc02
max_connections=120
channel=channel.socket:172.16.1.70:8009
group=lb

# Map the Tomcat examples webapp to the Web server uri space
[uri:/*.jsp]
group=lb

[uri:/servlet/*]
group=lb

[status:]
info=Status worker, displays runtime information

[uri:/jkstatus/*]
info=The Tomcat /jkstatus handler
group=status:
#####################################################
> vi httpd.conf
#####################################################
DocumentRoot "/export/home/na/SVC"
LoadModule jk2_module libexec/mod_jk2.so
Group nobody
KeepAlive Off
#####################################################

아래의 설정은 workers2.properties 에 명시한 내용과 
일부 Mapping시켜야 합니다.
Mapping시킬 곳은 Connector port="8009" 라고 적은 부분과
Engine 부분의 jvmRoute="tc01" 라고 적은 부분입니다.
79번 tomcat의 server.xml에는 port:8009, jvmRoute="tc01"로
70번 tomcat의 server.xml에는 port:8009, jvmRoute="tc02"로
각각 설정하면 됩니다.
그리고 Cluster 부분을 아래와 같이 설정해 줘야 Session Clustering 이
가능해 지게 됩니다. 그러니 Session Clustering을 설정하는 곳은
바로 이곳이 되겠네요.
마지막으로 Connection Pool을 설정하기 위해서 아래와 같이 Context 하위에
Resource를 정의합니다. Connection Pool은 Commons의 DBCP를 사용합니다.

172.16.1.79> vi /opt/tomcat5/conf/server.xml

#####################################################

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

  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>

  <GlobalNamingResources>

    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>

    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
       description="User database that can be updated and saved"
           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml" />

  </GlobalNamingResources>

  <Service name="Catalina">

    <Connector port="8009"
               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />

    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tc01">

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

      <Host name="localhost" appBase="webapps"
       unpackWARs="true" autoDeploy="true"
       xmlValidation="false" xmlNamespaceAware="false">

        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
                 expireSessionsOnShutdown="false"
                 useDirtyFlag="true"
                 notifyListenersOnReplication="true">

            <Membership
                className="org.apache.catalina.cluster.mcast.McastService"
                mcastAddr="228.0.0.4"
                mcastPort="45564"
                mcastFrequency="500"
                mcastDropTime="3000"/>

            <Receiver
                className="org.apache.catalina.cluster.tcp.ReplicationListener"
                tcpListenAddress="172.16.1.79"
                tcpListenPort="4001"
                tcpSelectorTimeout="100"
                tcpThreadCount="6"/>

            <Sender
                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
                replicationMode="pooled"
                ackTimeout="15000"/>

            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>

            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
                      tempDir="/tmp/war-temp/"
                      deployDir="/tmp/war-deploy/"
                      watchDir="/tmp/war-listen/"
                      watchEnabled="false"/>
        </Cluster>

        <Context docBase="/export/home/na/SVC" path="/"
         privileged="true" antiResourceLocking="false" antiJARLocking="false">
                    <Resource name="jdbc/Oracle" auth="Container"
                              type="javax.sql.DataSource"
                              driverClassName="oracle.jdbc.driver.OracleDriver"
                              url="jdbc:oracle:thin:@172.16.1.30:1521:happydb2"
                              defaultAutoCommit="false"
                              username="user"
                              password="password"
                              maxActive="50"
                              maxIdle="10"
                              maxWait="-1"
                              removeAbandoned="true"
                              removeAbandonedTimeout="60"
                              logAbandoned="true"
                              initialSize="50"
                              />
                </Context>

      </Host>
    </Engine>

  </Service>

</Server>

#####################################################

172.16.1.70> vi /opt/tomcat5/conf/server.xml

#####################################################

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

  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>

  <GlobalNamingResources>

    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>

    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
       description="User database that can be updated and saved"
           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml" />

  </GlobalNamingResources>

  <Service name="Catalina">

    <Connector port="8009"
               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />

    <Engine name="Catalina" defaultHost="localhost" jvmRoute="tc01">

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>

      <Host name="localhost" appBase="webapps"
       unpackWARs="true" autoDeploy="true"
       xmlValidation="false" xmlNamespaceAware="false">

        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
                 expireSessionsOnShutdown="false"
                 useDirtyFlag="true"
                 notifyListenersOnReplication="true">

            <Membership
                className="org.apache.catalina.cluster.mcast.McastService"
                mcastAddr="228.0.0.4"
                mcastPort="45564"
                mcastFrequency="500"
                mcastDropTime="3000"/>

            <Receiver
                className="org.apache.catalina.cluster.tcp.ReplicationListener"
                tcpListenAddress="172.16.1.70"
                tcpListenPort="4001"
                tcpSelectorTimeout="100"
                tcpThreadCount="6"/>

            <Sender
                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
                replicationMode="pooled"
                ackTimeout="15000"/>

            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>

            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
                      tempDir="/tmp/war-temp/"
                      deployDir="/tmp/war-deploy/"
                      watchDir="/tmp/war-listen/"
                      watchEnabled="false"/>
        </Cluster>

        <Context docBase="/export/home/na/SVC" path="/"
         privileged="true" antiResourceLocking="false" antiJARLocking="false">
                    <Resource name="jdbc/Oracle" auth="Container"
                              type="javax.sql.DataSource"
                              driverClassName="oracle.jdbc.driver.OracleDriver"
                              url="jdbc:oracle:thin:@172.16.1.30:1521:happydb2"
                              defaultAutoCommit="false"
                              username="user"
                              password="password"
                              maxActive="50"
                              maxIdle="10"
                              maxWait="-1"
                              removeAbandoned="true"
                              removeAbandonedTimeout="60"
                              logAbandoned="true"
                              initialSize="50"
                              />
                </Context>

      </Host>
    </Engine>

  </Service>

</Server>

#####################################################

이제 어느정도 정리가 된거 같습니다.
위와같이 따라하셨다면 이제 tomcat과 apache를 다시 시작하면 되겠군요

마지막으로 DBCP에 대해서 한가지 말씀드리겠습니다.
server.xml의 DBCP 설정부분에 initialSize="50"이라고 설정한 
부분이 있습니다. 이렇게 설정하였다고 해서 Tocmat이 기동할 때
자동으로 Connection 50개를 생성하지는 않더군요. 
그렇다면 Connection 50개를 최초 생성하는 시점은 언제일까요?
테스트해 본 결과 DB와 최초 커낵션이 일어나는 시점입니다.
그래서 저는 ServletContextListener를 만들어 contextInitialized() 메소드내에 
Connection을 가져온 후 바로 Connection을 close()하도록 했습니다. 
이렇게 만들면 Tomcat이 올라가는 시점에 Connection 50개가 자동으로 생성됩니다.

테스트가 잘 된 분이나 궁금하신 점이 있으신 분은 리플달아주세요.
그리고 문서가 잘 작성되었는지도 궁금합니다. 
리플달아 주시면 고맙겠습니다.

신관영:rednics@nate.com

+ Recent posts