관리 메뉴

I LOVE EJ

Tomcat - A Minimalistic User's Guide 본문

Os & Server/Tomcat

Tomcat - A Minimalistic User's Guide

BeOne 2007. 10. 15. 16:46
Tomcat 3.2

Tomcat - A Minimalistic User's Guide

이 문서는 Tomcat에 대해서 몇가지 기초적인 정보를 제공하고 있다. 여기서 다루는 몇가지 주제에 대한 것이 다음에 있다.
  1. 바이너리 버전에 대한 인스톨
  2. Tomcat 에서 사용되는 스크립트와 관련된 주요한 성질들
  3. Tomcat의 주요한 설정 파일인 server.xml에 관련된 주요한 성질
  4. 원래 웹서버와 같이 운영하는 Tomcat을 설정하는 방법에 대한 설명
  5. 실제 웹사이트에서 Tomcat을 설정하는 방법에 대한 설명

Getting Started

Tomcat JSP 환경을 포함하고 있는 Servlet 컨테이너이다. Servlet 컨테이너는 사용자 입장에서 Servlet을 유지하고 호출하는 실행시 쉡이다.
Tomcat Servlet 컨테이너를 다음과 같이 나눠볼 수 있다.
  1. Stand-alone servlet containers
    이것은 내장된 웹서버의 기능을 사용하는 것이다. 이 기능은 예를 들어 JavaWebServer의 부분인 Serlvet 컨테이너와 같이 Java 근간 웹 서버를 사용하는 것과 같은 경우이다. Stand-alone 기능은 Tomcat의 기본 모드이다.
    그러나, 대부분의 웹서버는 다음의 두가지 컨테이너 형태와 같이 Java 근간이 아니다.
  2. In-process servlet containers
    Servlet 컨테이너는 웹서버 플러그인과 Java 컨테이너 구현으로 구성된다. 웹서버 플러그인은 웹서버의 주소 공간 내에 JVM을 열고 그 안에서 Java 컨테이너가 실행되도록 한다. 만일 요청이 Servlet을 실행하고자 한다면, 플러그인이 요청을 담당하고 (JNI를 사용해서) Java 컨테이너에게 넘겨준다. In-process 컨테이너는 다중 스레드의 단일 프로세스 서버에 적당하고 퍼포먼스도 좋지만 확장성에 한계가 있다.
  3. Out-of-process servlet containers
    Servlet 컨테이너는 웹 서버 플러그인과 웹 서버의 외부의 JVM에서 실행하는 Java 컨테이너 구현으로 구성되어 있다. 웹 서버 플러그인과 Java 컨테이너 JVM은 몇몇 IPC 체계(보통은 TCP/IP 소켓)를 사용해서 통신을 한다. 만일 요청이 Servlet을 실행하도록 한다면 플러그인이 그 요청을 담당해서 (IPC를 사용해서) Java 컨테이너에게 넘긴다. Out-of-process 엔진의 반응 시간은 in-process 만큼 좋지는 않지만 out-of-process 엔진은 많은 알맞은 방법 (확장성, 안정성 등) 으로 더 좋게 실행한다.
Tomcat stand-alone 컨테이너 (주로 개발이나 디버그 용으로) 나 기존에 있는 웹 서버(현재 아파치와 IIS, Netscape 서버를 지원한다.)에 애드온을 사용할 수 있다. 이것은 Tomcat을 사용할 때마다 어떻게 사용할지를 선택해야 하며 만일 두번째나 세번째 옵션을 선택할 경우에 웹 서버 아답터를 설치할 필요가 있다는 것을 의미한다.

Tomcat Jserv 사이의 차이점은 무엇인가? Tomcat Jserv 아닌가?

이것은 흔히 혼동하는 것이다. Jserv는 아파치와 같이 사용되기 위해 만들어진 Servlet API 2.0을 컴파일하는 컨테이너이다. Tomcat은 완전히 재작성을 한 것이고 Servlet API 2.2 JSP 1.1을 컴파일하는 컨테이너이다.
Tomcat Jserv의 몇몇 작성된 코드 특히, Jserv의 아파치 서버 아답터를 사용했지만, 이것만 공통된 것이다.

어떻게 Tomcat 바이너리 버전을 설치할 것인가?

매우 간단하다. 다음과 같이 하면 된다.
  • http://jakarta.apache.org/downloads/binindex.html에서 zip이나 tar.gz 파일을 다운로드 받는다.
  • 다운로드를 받은 같은 디렉토리에 파일을 압축을 푼다. “tomcat”이라는 새로운 하위 디렉토리를 생성한다.
  • “tomcat” 으로 디렉토리를 변경하고 Tomcat 구조의 루트 디렉토리를 가리키는 새로운 환경 변수(TOMCAT_HOME)를 설정하라.
    1. Win32에서는 다음과 같이 설정한다.
      "set TOMCAT_HOME=footomcat"
    2. Unix에서는 다음과 같이 설정한다.
      bash/sh에서는 "TOMCAT_HOME=foo/tomcat ; export TOMCAT_HOME"
      tcsh
      에서는 "setenv TOMCAT_HOME foo/tomcat"
  • JDK 구조의 루트 디렉토리를 가리키는 환경변수 JAVA_HOME을 설정하고 PATH 환경 변수에 Java 인터프리터(java)를 추가하라.
이상이다. Tomcat을 실행하면 stand-alone(타입 1) servlet 컨테이너를 실행할 수 있을 것이다.

Tomcat 시작하고 멈추기

Bin 디렉토리에 있는 스크립트를 사용해서 Tomcat을 시작하고 멈추면 된다.
Tomcat을 시작하기 위해서 다음과 같이 실행하면 된다.
Unix : bin/startup.sh
Win32: binstartup
Tomcat을 멈추기 위해서 다음과 같이 실행한다.
UNIX: bin/shutdown.sh
Win32: binshutdown

Tomcat 디렉토리 구조

압축이 풀린 Tomcat 바이너리 배포 버전을 확인하면 다음과 같은 디렉토리 구조를 확인할 수 있을 것이다.
디렉토리
   

bin

startup/shutdown... 스크립트를 포함한다.
conf
Tomcat에서 설치된 다양한 웹 어플리케이션에 대해서 기본적인 값을 설정하는 server.xml(Tomcat의 주요한 설정 파일) web.xml을 포함하는 다양한 설정 파일을 포함한다.
doc
Tomcat에 관한 여러가지 문서를 포함한다.
lib
Tomat에서 사용되는 여러가지 jar 파일을 포함한다. Unix에서는 이 디렉토리에 있는 파일이 Tomcat classpath에 추가된다.
logs
Tomcat log 파일이 위치한 곳이다.
src
Servlet API 소스파일이 위치한 곳. 그러나 Servlet 컨테이너에 의해 구현되어야만 하는 인터페이스와 추상 클래스만 포함되어 있다.
webapps
예제 웹 어플리스케이션이 포함되는 곳이다.
추가적으로 다음과 같은 디렉토리를 생성할 수 있다.
work
Tomcat에 의해 자동으로 생성이 되는데, 동작되는 동안 중간 파일(컴파일된 JSP 파일과 같은)이 위치하는 곳이다. 만일 이 디렉토리를 삭제한다면 Tomcat이 작동되는 동안에 JSP 페이지를 실행할 수 없을 것이다.
classes
classpath에 추가 클래스들을 추가하는 디렉토리를 이곳에 만들 수 있다. 이 디렉토리에 추가하는 클래스는 Tomcat classpath에 위치한 곳을 찾게 된다.

Tomcat Scripts

Tomcat Java 프로그램이고 따라서 몇가지 환경변수를 설정하고 나서 명령행에서 실행할 수 있을 것이다. 그러나, 각각의 환경 변수를 설정하는 것과 다음에 오는 Tomcat에서 사용되는 명령행 인자는 에러가 발생하고 쉽고 단순한 것이다. 대신에 Tomcat 개발팀은 Tomcat을 쉽게 시작하고 멈추게 하는 몇가지 스크립트를 제공하고 있다.
주의 : 스크립트는 start/stop를 하기 위한 편리한 방법일 뿐이다. 정확한 명령행이 Tomat에 대해서 발생되는 한 CLASSPATH PATH LD_LIBRARY_PATH와 같은 환경 변수를 맞추어서 변경할 수 있다.
이러한 스크립트는 어떤 것인가? 다음 표는 일반 사용자에게 가장 중요한 스크립트를 보여주고 있다.
스크립트 명
   
tomcat
중요한 스크립트. CLASSPATH TOMCAT_HOME, JAVA_HOME을 포함하는 적절한 환경을 설정하고 명령행 인자와 같이 Tomcat을 시작한다.
startup
뒷단에서 tomcat을 시작한다. “tomcat start”에 대한 간편한 명령어.
shutdown
tomcat을 멈춘다. “tomcat stop”에 대한 간편한 명령어.
사용자에게 가장 중요한 스크립트는 tomcat(tomcat.sh/tomcat.bat)이다. 다른 Tomcat과 관련된 스크립트들은 tomcat 스크립트로 지향하는 엔트리 접점으로 단순한 단일 업무로써 서비스를 하는 것이다.(다른 명령행 인자 등을 설정한다)
tomcat.sh/tomcat.bat를 조금도 자세히 보면 다음과 같은 일을 수행하는 것을 볼 수 있다.
운영 체제
   
Unix
  • TOMCAT_HOME이 지정되지 않았으면 지정한다.
  • JAVA_HOME이 지정되지 않았으면 지정한다.
  • 다음의 내용으로 CLASSPATH를 설정한다.
    1. (사용할 경우) ${TOMCAT_HOME}/classes 디렉토리
    2. ${TOMCAT_HOME}/lib의 모든 내용
    3. ${JAVA_HOME}/lib/tools.jar ( jar 파일은 javac 도구를 포함하고 있는데, jsp 파일에서 javac가 필요하다)
  • startup 클래스로 org.apache.tomcat.startup.Tomcat와 같이 tomcat.home이 호출되면서 java 시스템 환경을 설정하는 명령행 인자와 같이 java를 실행한다. 명령행 인자를 다음과 같은 것들을 org.apache.tomcat.startup.Tomcat 로 보내준다.
    1. start/stop/run/etc 를 수행하는 작업
    2. Tomcat  프로세스에서 사용되는 server.xml의 경로
예를 들어서 server.xml/etc/server_1.xml 에 있고 사용자가 뒷단에서 Tomcat을 시작하기 원한다면 다음과 같은 명령행이 제공되어야 한다.
bin/tomcat.sh start -f /etc/server_1.xml
Win32
  • 현재 TOMCAT_HOME CLASSPATH 설정을 저장한다.
  • JAVA_HOME이 설정되어 있는지 점검한다.
  • TOMCAT_HOME이 설정되어 있는지 점검하고 만일 설정되어 있지 않다면 기본적으로 현재 디렉토리인 “.”로 설정한다. 그 다음에 TOMCAT_HOME TOMCAT_HOME이 유효한지를 확인하기 위해서 servlet.jar 파일이 있는지 점검한다.
  • CLASSPATH 설정은 다음과 같다.
    1. (실제 존재하지 않더라도) %TOMCAT_HOME%classes
    2. %TOMCAT_HOME%lib jar 파일. 가능하다면 %TOMCAT_HOME%lib의 모든 jar 파일들을 동적으로 포함시킨다. 만일 가능하지 않다면 다음의 jar 파일들은 정적으로 포함된다 : ant.jar, jasper.jar, jaxp.jar, parser.jar, servlet.jar, webserver.jar
    3. (존재한다면) %JAVA_HOME%libtools.jar, if it exists ( jar 파일은 javac 도구를 포함하고 있는데, jsp 파일에서 javac가 필요하다)
  • startup 클래스로 org.apache.tomcat.startup.Tomcat와 같이 tomcat.home이 호출되면서 java 시스템 환경을 설정하는 명령행 인자와 같이 %JAVA_HOME%binjava를 실행한다. 명령행 인자를 다음과 같은 것들을 org.apache.tomcat.startup.Tomcat 로 보내준다.
    1. startstoprunetc 를 수행하는 작업
    2. Tomcat  프로세스에서 사용되는 server.xml의 경로
예를 들어서 server.xml confserver_1.xml 에 있고 사용자가 새로운 창에서 Tomcat을 시작하기 원한다면 다음과 같은 명령행이 제공되어야 한다.
bintomcat.bat start -f confserver_1.xml
  • 이전에 저장된 TOMCAT_HOME CLASSPATH 설정을 다시 저장한다.
보는 바와 같이 tomcat.bat Win32 버전은 Unix 것 만큼 강력하지 않다. 특히, JAVA_HOME의 세팅을 고려하지 않고 TOMCAT_HOME을 현재 디렉토리인 “.”로 설정한다. CLASSPATH를 동적으로 만들 수는 있지만, 모든 경우가 그런 것은 아니다. 만일 TOMCAT_HOME이 스페이스를 포함하거나 Win9x에서는 TOMCAT_HOME 8.3 디렉토리명이 아닌 것을 포함하면 CLASSPATH를 동적으로 만들 수 없다.

Tomcat 설정 파일

Tomcat의 설정은 다음 두가지 파일에 기초한다.
  1. server.xml – Tomcat의 전역 설정 파일
  2. web.xml – Tomcat에서 다양한 context를 설정
이 장에서는 위의 파일을 어떻게 사용하는지를 다룰 것이다. web.xml의 내부 내용에 대해서는 다루지 않을 것이다. 이 내부 내용은 Servlet API 스펙에 더 자세하게 다뤄졌다. 대신에 server.xml의 내용을 다루고 Tomcat context에서 web.xml의 사용법에 대해서 소개된다.

server.xml

server.xml Tomcat의 중요한 설정 파일이다. 다음의 두가지 목적을 제공한다.
  1. Tomcat 콤포넌트에 대한 초기 설정을 제공
  2. Tomcat에 대한 구조를 지정하는데, 이것은 server.xml에서 지정된 콤포넌트를 초기화함으로써 Tomcat을 부팅하고 구성한다는 것을 의미한다.
server.xml 에서 중요한 요소는 다음의 테이블에 나와있다.
요소
설명
Server
serverl.xml 파일에서 가장 처음에 있는 요소. Server 요소는 단일 Tomcat 서버를 정의한다. 일반적으로 너무 많이 지정해서는 안된다. Server 요소는 Logger ContextManager 요소를 포함할 수 있다.
Logger
이 요소는 logger 객체를 정의한다. 각각의 logger는 지정하는 이름을 갖고 있고, 그 뿐만 아니라 logger의 결과와 (log level을 지정하는)verbosityLevel을 포함하는 log 파일의 경로까지도 포함한다. 현재 servlet(ServletContext.log()가 위치하는 곳), JSP 파일과 tomcat 실행시에 대한 logger가 있다.
ContextManager
ContextManager ContextInterceptor, RequestInterceptor, Context Connector에 대한 설정과 구조를 지정한다. ContextManager는 다음의 성질을 제공하는 몇가지 속성이 있다.
  1. debug 메시지를 로그에 남기기 위해 사용되는 Debug 레벨
  2. webapps/, conf/, logs/, 모든 정의된 context에 대한 기본 위치 TOMCAT_HOME보다는 다른 디렉토리로부터 Tomcat을 시작하는데 사용된다.
  3. working 디렉토리의 이름
  4. stack trace와 다른 debug 정보가 기본 응답에 포함시킬 것인지에 대한 플래그
ContextInterceptor & RequestInterceptor
interceptor들은 ContextManager에서 발생한 어떤 이벤트에 대해서 청취한다. 예를 들어서, ContextInterceptor Tomcat의 시작과 종료 이벤트에 대해서 청취하고, RequestInterceptor는 사용자 요청이 서비스받는 동안 넘겨줄 필요가 있는 여러가지 상황을 주시한다. Tomcat 관리자는 interceptor에 대해 많은 것을 알 필요가 없고 반면에 개발자는 이것이 어떻게 동작에서의 “global” 타입이 Tomcat에서 구현될 수 있는지를 알아야만 한다. (예를 들어, 보안이나 요청당 logging과 같은)
Connector
Connector는 웹 서버나 직접적인 사용자의 브라우저(stand-alone 설정에서)를 통해서 사용자와의 연결을 나타낸다. Connector 객체는 Tomcat worker 스레드의 운영과 다양한 클라이언트와의 socket 연결에 대한 요청/응답을 읽고/쓰는 것에 대해서 담당을 하는 한가지이다. Connector에 대한 설정은 다음과 같은 정보를 포함한다.
  1. handler 클래스
  2. handler가 청취하는 TCP/IP port
  3. handler 서버 소켓에 대한 TCP/IP backlog
다음 문서에서 Connector 설정을 어떻게 하는지 설명할 것이다.
Context
각각의 Context web 어플리케이션이 위치한 곳의 Tomcat 구조에서 경로를 나타낸다. Tomcat Context는 다음의 설정을 포함한다.
  1. context가 위치한 경로. 이것은 ContextManager home에 대한 전체 또는 상대 경로가 될 수 있다.
  2. debug 메시지를 로그남기는 데에 debug 수준
  3. reloadable 플래스. Servlet을 개발할 때에 Tomcat을 리로드할지 변경하는 것은 매우 편리하다. 이것은 bug를 수정할 수 있고, shutdown과 재시작을 할 필요없이 새로운 코드로 Tomcat을 테스트할 수 있다. Servlet reloading을 하기 위해서는 reloadable 플래그를 true로 설정하면 된다. 그러나 이러한 변화는 시간이 걸리는 것을 인지하고, 게다가 새로운 servlet이 새로운 class-loader 객체에 로딩되기 때문에 이러한 class-reloading 트리거가 에러를 발생하는 경우가 있다. 이러한 문제를 회피하기 위해서 reloadable 플래그를 false를 설정하면 된다. 이것은 자동 리로드 설정을 막는 것이다.

추가적인 정보는 server.xml 파일에서 볼 수 있다.

다른 디렉토리에서 Tomcat 실행하기

기본적으로 tomcat은 설정파일로 TOMCAT_HOME/conf/server.xml을 사용한다. 기본 설정은 context에 대한 근간으로 TOMCAT_HOME을 사용한다.
"-f /path/to/server.xml" 옵션으로 다른 서버 설정 파일과 context manager home 등록정보를 설정함으로써 이러한 설정을 바꿀 수 있다. home에 있는 다음과 같은 필요한 파일을 설정할 필요가 있다.
  • webapps/ 디렉토리 (생성했다면) – 확장된 모든 war 파일들과 context로 추가된 모든 하위 디렉토리
  • conf/ 디렉토리 - tomcat-users.xml 과 다른 설정 파일을 저장할 수 있다.
  • logs/ - 모든 로그들을 TOMCAT_HOME/logs/ 디렉토리 대신에 이 디렉토리에 넣을 수 있다.
  • work/ - context에 대한 work 디렉토리
만일 server.xml에 있는 ContextManager.home 등록정보가 상대적이면, 현재 working 디렉토리에 대해 상대적이다.

web.xml

web.xml web 어플리케이션 구조(디렉토리 구조와 설정 포함)에 대한 상세한 설명은 Servlet API Spec 9, 10, 14 장에 있기 때문에 여기에서는 설명하지 않을 것이다.
그러나 web.xml과 관련되어서 Tomcat과 관련된 특징에 대해서는 설명할 것이다. Tomcat은 사용자로 하여금 conf 디렉토리에 있는 기본 web.xml을 둠으로써 모든 context에 대한 기본 web.xml 값을 정의하게 한다. 새로운 Context를 만들 때에 Tomcat은 기본 설정으로 기본 web.xml과 이 기본 파일을 단지 overwrite하는 어플리케이션이 지정한 web.xml(어플리케이션의 WEB-INF/web.xml 파일)을 사용한다.

Apache 서버와 같이 Tomcat 사용하게끔 설정하기

지금까지 Tomcat을 에드 온 서버로 설명하지 않았고 대신에 stand-alone 컨테이너로 설명하고 어떻게 사용하는가를 이야기했다. 그러나 다음과 같은 몇가지 문제가 있다.
  1. Tomcat은 정적 페이지를 다룰 때에 Apache 만큼 빠르지 않다.
  2. Tomcat Apache 만큼 설정에 강력하지 않다.
  3. Tomcat Apache 만큼 강력하지 않다.
  4. 어떤 웹서버에서는 긴 시간 개발한 많은 사이트들이 있다. 예를 들어 CGI 스크립트/Server API 모듈/perl/php …. 이러한 모든 것들이 이런 기존 시스템을 없앨 것인지 가정할 수 없다.
이러한 모든 이유로 실 세계 사이트에서는 사이트의 정적 내용을 서비스하기 위해서 Apache와 같은 웹 서버를 사용하고, Servlet/JSP 애드 온으로 Tomcat을 사용하기를 추천한다.
다른 설정에 대해서 자세하게 다루지는 않고, 대신에 다음과 같은 것을 이야기할 것이다.
  1. 웹 서버의 기본적인 행위
  2. 어떤 설정이 필요한가.
  3. Apache에 대해서 이러한 것을 설명한다.

서버 동작

간단하게 말해서 웹 서버는 클라이언트의 HTTP 요청을 기다리고 있는 것이다. 이러한 요청들이 서버에 도달할 때에 필요한 내용을 제공함으로써 무엇이든지 요청에 대해서 서비스할 필요가 있다. Servlet 컨테이너를 추가하는 것은 다소 이러한 행위를 변하게 하는 것일 수도 있다. 웹 서버는 또한 다음과 같은 역할을 수행할 필요가 있다.
  • Servlet 컨테이너 라이브러리를 로딩하고 초기화한다. (요청을 서비스하기 전에)
  • 요청이 도달하면 어떤 요청이 servlet에 속하고, 그럴 경우 adapter가 요청을 담당하고 다루게끔 점검할 필요가 있다.
반면에 adapter는 일반적으로 요청 URL에서 어떤 페턴에 근거하고 이러한 요청을 직접적으로 어디에서 서비스를 할 요청이 무엇인지 알 필요가 있다.
사용자가 가상 호스트를 사용하는 설정을 사용하기 원하거나 같은 웹서버에서 서로 다른 servlet 컨테이너 JVM을 서비스하는 데에서 개발자들이 작업하기를 원할 때에는 일이 좀 더 복잡해진다. 이러한 두가지 경우에 대해서는 고급을 다루는 장에서 설명할 것이다.

필요한 설정은 무엇인가.

생각할 수 있는 가장 명확한 설정은 serlvet 컨테이너의 담당 하에 있는 servlet URL의 설정이다. 이것은 명확하다. Serlvet 컨테이너에게 전달하는 것인 어떠한 요청인지를 알아야 한다. 그러나 web-server/servlet-container 복합 구성에게 제공해야만 하는 다음과 같은 추가적인 설정 항목이 있다.
  • 사용 중인 Tomcat 프로세스와 어떤 TCP/IP 호스트/포트에서 청취되고 있는지에 대한 설정을 제공할 필요가 있다.
  • adapter 라이브러리의 위치를 웹 서버에게 알려줄 필요가 있다. (그래서 시작시에 로딩할 수 있게끔)
  • log를 어디에 얼마만큼 남길 것인지 등과 같은 adapter 내부 정보에 대해서 설정할 필요가 있다.
이러한 모든 정보는 웹 서버 설정이나 adapter에서 사용되는 개인 설정 파일에 나타나야만 한다. 다음 장은 Apache에서 어떻게 설정이 구현되는지를 설명하고 있다.

Apache에서 설정하기

장은 Tomcat 같이 사용하기 위해서 Apache 어떻게 설정할지를 보여주고 있고, 여러분들이 사용해만하는 설정 지시문에 대한 식견 뿐만 아니라 설명도 제공하고자 한다. jserv install page 에서 추가적인 정보를 찾아볼 있다.
Tomcat 시작할 때에 자동으로 Apache 대한 설정 파일을 TOMCAT_HOME/conf/tomcat-apache.conf 에 생성하게 된다. 대부분의 경우에 어떤 조치를 할 필요는 없지만 이 파일을 ("Include TOMCAT_HOME/conf/tomcat-apache.conf"를 추가함으로써) httpd.conf에 포함해야 한다. 만일 AJP port에 대해서 8007이외의 다른 포트를 설정하는 것과 같은 특별한 필요가 있을 경우에, 이 파일을 기본 설정 파일로 사용할 수도 있고 다른 파일에 그 결과를 저장해서 사용할 수도 있다. 만일 Apache 설정을 다른 파일에서 사용할 경우에는 새로운 context를 추가할 때마다 그 파일을 업데이트할 필요가 있다.
Tomcat: 새로운 context를 추가하고 나서 tomcat apache를 재 시작해야하고 apache는 재시작없이 설정 변경에 대한 지원을 하지 않는다. 또한  TOMCAT_HOME/conf/tomcat-apache.conf 파일은 tomcat이 시작하면 생성이 되어서 Apache이전에 Tomcat을 시작할 필요가 있다. Tomcat은 시작할 때마다  TOMCAT_HOME/conf/tomcat-apache.conf overwrite하고, 변경된 설정 파일은 어느 곳에서든지 유지되어야만 한다.
Apache-Tomcat 설정은 Jserv 유일 지시자 뿐만 아니라 Apache 핵심 설정 지시자를 사용해서 처음에 혼동할 수도 있지만, 단순화 시키는 다음과 같은 두가지 것이 있다.
  • 일반적으로 모든 Jserv 유일 지시자가 “ApJServ” 접두어로 시작하는 것을 주시함으로써 두 지시자 집합사이에서 구별할 수 있다.
  • 설정과 관련된 전체 Tomcat tomcat.conf라고 하는 단일 설정 파일에 집중되어 있거나 자동으로 생성된 tomcat-apache.conf에 있기 때문에 한가지 파일에서만 살펴보면 된다.
다음 예제 파일인 tomcat.conf 파일을 살펴보자.
단순한 Apache-Tomcat 설정
    
###########################################################
#      A minimalistic Apache-Tomcat Configuration File    #
###########################################################
 
# 주의 : 이 파일은 httpd.conf 에 추가되거나 포함되어야 한다.
 
# (1) Tomcat apache 어댑터로 서비스하는 jserv 모듈을 로딩하기
LoadModule jserv_module libexec/mod_jserv.so
 
# (1a) 설정에 종속된 모듈
<IfModule mod_jserv.c>
 
# (2) Apache Tomcat을 실행하지 않게끔 한다.
ApJServManual on
# (2a) 보안 통신을 사용하지 않는다.
ApJServSecretKey DISABLED
# (2b) 가상 호스트가 사용될 경우, 기본 서버로부터 mount 지점을 복사한다.
ApJServMountCopy on
# (2c) jserv 모듈에 대한 Log 수준
ApJServLogLevel notice
 
# (3) 기본 통신 프로토콜로 ajpv12로 사용한다.
ApJServDefaultProtocol ajpv12
# (3a) Tomcat connector에 대한 기본 위치
# 같은 서버에 위치하고 8007 포트 사용
ApJServDefaultHost localhost
ApJServDefaultPort 8007
 
# (4)
ApJServMount /examples /root
# 전체 URL mount
# ApJServMount /examples ajpv12://hostname:port/root
</IfModule>
            
보는 바와 같이 설정은 다음과 같은 4 단계로 나눠진다.
  1. 이 단계에서 Apache에게 jserv 공유 객(NT 에서는 dll)체를 로딩하도록 지시한다. 이것은  잘 알려진 Apache 지시자이다. 만일 로딩이 잘되고 모듈이 mod_jserv.c(1a)라는 파일에서 가지고 올 경우에 Jserv-Tomcat 설정의 나머지 부분으로 시작할 수 있다.
  2. 이 단계는 다음의 인자인 다양한 Jserv 내부 인자를 설정한다.
    • jserv Tomcat 프로세스를 시작하지 못하도록 지시한다. 자동으로 Tomcat을 시작하는 것은 아직 구현되지 않았다.
    • Apache Tomcat 사이의 보안 키에 대한 요청/응답을 사용 못하게 한다. 보안키 작동 또한 아직 구현되지 않았다.
    • 가상 호스팅의 경우 jserv에게 기본 서버 mount 지점(다음 절 참조)을 복사하도록 지시한다.
    • jserv에게 log 수준을 주시하도록 지시. 다른 log 수준은 emerg, alert, crit, error, warn, info, debug 등을 포함한다.
  3. 이 단계는 기본 통신 인자를 설정한다. 기본적으로 통신에서 사용되는 기본 프로토콜은 ajpv12이고(이와 같이 할 필요는 없다.) Tomcat 프로세스는 같은 머신에서 실행되고 8007 포트에서 서비스된다. 만일 Apache에서 사용되는 머신이 아닌 다른 머신에서 Tomcat을 실행하려고 하면 ApJServDefaultHost를 수정하거나 context mount할 때에(다음 참조) 전체 URL을 사용해야만 한다. 또한, 8007 이외의 다른 포트를 사용하는 Tomcat connector를 설정하고자 한다면, ApJServDefaultPort를 변경하거나 context mount할 때에 전체 URL을 사용해야 한다.
  4. 이 단계는 Tomcat에게 context mount한다. 기본적으로 /examples로 시작되는 모든 웹 서버 경로는 Tomcat에게 넘기는 것을 의미한다. ApJServMount 예제는 간단한 것이다. 사실 ApJServMount는 또한 예를 들어 다음과 같이 사용되는 통신 프로토콜과 Tomcat 프로세스가 청취하는 장소에 대한 정보를 제공할 수 있다.
ApJServMount /examples ajpv12://hostname:port/root
위의 예제는 /example context“hostname”이라는 호스트와 “port” 라는 포트 번호에서 청취되는 호스트에서 실행하는 Tomcat 프로세스로 mount한다.
지금까지 예제 파일에서 서로 다른 설정 지시에 대해서 이해가 될 것인데, 그러면 Apache 설정에 어떻게 추가할 수 있을 것인가? 한가지 단순한방법은 httpd.conf에 그 내용을 적는 것이다. 그러나 이것은 매우 성가신 일이다. 대신에 지시자를 포함하는 Apache를 사용해야 한다. Apache 설정 파일(httpd.conf)의 끝에 다음과 같은 지시자를 포함하면 된다.
include <full path to the Tomcat configuration file>
예를 들어,
include /tome/tomcat/conf/tomcat.conf
이것은 Apache에게 Tomcat 설정을 추가하는 것이다. 이것으로 인해, jserv 모듈을 Apache libexec 디렉토리(Win32의 경우 modules 디렉토리)에 복사하고 Apache를 재시작해야 한다. 이제 Tomcat과 연결될 수 있는 준비가 된 것이다.

Jserv Module (mod_jserv) 구하기

위에서 설명했듯이 Apache에서 Tomcat에게 요청을 재전송하기 위해서 웹 서버 어댑터가 필요하다. Apache에서는 이 어댑터가 mod_jserv라는 다소 수정된 버전이다.
여기를 참조하고 여러분의 OS에 맞는 이미 만들어진 mod_jserv 버전(일반적으로 NT에 대한 것은 한가지이다.)을 구할 수 있다. 그러나, 원래의 소스 library에 대해서는 구할 수는 없다. (많은 OS와 충분하지 못한 개발자, 짧은 유지시간 등의 이유) 게다가, 개발된 Apache나 특정 UNIX 에서 사용되는 방식의 조그만 차이가 동적 연결 에러 결과를 초래할 수도 있다. 여러분 자신에 맞는 mod_jserv를 만들 수도 있어야 한다.(어려워하지 마라. 쉬운 일이다.)
UNIX에서 mod_jserv를 만드는 것은 다음과 같은 것을 포함한다.
  1. 여기에서 Tomcat의 소스 버전을 다운로드 받는다.
  2. 디렉토리에 압축을 푼다.
  3. 모듈을 다음과 같이 만든다.
    • jakarta-tomcat/src/native/apache/jserv/ 로 디렉토리를 이동
    • 다음과 같은 명령어를 실행
apxs -c -o mod_jserv.so *.c
apxs Apache 버전의 부분이고 APACHE_HOME/bin에 위치해 있어야 한다.
Win32에 대한 mod_jserv를 만드는 것은 다소 틀리다. (Win32에 대한 다운로드 받을 수 있는 dll을 이미 가지고 있다.) 그러나 만일 다시 만들기를 원한다면 Visual C++를 인스톨 해야하고 다음과 같이 수행하면 된다.
  1. 여기에서 Tomcat의 소스 버전을 다운로드 받는다.
  2. 디렉토리에 압축을 푼다.
  3. 다음과 같은 모듈을 만든다.
    • jakarta-tomcatsrcnativeapachejserv 로 이동
    • VCVARS32.BAT 스크립트를 실행해서 환경에 Visual C++를 추가
    • Apache 소스 디렉토리로 지정하는 APACHE_SRC라는 환경 변수를 설정. 예를 들어,  SET APACHE_SRC=C:Program FilesApache GroupApachesrc와 같이 지정. make 파일은 APACHE_SRC 디렉토리 내의 “CoreRApacheCore.lib”로 링크된다는 것에 유의. ApacheCore를 만드는 Apache 문서를 참조.
    • 다음과 같은 명령어를 실행
nmake -f Makefile.win32
nmake Visual C++ make 프로그램이다.
이상과 같이 하면, mod_jserv를 만들게 된다.

자신의 Context 정적 파일을 서비스하는 Apache Server 설정하기

이전의 Apache-Tomcat 설정 파일은 다소 비효율적이라서 Apache에게 Tomcat에서 서비스하는 /examples 접두어로 시작하는 리소스에 대한 요청을 보내게끔 지시했었다. 이것이 진정 원하는 것인가?  Servlet context의 부분에 있을지 모르는 정적 파일(예를 들어, 이미지나 정적 HTML 파일과 같은)이 많이 있는데, Tomcat은 이러한 파일을 서비스해야만 하는가?
그렇게 하는 것은 예를 들어, 다음과 같은 이유가 실제로 있어서 일런지 모른다.
  1. 이러한 리소스에 대해서 보안에 근거한 Tomcat을 설정하기 원할 수도 있다.
  2. interceptor를 사용하는 정적 리소스에 대해서 사용자 요청을 따르기를 원할 수도 있다.
그러나 일반적으로 이것은 그러한 경우가 아니다. Tomcat이 정적 파일을 저장하게끔 하는 것은 단지 CPU 낭비이다. 대신에 Apache가 이러한 정적 파일을 서비스하게 하고 Tomcat은 그렇지 않게끔 해야 한다.
Apache가 정적 파일을 서비스하게 하려면 다음과 같은 것이 필요하다.
  1. Apache에게 모든 servlet 요청을 Tomcat에게 전달하도록 지시
  2. Apache에게 모든 JSP 요청을 Tomcat에게 전달하도록 지시
그리고, Apache가 나머지를 다루도록 한다. 정확하게 그러한 것을 하는 다음의 tomcat.conf 예제 파일을 한번 보자.
Apache가 정적 Context를 서비스하는 곳의 Apache-Tomcat 설정
    
################################################
#              Apache-Tomcat Smart Context Redirection               #
################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
 
ApJServDefaultHost localhost
ApJServDefaultPort 8007
 
#
# 단일 context에 대한 mount
#
# (1) Apache에게 context 위치에 대해서 알려준다.
Alias /examples c:/jakarta-tomcat/webapps/examples
# (2) 선택 사항, Apache context 서비스 설정
<Directory "c:/jakarta-tomcat/webapps/examples">
    Options Indexes FollowSymLinks
# (2a) context 루트에 대해서 디렉토리 인덱싱이 없음.
#    Options -Indexes
# (2b) 디렉토리 index 파일에 대해서 index.jsp 파일 설정
#    DirectoryIndex index.jsp
</Directory>
# (3) WEB-INF 디렉토리에 대한 검색 방지
<Location /examples/WEB-INF/>
    AllowOverride None
    deny from all
</Location>
# (4) Apache에게 jserv servlet handler 내에 있는 모든 .jsp 파일을 전송하도록 지시
<LocationMatch /examples/*.jsp>
    SetHandler jserv-servlet
</LocationMatch>
# (5) Tomcat에게 알려진 servlet URL 전송
ApJServMount /examples/servlet /examples
 
# (6) 선택 사항, Tomcat으로의 context에게 servlet 전송
ApJServMount /servlet /ROOT
</IfModule>
      
보는 바와 같이, 이 설정 파일의 시작에는 이전 예제에서 보는 것과 같다. 그러나, 마지막 단계(context mount하기)는 다음에 설명되는 일련의 긴 Apache ApJServ 설정 지시자로 대체된다.
  1. 이 단계는 Apache에게 context 위치를 알려주고 그것을 Apache 가상 디렉토리로 명명하는 것이다. 이러한 방법으로 Apache는 이 디렉토리로부터 파일을 서비스할 수 있다.
  2. 이 선택 단계는 Apache로 하여금 context를 어떻게 서비스할 것인지에 대해서 지시하는 것이다. 예를 들어, Apache가 디렉토리 인덱싱(리스팅)이나 특정 인덱스 파일을 설정하도록 할 수 있다.
  3. 이 단계는 Apache가 클라이언트 접근으로부터 WEB-INF 디렉토리를 보호하게 한다. 보안의 이유로 WEB-INF 디렉토리의 내용을 사용자가 보지 못하게 하는 것은 중요하다. 예를 들어, web.xml은 사용자에게 가치있는 정보를 제공하게 될 것이다. 이 단계는 방문자로 하여금 WEB-INF 내용을 막는 것이다.
  4. 이 단계는 Apache jserv servlet handler를 사용해서 context 내의 모든 jsp 위치를 서비스하게 하는 것이다. servlet handler는 기본 호스트와 포트를 근거로 하는 이러한 요청을 재전송한다.
  5. 이 단계는 Tomcat에게 특정 servlet URL mount 한다. 특정 servlet URL의 숫자 만큼 mount 지시자가 있어야 되는 것에 유의해야 한다.
  6. 이 마지막 단계는 Tomcat으로 sevlet context의 추가에 대한 예제이다.
이러한 설정은 첫번째 예보다 더 복잡하고 에러가 나기 쉽다는 것이 눈에 들어올 것이다. 그렇지만, 향상된 performance에 대한 대가라고 생각하면 될 것이다.

다중 Tomcat JVM 대한 설정

때로 서로 다른 JVM에서 다뤄지는 서로 다른 context를 설정하는게 유용하다. 예를 들어, 다음과 같은 상황에서이다.
  • 각각의 context가 서로 다르게 서비스를 하고 서로 다른 머신에서 특정 업무와 실행을 할 경우
  • 개인적인 Tomcat 프로세스에서 여러 개발자들이 개발을 하고 있지만, 같은 웹서버를 사용할 경우
서로 다른 context가 서로 다른 JVM에서 서비스를 받고 있는 시스템을 구현하는 것은 매우 쉽고 다음은 그러한 설정 파일에 대해서 보여주고 있다.
Context JVM Apache-Tomcat 설정
    
#################################################
#             Apache-Tomcat with JVM per Context                     #
#################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
 
ApJServDefaultHost localhost
ApJServDefaultPort 8007
 
# Mounting the first context.
ApJServMount /joe ajpv12://joe.corp.com:8007/joe
 
# Mounting the second context.
ApJServMount /bill ajpv12://bill.corp.com:8007/bill
</IfModule>
            
이전의 예제에서 보는 바와 같이, 서로 다른 JVM을 사용하는 것(심지어 서로 다른 머신에서 실행이 되더라도)은 전체 ajp URL mount를 사용해서 쉽게 할 수 있다. 이러한 전체 URL에서 실제로 Tomcat 프로세스가 위치한 곳과 그 포트를 지정하게 된다.
두개의 Tomcat 프로세스가 같은 머신에서 실행된다고 하면, 서로 다른 connector 포트로 그 각각을 따로 설정해주어야 한다. 예를 들어, 두개의 JVM localhost에서 실행이 된다고 하면, Apache-Tomcat 설정은 다음과 같이 된다.
같은 머신상의 다중 JVM 실행 Apache-Tomcat 설정
    
#################################################
#      Apache-Tomcat with Same Machine JVM per Context               #
#################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
 
ApJServDefaultHost localhost
ApJServDefaultPort 8007
 
# Mounting the first context.
ApJServMount /joe ajpv12://localhost:8007/joe
 
# Mounting the second context.
ApJServMount /bill ajpv12://localhost:8009/bill
</IfModule>
            
위의 파일은 보면 같은 머신에서 서로 다른 포트로 각각 지적하는 두개의 명확한 ApJServ mount 지점이 있다는 것을 볼 수 있다. 이 설정은 server.xml 파일에 있는 설정으로부터 지원이 필요하다는 것이 명확하다. 서로 다른 Tomcat 프로세스에 대해서 이 파일 안에 서로 다른 <Connector> 설정이 필요할 것이다. 다음의 두 예제에서 보는 바와 같이 서로 다른 <Connector> 태그를 갖는 두 가지 서로 다른 server.xml 파일(여기서는 server_joe.xml server_bill.xml이라고 하자)이 실제로 필요할 것이다.
Joe server.xml 파일
    
<?xml version="1.0" encoding="ISO-8859-1"?>
 
<Server>
    <!-- Debug low-level events in XmlMapper startup -->
    <xmlmapper:debug level="0" />
 
    <!--  @@@
        log 파일이 bill 파일과 구별하기 위해서 _joe로 접미사를 붙였다는 것에 유의하라.
    -->
 
    <Logger name="tc_log" 
            path="logs/tomcat_joe.log"
            customOutput="yes" />
 
    <Logger name="servlet_log" 
            path="logs/servlet_joe.log"
            customOutput="yes" />
 
    <Logger name="JASPER_LOG" 
        path="logs/jasper_joe.log"
            verbosityLevel = "INFORMATION" />
 
    <!--  @@@
        work 디렉토리가 bill work 디렉토리와 구별하기 위해서 _joe로 접미사가 붙었다는 
것에 유의하라.
    -->
    <ContextManager debug="0" workDir="work_joe" >
        <!-- ==================== Interceptors ==================== -->
 
        ...
        
        <!-- ==================== Connectors ==================== -->
 
        ...
 
        <!-- Apache AJP12 지원한다. 이것은 tomcat shutdown할 때에 역시 사용된다.
          -->
        <!-- @@@ 이 연결은 ajp 통신을 위해 포트 번호 8007을 사용하고 있다. -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
       value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter name="port" value="8007"/>
        </Connector>
        
        <!-- ==================== Special webapps ==================== -->
 
        <!-- @@@ the /jow context -->
        <Context path="/joe" docBase="webapps/joe" debug="0" reloadable="true" > 
        </Context>
    </ContextManager>
</Server>       
            
server_joe.xml 파일을 보면 <Connector> 8007 포트로 설정이 되었다는 것을 볼 수 있다. 반면에 server_bill.xml(다음 예제) <Connector> 8009 포트로 설정이 되어 있다.
Bill server.xml 파일
    
<?xml version="1.0" encoding="ISO-8859-1"?>
 
<Server>
    <!-- Debug low-level events in XmlMapper startup -->
    <xmlmapper:debug level="0" />
 
    <!--  @@@
        log 파일이 joe의 파일과 구분하기 위해서 _bill로 접미사가 붙었다는 것에 유의하라.
    -->
 
    <Logger name="tc_log" 
            path="logs/tomcat_bill.log"
            customOutput="yes" />
 
    <Logger name="servlet_log" 
            path="logs/servlet_bill.log"
            customOutput="yes" />
 
    <Logger name="JASPER_LOG" 
        path="logs/jasper_bill.log"
            verbosityLevel = "INFORMATION" />
 
    <!--  @@@
        work 디렉토리가 joe work 디렉토리와 구분하기 위해서 _bill로 접미사가 붙었다는 
것에 유의하라.
    -->
    <ContextManager debug="0" workDir="work_bill" >
 
        <!-- ==================== Interceptors ==================== -->
 
        ...
        
        <!-- ==================== Connectors ==================== -->
 
        ...
 
        <!-- Apache AJP12 지원한다. 이것은 tomcat shutdown할 때에 역시 사용된다.
          -->
        <!-- @@@  connector ajp 통신으로 포트 번호 8009를 사용하고 있다. -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler" 
       value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter name="port" value="8009"/>
        </Connector>
        
        <!-- ==================== Special webapps ==================== -->
    
        <!-- @@@ the /bill context -->
        <Context path="/bill" docBase="webapps/bill" debug="0" reloadable="true" > 
        </Context>
    </ContextManager>
</Server>       
          
포트 설정은 joe bill 설정이 다른 장소가 이니다. xml 파일에서 변경해야만 하는 4가지 장소에 @@@ 마크를 했다. 보는 바와 같이, 이 차이는 두개의 Tomcat 프로세스가 각각 서로 다른 로그와 실행 장소를 overwriting하는 것을 피하게끔 하는데 필요하다.
그 다음에 다음과 같이 – f 명령어 옵션을 사용해서 두개의 tomcat 프로세스를 시작해야 한다.
binstarup -f confserver_joe.xml
binstarup -f confserver_bill.xml
그리고 나서 서로 다른 URL 경로 접두어를 근거로 Apache로부터 접근을 하면 된다.

가상 호스팅 설정

Tomcat 3.2 하에서는 가상 호스트를 지원할 수 있다. 사실 가상 호스트에 대한 설정은 다중 JVM에 대한 설정(이전 절에서 설명)과 매우 흡사하고, 그 이유도 간단하다. Tomcat3.2에서 각각의 가상 호스트는 서로 다른 Tomcat 프로세스에 의해 구현되기 때문이다.
현재 Tomcat(버전 3.2)으로 가상 호스팅에 대한 인식은 웹 서버(Apache/Netscape )에 의해 제공된다. 웹 서버 가상 호스팅 지원은 이 가상 호스트의 context를 포함하는 JVM으로 어떠한 가상 호스트를 포함한 요청을 재전송하는 Tomcat 어댑터에 의해 사용된다. 이것은 만일 두개의 가상 호스트를 가지고 있다면(예를 들어, vhost1 vhost2), 두개의 JVM을 갖게 된다는 것을 의미한다. 하나는 vhost1 context에서 실행되는 것이고, 다른 하나는 vhost2 context에서 실행되는 것이다. JVM들은 서로 다른 존재에 대해서 인식을 못한다. 사실, 가상 호스팅이라는 개념에 대해서 알지 못하는 것이다. 모든 가상 호스팅 로직은 웹 서버 어댑터의 내부에 있다. 내용을 더 명확하게 하기 위해서, 다음의 Apache-Tomcat 설정 파일 예를 보자.
가상 호스트 지원에 대한 Apache-Tomcat 설정
    
###############################################
#        Apache Tomcat Virtual Hosts Sample Configuration            #
################################################
LoadModule jserv_module modules/ApacheModuleJServ.dll
<IfModule mod_jserv.c>
ApJServManual on
ApJServDefaultProtocol ajpv12
ApJServSecretKey DISABLED
ApJServMountCopy on
ApJServLogLevel notice
 
ApJServDefaultHost localhost
ApJServDefaultPort 8007
 
# 1 Creating an Apache virtual host configuration
NameVirtualHost 9.148.16.139
 
# 2 Mounting the first virtual host
<VirtualHost 9.148.16.139>
ServerName www.vhost1.com
ApJServMount /examples ajpv12://localhost:8007/examples
</VirtualHost>
 
# 3 Mounting the second virtual host
<VirtualHost 9.148.16.139>
ServerName www.vhost2.com
ApJServMount /examples ajpv12://localhost:8009/examples
</VirtualHost>
</IfModule>
            
보는 바와 같이, 1, 2, 3 단계는 두개의 Apache 가상 호스트에 대해 정의를 하고 있고 그 각각에 대해서 어떤 ajpv12 URL /examples context mount 하고 있다. 그러한 각각의 ajpv12 URL은 가상 호스트를 담고 있는 JVM에게로 향하고 있다. 두개의 JVM의 설정은 이전의 절에서 설명한 것과 매우 흡사하기 때문에 다시 두개의 서로 다른 server.xml 파일(각각 가상 호스트 프로세스에 대한 것)이 필요하고 –f 명령어 옵션으로 Tomcat 프로세스를 실행할 필요가 있다. 그렇게 하고 난 후에 Apache에 접근을 할 수 있고, 서로 다른 호스트 이름을 호출할 경우에 어댑터는 적절한 JVM에게로 재전송한다.
향상된 가상 호스트 지원에 대한 필요성
각각의 가상 호스트가 서로 다른 JVM에 의해 구현이 되었다는 것은 확장성 문제에 있어서 매우 크다. Tomcat의 차기 버전은 같은 Tomcat JVM 내에서 몇가지 가상 호스트를 지원할 수 있게끔 할 것이다.

실세계 설정

기본적으로 Tomcat 배포본은 주 목표가 처음에 사용하는 사람을 대상으로 하고 설정에 대해서 변경하지 않아도 작동이 가능하게끔 되어 있는 설정이다. 그러나 이러한 설정은 실제 사이트에서 적용하기에는 최선의 방법은 아니다. 예를 들어서, 실제 사이트는 어떤 퍼포먼스 튜닝이나 특정 세팅(예를 들어 경로 요소의 추가라든가)이 필요할 수도 있다. 이 장은 사이트에 근거한 Tomcat을 작동하기 이전에 조치를 취해야만 하는 첫번째 단계를 지적함으로 인해 시작할 것이다.

배치 파일에 대한 수정

이전 장에서 설명했듯이 startup 스크립트는 편이에 의해서 있는 것이다. 그러나, 때로는 적용에 필요한 스크립트는 수정되어야 한다.
  • descriptor의 최대 숫자와 같은 리소스 한계의 설정
  • 새로운 CLASSPATH 값의 추가 (예를 들어, JDBC 드라어버)
  • 새로운 PATH/LD_LIBRARY_PATH 값의 추가 (예를 들어, JDBC 드라이버의 DLL)
  • JVM 명령행 설정에 대한 변경
  • 특정 JVM을 사용하도록 설정 (머신에 인스톨된 두개 혹은 세개의 JVM)
  • UNIX 명령어 “su”를 사용해서 root 사용자에서 다른 사용자로의 변경
  • 사용자 편이에 의한 이유
이러한 변경 중에 몇몇은 기본적인 스크립트를 바꾸지 않고 실행할 수 있다. 예를 들어, tomcat 스크립트는 JVM에게 특정 명령행 인자(메모리 세팅과 같은)를 설정하는 TOMCAT_OPTS라고 하는 환경변수를 사용할 수 있다. UNIX에서는 홈 디렉토리에 “.tomcatrc”라고 하는 파일을 생성하고 Tomcat이 이 파일로부터 PATH, JAVA_HOME, TOMCAT_HOME, CLASSPATH와 같은 환경 정보를 가지고 오게 할 수도 있다. 그러나, NT(그리고 UNIX에서도 수정이 JVM 명령행과 같은 부분에 대해서 일때이다.)에서는 startup 스크립트의 몇몇 부분들을 다시 쓰면 된다.
결코 주저하지 말라. 한번 해보면 된다.

기본 JVM 설정에 대한 변경

Tomcat 스크립트에서 기본 JVM에 대한 설정은 매우 원시적이다. 모든 것이 기본적이다. Tomcat 퍼포먼스를 향상하는 데 고려해야 하는 다음 몇가지 사항이 있다.
  1. JVM 메모리 설정을 변경하라. 일반적으로 JVM Java 힙에 대한 초기 크기를 할당한다. 만일 필요하다면, 이 메모리 양은 얻을 수는 없을 것이다.
    그럼에도 불구하고, 실제 사이트에서는 JVM에게 메모리를 추가함으로써 Tomcat의 성능을 향상시킬 수 있다. Java 힙의 최대/최소 크기를 설정하기 위해서 -Xms/-Xmx/-ms/-mx와 같은 명령행 인자를 사용해야 한다. (그리고, 성능이 향상되었는지 점검해보라.)
  2. JVM 스레딩 설정을 변경하라. SUN의 리눅스 버전인 JDK1.2.2는 안전(green) 스레드와 원천(native) 스레드 둘다를 지원한다. 일반적으로 원천 스레드는 I/O 범위 어플리케이션에 대해서 향상된 성능을 제공하는 것을 알려져 있지만 반면에 안전 스레드는 머신에 로드를 줄이게 되어있다. 이러한 두가지 스레딩 모델에 대해서 실험해보고 어떤 모델이 여러분의 사이트에 더 적합한지를 알아야 한다. (일반적으로 원천 스레드가 더 낫다.)
  3. 업무에 있어서 최상의 JVM을 선택하라. 몇가지 JVM 벤더들이 있는데, 예를 들어, 리눅스에 대해서 현재(2000년 3월 21) SUN에서 제공하는 JDK1.2.2 IBM에서 제공하는 JDK1.1.8의 두가지 JVM이 있다. 만일 어플리케이션이 특정 JDK 기능을 필요로 하지 안는다면 두가지 JVM에 대해서 벤치마크를 해보고 더 나은 것을 선택해야 한다. 저자의 테스트 경우, IBM JVM SUN사의 것보다 훨씬 더 빠른 걸로 나타났다. 여러분들은 직접 점검을 해보고 결정을 해보기 바란다.

Connector 수정

Tomcat의 기본 server.xml에 설정된 Connector는 다음 server.xml 부분에서처럼 설정된 두가지 Connector를 포함하고 있다.
server.xml에서 두가지 기본적인 Connector
        <!-- (1) HTTP Connector for stand-alone operation -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler"
                value="org.apache.tomcat.service.http.HttpConnectionHandler"/>
            <Parameter name="port"
                value="8080"/>
        </Connector>
 
        <!-- (2) AJPV12 Connector for out-of-process operation -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter name="handler"
                value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter name="port"
                value="8007"/>
        </Connector>
                
  1. 첫번째 것은 8080포트에서 HTTP 요청을 받아들이는 Connector이다. Connector stand-alone 옵션에서 필요한 것이다.
  2. 두번째 것은 8007포트에서 AJPV12 요청을 받아들이는 Connector이다. Connector는 웹 서버에 애드 온해서 사용할 때(out-of-process 옵션)에 필요한 것이다.
AJPV12 Connector Tomcat 셧다운 시에 필요하다. 그러나, HTTP Connector stand-alone 옵션이 필요하지 않다면 제거해야 할 것이다.

Connector에서 스레드 사용

Tomcat은 다중 스레드 servlet 컨테이너이다. 이것은 각각의 요청은 어떤 스레드에 의해 실행될 필요가 있다는 것을 의미한다. Tomcat 3.2 이전에는 들어오는 각각의 요청에 대해서 새로운 스레드가 생성이 되어서 서비스하게 되어 있었다. 이것은 다음과 같은 이유로 사이트에 대해서 로드를 주는 문제를 야기시킨다.
  • 모든 요청에 대해서 스레드를 시작하고 멈추는 것은 OS JVM에 대해 불필요한 로드를 주는 것이다.
  • 자원 소비에 대해서 제한하기가 어렵다. 만일 동시에 300개의 요청이 들어온다면 Tomcat은 그들을 서비스하기 위해서 300개의 스레드를 열고 동시에 300개의 요청을 서비스할 필요가 있는 자원을 할당할 것이다. 이것은 Tomcat이 훨씬 더 많은 자원(CPU, 메모리, descriptor )을 할당하게 하고, 낮은 성능을 이끌 뿐만 아니라 자원이 다 소모될 경우에 서버가 멈추기까지 한다.
이러한 문제에 대한 해결책은 스레드 풀(thread pool)을 사용하는 것인데, 이것은 Tomcat3.2가 기본적으로 지원을 한다. 스레드 풀을 사용하는 Servlet 컨테이너는 자신의 스레드를 직접적으로 관리하는 것으로부터 자유롭게 한다. 새로운 스레드를 할당하는 대신에 스레드가 필요할 때마다 풀에서 스레드를 요청하고 스레드에 대한 서비스가 끝나면 스레드는 다시 풀에 반환된다. 스레드 풀은 현재 다음과 같이 복잡한 스레드 관리를 구현하기 위해 사용될 수 있다.
  1. 스레드를 열어놓은상태로 유지하고 반복하여 재사용한다. 이것은 연속적으로 스레드를 생성하고 소멸하는 것과 관련한 문제를 없앤다.
    • 일반적으로 관리자는 필요하면 스레드를 제거함으로써 너무 많은 유휴 스레드를 가지지 않도록 풀에게 지시할 수 있다.
  2. 동시에 사용된는 스레드의 숫자의 한계를 설정한다. 이것은 제한되지 않는 스레드 할당과 관련한 할당 문제를 없앤다.
    • 만일 컨테이너가 제한 스레드 숫자를 넘고 새로운 요청이 들어온다면, 새로운 요청은 다른 요청이 끝나고 그 요청을 서비스하기 위해서 스레드를 자유롭게 될 때까지 대기해야 할 것이다.
위에서 여러가지 방법으로 설명된 기술을 기교를 부려 사용할 수는 있겠지만, 그것은 어디까지나 기교일 뿐이다. 스레드 쿨의 주요 목표는 스레드의 재사용과 리소스 사용에 한계가 있는 동시 처리 한계 값을 갖는다는 것이다.
Tomcat에서 스레드 풀을 사용하는 것은 단순하다. 해주는 것은 <Connector> 설정에서 PoolTcpConnector를 사용하는 것이다. 예를 들어 다음의 server.xml 부분은 풀링된 Connector ajpv12을 정의하고 있다.
풀링된 ajpv12 Connector
        <!-- A pooled AJPV12 Connector for out-of-process operation -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter
                name="handler"
                value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter
                name="port"
                value="8007"/>
        </Connector>
                
이 부분은 매우 단순하고 (기본) 풀 행동이 다음과 같은 항목으로 제약된다.
  • 50개의 스레드의 동시 처리에 대한 한계
  • 풀이 휴지 상태의 25개 이상의 스레드를 가지고 있으면 모두를 없애기 시작한다.
  • 풀은 생성시에 10개의 스레드로 시작하고 (한계가 유지되는 한)10개의 비어있는 스레드를 유지하려고 한다.
기본 설정은 평균 10~40개의 동시 요청에 대해서 로드가 걸리는 중소 사이트에 대해서 적당하다. 만일 여러분의 사이트가 그렇지 않다면 이와 같은 설정 (예를 들어 한계값)을 수정해야 한다. 풀을 설정하는 것은 아래와 같이 server.xml <Connector> 요소를 통해서 하면 된다.
스레드 풀 설정하기
        <!-- A pooled AJPV12 Connector for out-of-process operation -->
        <Connector className="org.apache.tomcat.service.PoolTcpConnector">
            <Parameter
                name="handler"
                value="org.apache.tomcat.service.connector.Ajp12ConnectionHandler"/>
            <Parameter
                name="port"
                value="8007"/>
            <Parameter
                name="max_threads"
                value="30"/>
            <Parameter
                name="max_spare_threads"
                value="20"/>
            <Parameter
                name="min_spare_threads"
                value="5" />
        </Connector>
                
보는 바와 같이 풀은 다음의 3개의 설정 인자를 갖는다.
  • max_threads – 동시 요청을 서비스 할 수 있는 최대 스레드 개수. 풀은 이 숫자 이상의 스레드를 생성하지 않는다.
  • max_spare_threads – 풀이 휴지 상태를 유지하는 최대 스레드 개수. 만일 휴지 스레드의 수가 max_spare_threads의 값을 초과하면 풀은 이러한 스레드를 없앤다.
  • min_spare_threads – 풀은 어떠한 시점에도 도달하는 새로운 요청을 대기하는 휴지 스레드의 이 숫자를 최소한 있도록 한다. min_spare_threads 0보다 커야한다.
위의 인자를 사용해서 필요한 만큼 풀의 상태를 적용할 수 있다.

Servlet Auto-Reloading 기능 제거

servlet auto-reloading은 개발 시점에 매우 유용하다. 그러나 그것은 매우 소모적이고 어떤 클래스 로더에 의해 로딩되었던 클래스가 현재 클래스 로더에 의해 로딩된 클래스와 연관을 시키지 못할 경우에 충돌 현상이 생길 수도 있다.
그래서 개발 동안 클래스 리로딩이 정말로 필요하지 않다면 context에서 reloadable 플래그를 false로 하는 게 좋다.