달력

1

« 2025/1 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2010. 5. 18. 12:22

JSP 웹서버 세팅(tomcat6.0+apache2.2연동) Enjoy/JSP2010. 5. 18. 12:22


원문 : http://www.cyworld.com/CHERRY_PINK82/2661345





우선 기본적으로 apche2.2와 tomcat6.0이 설치 되어 있다는 전재하에 설명을 시작한다.

아참..그리고 이거대로 한다고 100% 다 되는건 아니다.. 꼭 자기 개발환경에 맞게 참고하여

수정하는게 중요하니 똑같이 뱃겨놓고 안되요...이러는건 아마츄어에요!ㅋㅋㅋ

 

1. apache2.2 Install

Apache 란? – 정적 파일의 웹 서비스를 담당하는 웹서버

Tomcat 자체적으로도 정적 파일 웹 서비스 기능이 있으나 속도가 느리기 때문에 정적 파일만을 전문으로

서비스하는 Apache 와 연동하여 역할을 분담하는 방식으로 주로 사용한다.

 


2. tomcat6.0  Install
Tomcat 이란? – 가장 유명한 JSP, Servlet Container
(Tomcat 을 설치하기 전에 반드시 먼저 JDK 가 설치되어 있어야 함)

 

 

3. JK 1.2 Install
JK Connector 란? - Apache + Tomcat 연동 프로그램

JK설치에는 동적모듈방식, 정적,모듈방식  두 가지 방법이 있는데 후자의 경우가 성능이 좋으나
지금 설치는 동적모듈 방식으로 설명한다.

 

www.apache.org ==> tomcat ==> tomcat_connectors ==> Binary Releases 에서
원하는 서버에 맞는 버젼을 다운받아 아래와 같이 "mod_jk.so"로 이름 변경 후  Apache2.2/modules 에 복사해 놓는다.

mod_jk-1.2.27-httpd-2.0.63.so ==> mod_jk.so 
mod_jk-1.2.27-httpd-2.2.10.so ==> mod_jk.so

 

4. workers.properties 생성
---------------------------------------------------------------------------------------------------------------------------
Apache2.2/conf 폴더안에  workers.properties 파일생성 후 아래 내용을 작성한다.
---------------------------------------------------------------------------------------------------------------------------
workers.tomcat_home="C:/Program Files/Apache Software Foundation/Tomcat 6.0"
workers.java_home="C:/Program Files/Java/jdk1.5.0_07"
ps=/

worker.list=ajp12, ajp13
worker.ajp12.port=8007
worker.ajp12.host=localhost
worker.ajp12.type=ajp12
worker.ajp12.lbfactor=1

worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.lbfactor=1

worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=ajp12, ajp13
worker.inprocess.type=jni
worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
worker.inprocess.cmd_line=start
worker.inprocess.stdout=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout
worker.inprocess.stderr=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stder

 

 

5. mod_jk.conf 파일 생성
---------------------------------------------------------------------------------------------------------------------------
Apache2.2/conf 폴더안에  mod_jk.conf  파일생성 후 아래 내용을 작성한다.
---------------------------------------------------------------------------------------------------------------------------
JkWorkersFile "C:/Program Files/Apache Software Foundation/Apache2.2/conf/workers.properties"
JkLogFile "C:/Program Files/Apache Software Foundation/Tomcat 6.0/logs/mod_jk.log"
JkLogLevel debug
JkAutoAlias "C:/Program Files/Apache Software Foundation/Tomcat 6.0/webapps"
JkMount /* ajp13
JkUnmount /images/* ajp13
<Directory "C:/Program Files/Apache Software Foundation/Tomcat 6.0/webapps">
    Options Indexes FollowSymLinks
    allow from all
</Directory>

 

 

6. httpd-vhosts.conf(가상호스트 설정방법) 수정
---------------------------------------------------------------------------------------------------------------------------
Apache2.2/conf/extra 폴더안에  httpd-vhosts.conf 파일안에 내용추가
---------------------------------------------------------------------------------------------------------------------------
<VirtualHost 127.0.0.1:80>
    ServerAdmin hja1028@naver.com
    DocumentRoot "C:/workspace/rvsystem/web/"
    ServerName dev.rvsystem.com
    ErrorLog "logs/rvsystem-error.log"
    CustomLog "logs/rvsystem-access.log" common
 JkUnmount /images/* ajp13
 JkUnmount /scripts/* ajp13
 JkUnmount /css/* ajp13
 JkMount /* ajp13
</VirtualHost>

 

<주의사항>

  • 처음설정은 디폴트 호스트(DocumentRoot)로써 주로 비워두거나 테스트용도로 설정한다.
  •  [주의] 가상호스트로 사용하기 위해선 반드시 위에서 설정한 <Directory “/workspace”> 을 확인해야한다.
      이를 설정하지 않는다면 모든 가상호스트들 접속시 403에러(접근권한에러)가 난다.
  •  이후 추가되는 가상호스트는 같은 형식으로 추가 후 DocumentRoot와 ServerName만 수정

 

7. httpd.conf수정
---------------------------------------------------------------------------------------------------------------------------
Apache2.2/conf폴더안에  httpd.conf 파일안에 내용추가
---------------------------------------------------------------------------------------------------------------------------
<Directory "/workspace") - 접근권한 디렉토리명 변경

LoadModule jk_module modules/mod_jk.so


<Directory />
    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
    Deny from all
    Satisfy all
</Directory>


Include conf/mod_jk.conf

 

 

8. server.xml 수정
<Connector port="8080"> 모두 주석처리 (아파치와의 커넥터(ajp13)만 사용)
<Connector port="8009"> URIEncoding="UTF-8" 추가. (GET request 한글처리)

 

첨부파일은 참고만 하세요 현재 제꺼에 맞춰논것들이라 그냥 쓰면 에러가 ~_~!

참 mod_jk.so 다운받으실 때 1.2.24버전 이후꺼 받으세여!ㅋㅋ

전 1.2.27버전이랍니다..

:
Posted by 라면스프





왜 Apache HTTP Server와 Tomcat을 연동하는가?

Apache Tomcat(이하 Tomcat)은 아마도 가장 널리 알려진 JSP / Servlet Engine일 것입니다. JSP / Servlet 명세에 대한 참조 구현물(Referencial Implementation, 흔히 줄여서 RI라고도 하죠) 역할도 하고 있으며, 실 업무에서도 꽤 씁니다(왕년에 Naver Blog를 쓸 때 한번은 Java Exception Trace log가 Web Browser에 표시된 것을 본 적이 있었습니다. 그 덕에 Naver Blog가 Tomcat을 쓴다는 것을 알았죠).

 

그러나 실전에서는 web server와 tomcat 같은 JSP/Servlet Engine 둘을 연동해서 쓰지, tomcat만 쓰지는 않습니다. 그 이유는 아래와 같습니다.

성능 상의 이유

JSP/Servlet Engine 상에서 동작하는 Servlet이나 JSP라는, (동일한 HTTP Request를 보내도 매 번 그 결과가 다를 수 있는) 동적인 HTTP Response를 생성해 보내는 것들입니다. 그에 비해 단순한 HTML 문서, image, CSS(Cascading Style Sheet), Javascript file은 거의 변할 일는 (동일한 HTTP Request를 보내면 그 결과가 늘 같은) 정적 contents입니다. 이런 정적 contents는 통상적으로 Web Server가 JSP/Servlet Engine보다 더 빠르게 service합니다.

 

감 이 오시나요? 결국 정적 content는 정적 contents 처리에 강한 Web Server가 처리하고, 동적 contents는 JSP/Servlet Engine이 맡는 것입니다. 일단 HTTP Request를 Web Server가 먼저 받아보고 정적 contents를 요구하면 자신이 처리하고, 동적 contents request라면 이 request를 JSP/Servlet Engine에게 넘기죠. 아니면 특정 URL pattern이 들어오면 JSP/Servlet Engine으로 넘기는 방법도 있습니다. 결국 이렇게 하면 부수적으로 동적 contents 생성하느라 바쁜 JSP/Servlet Engine에 부하를 덜 줄 수 있고 정적 contents service하느라 귀중한 JVM Heap을 아낄 수 있는 이점도 누릴 수 있습니다.

보안 상의 이유

보 통 JSP/Servlet Engine은 중요한 업무 절차에 대한 구현을 가지고 있게 마련입니다. 단순한 image, CSS 같은 정적 contents를 담은 Web Server보다 더 안전해야 보호해야 한다는 뜻이 됩니다. 보통 어떤 기업 같은 조직의 network를 구성할 경우 외부 network와 조직의 network를 방화벽(firewall)으로 단절시키고 방화벽에 규칙(rule)을 등록, IP packet이 제한적으로만 그 방화벽을 넘다들 수 있도록 합니다. 안전성이 더 높아야 하는 server들이 있는 network zone는 여기에 한 번 더 방화벽을 칩니다. 그리고 이 두 방화벽 사이의 network zone을 DMZ라고 합니다.

 

이렇게 Web Server와 JSP/Servlet Engine을 따로따로 쓰면 DMZ에 덜 중요한 data를 가진 web server를 놓고 이중 방화벽 뒤에 있는 network zone에 JSP/Servlet Engine을 놓음으로써 높은 보안성을 획득하면서도 외부에 동적 contents를 제공할 수 있게 됩니다.

가용성 상의 이유

web server도 하나, JSP/Servlet Engine도 하나라면 둘 중 하나만 죽으면 정상적인 service가 불가능합니다. 따라서 절대 멈추면 안되는 service(세계화가 되면서 이런 요구 사항은 더 늘었습니다. 지구 상 어딘가는 늘 업무 시간이니까요)를 담당하는 web server, JSP/Servlet Engine은 두 개 이상을 가동하는 이중화를 적용합니다.

 

web server가 어떤 HTTP Request를 받아 이를 JSP/Servlet Engine으로 넘기려 할 때 그 JSP/Servlet Engine이 이중화가 되어 있다면 web server는 이 request를 좀 한가한 JSP/Servlet Engine에 넘긴다던지 할 수 있습니다(물론 실제로는 간단하게는 round robin부터 시작해서 이에 대한 여러가지 방법이 있습니다). 내지는 JSP/Servlet Engine 중 하나가 비정상적으로 종료한 상태이면 현재 살아 있는 JSP/Servlet Engine에게 이 request 처리를 위임, 전반적인 service 중단을 막을 수 있습니다.

 

준비물

  • Apache Tomcat

    • Apache Tomcat : Apache Tomcat 대표 site. Tomcat을 내려받으려면 가야 하는 곳.
  • Apache HTTP Server

    • Apache HTTP Server : Apache HTTP Server 대표 site.
    • Apache Lounge : Windows용 Apache HTTP Server 정보가 풍부함. Windows용 Apache HTTP Server는 여기에서 받을 것을 추천!
  • mod_jk

    • Apache Tomcat : Apache Tomcat 대표 site. mod_jk도 여기서 받을 수 있습니다(이 site에서는 mod_jk를 'Apache Connector'라고 부릅니다).

 

작업 절차

 

간단한 구성

간단한 구성이란, 개발이나 가벼운 Web Service 운영을 목적으로 하나의 Apache HTTP Server + 하나의 Tomcat 연동 구성을 하는 것입니다. 이 작업에 대한 구체적 작업 절차는 [tomcat]apache, tomcat 연동하기 글에서 잘 설명하고 있습니다(Windows / Linux에서 mod_jk로 Apache와 Tomcat 연동하는 것을 proxy_module과 같이 설치할 경우와 아닌 경우 모두 설명하고 있습니다).

 

고가용성을 위한 구성

Naver Blog와 같이 사용자가 많다거나 장애 등을 감내할 수 있는(Fault Tolerant) Web Service를 구성하려면 위 간단한 구성으로는 어렵고 여러 개의 Apache HTTP Server + 여러 개의 Tomcat 연동 구성을 해야 합니다. 이렇게 해야 일부 Apache HTTP Server나 Tomcat이 죽어도 나머지들이 request를 처리할 수 있지요. 이러한 특성을 고가용성(High Availability)이라 하는데 이 고가용성은 위와 같은 단순한 설정만으로는 얻기 어렵습니다. 이런 고가용성 설정은 '아파치와 톰캣을 활용한 대용량 웹서비스 운영'이란 글에서 잘 설명하고 있습니다.

 

참고 문헌

 

예시

  • Apache HTTPD 2.2 설정 file : mod_jk로 Apache HTTP Server 2.2와 Tomcat 6을 연동시킨 결과로 나온 Apache Web Server 2.2 설정 file.
  • Apache Tomcat 6 설정 file : mod_jk로 Apache HTTP Server 2.2와 Tomcat 6을 연동시킨 결과로 나온 Apache Tomcat 6 설정 file.
  • mod_jk.conf : 실제 mod_jk 설정 정보를 담은 mod_jk 설정 file.

출처 : http://ryudaewan.springnote.com/pages/610881
:
Posted by 라면스프

원문 : http://www.ibm.com/developerworks/kr/library/opendw/20061017/?ca=drs-kr

난이도 : 초급 
2006년 10월 17일


웹 개발자에게 있어 톰캣은 JSP를 배우거나 간단한 테스트를 하는 정도의 웹 컨테이너로 생각하는 경우가 많다. 하지만 근래 들어 기업 및 대형 포탈에서 상용 서비스를 위한 웹 컨테이너로서 톰캣을 선택해, 성공적으로 적용한 사례들이 늘고 있다. 톰캣에서 안정적인 웹 서비스를 제공하기 위해서 지원하는 기능은 5가지가 있다. 아파치 웹서버와 연동, 로드밸런싱, 세션 클러스터링, 데이터베이스 처리, 모니터링 및 관리 등이 그것이다. 
이 문서에서는 로드밸런싱과 세션 클러스터링 위주로 설명을 할 것이며, 다음에 기회가 된다면 다른 부분에 대해서도 자세히 알아보도록 하겠다.

아파치 웹 서버와 톰캣의 연동

일반적으로 정적인 페이지를 서비스할 때는 웹서버가 훨씬 더 좋은 성능을 발휘한다. 또한 이렇게 역할 분담을 함으로 톰캣에 가중되는 부하를 줄여주는 효과도 얻을 수 있다. 아파치웹서버와 톰캣을 연동하는 것을 일반적으로 ‘커넥터(Connector)'라고 부르며, 여기에는 WARP 커넥터, JK 커넥터 그리고 JK2 커넥터가 있다. 이중에서 WARP와 JK2는 공식 커넥터에서 제외되었고 현재 남아 있는 것은 JK 커넥터뿐이다. 그럼 먼저 JK 커넥터를 이용해서 아파치 웹서버와 톰캣을 연동해 보도록 하겠다. 
아파치 웹사이트에서 바이너리 혹은 소스 코드를 다운로드 받도록 하자. 유닉스 혹은 리눅스는 mod_jk.so이며 윈도우용은 mod_jk.dll이다. 이 파일을 아파치 웹서버의 modules 디렉토리에 저장한다(주의, 아파치 웹서버를 컴파일해서 사용하는 경우는 컴파일시에 DSO 기능이 가능하도록 설정해줘야 한다). 저장을 한 후에 아파치 웹서버에 해당 모듈을 인식시켜야 하며 아파치 웹서버의 httpd.conf 파일에 다음 내용을 추가하도록 하자.


리스트 1. httpd.conf
        ...
LoadModule jk_module modules/mod_jk.so    # 모듈 추가
JkWorkersFile "conf/workers.properties"   # JK 설정 파일 위치 및 이름
 
JkLogFile "logs/mod_jk.log"               # JK에 대한 로그 파일 위치
JkLogLevel info                           # 로그 레벨 지정
JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"   # 로그 시간 포맷 지정
JkRequestLogFormat "%w %V %T"             # 로그 내용 포맷
JkMount /* loadbalancer                   # URL 링크 -> 모든 요청을 톰캣으로 지정
JkMount /servlet/* loadbalancer           # URL 링크 -> servlet 요청을 톰캣으로 지정
...

위와 같은 설정을 하게 되면 아파치 웹서버로 들어온 모든 요청을 톰캣으로 재전송 하게 된다. 만일 JSP와 서블릿만 톰캣에서 서비스를 하고 나머지는 아파치 웹서버에서 서비스 하고자 한다면 다음과 같이 수정하면 된다.

  
JkMount /*.jsp loadbalancer                # URL 링크 -> *.jsp 요청을 톰캣으로 지정 
JkMount /servlet/* loadbalancer           # URL 링크 -> servlet 요청을 톰캣으로 지정 

httpd.conf에는 위의 내용이 전부이다. 그럼 이제 workers.properties 파일을 작성해 보도록 하겠다. 이 파일이 실제 로드밸런싱을 위한 설정이 되겠다.




위로


라운드 로빈 방식의 로드밸런싱 설정

톰캣에서 제공하는 로드밸런싱은 정확히 톰캣 자체에서 제공하는 것이 아니라 아파치 웹서버와 연동되는 커넥터에 의해서 제공된다(로드밸런싱은 JK, JK2 커넥터에서만 제공된다). 현재는 라운드 로빈(Round Robin) 방식만이 제공되며 로드밸런싱에 대한 설정은 workers.properties 파일에서 정의하게 된다.

리스트 2. workers.properties 
  
worker.list=tomcat1, tomcat2, loadbalancer
 
worker.tomcat1.type=ajp13
worker.tomcat1.host=localhost
worker.tomcat1.port=11009
worker.tomcat1.lbfactor=100
 
worker.tomcat2.type=ajp13
worker.tomcat2.host=localhost
worker.tomcat2.port=12009
worker.tomcat2.lbfactor=200
 
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tomcat1,tomcat2

worker라는 개념은 톰캣의 프로세스로 보면 된다. 즉 worker를 설정하는 구성 요소는 JK 커넥터를 연결하는 방식(JK는 ajp13을 이용한다), 톰캣이 실행되어 있는 IP 혹은 도메인, ajp13 서비스 포트, 그리고 작업 할당량이다. 여기서 주의 깊게 볼 것이 작업 할당량인데 로드밸런싱 시에 lbfactor라는 작업량의 비율을 보고 라운드 로빈 방식의 서비스를 제공하게 된다. 여기서는 tomcat1과 tomcat2를 1대 2의 비율로 작업량을 할당한 것이다. 
그럼 이제 남은 작업은 2개의 톰캣 프로세스를 실행시키는 것이다. 톰캣 프로세스를 여러 개 띄우는 방법은 2가지가 있다.

  • 톰캣을 2개 설치해서 기동시킨다. 이때 포트 충돌을 피하기 위해 서버 포트, AJP13과 HTTP 1.1 커넥터 포트 2개를 충돌되지 않게 재정의 한다.
  • 하나의 톰캣에 2개의 서비스를 정의하고 톰캣을 기동시킨다. 이때 AJP13과 HTTP1.1 커텍터 포트 2개를 충돌되지 않게 재정의 한다.

먼저 2개의 바이너리를 설치했다고 가정하면 각각의 톰캣은 다음과 같은 형태의 server.xml 파일로 적용해 준다.

리스트 3. server.xml 
<Server port="11005" shutdown="SHUTDOWN"> <!-- 톰캣 프로세스를 관리하는 포트 --> <Service name="Catalina"> <Connector port="11080"/> <!-- 아파치를 통하지 않고 직접 접속하고자 할때의 포트 --> <Connector port="11009" protocol="AJP/1.3"/> <!-- 아파치와 연동하기 위한 포트 --> <!-- jvmRoute 명 JK 커넥터에서 톰캣 프로세스를 구분하는데 사용. 프로세스 별로 다르게 적용해야 함 --> <Engine jvmRoute="tomcat1" name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps"/> </Engine> </Service> </Server>


리스트 4. server.xml 
<Server port="12005" shutdown="SHUTDOWN"> <!-- 톰캣 프로세스를 관리하는 포트 --> <Service name="Catalina"> <Connector port="12080"/> <!-- 아파치를 통하지 않고 직접 접속하고자 할때의 포트 --> <Connector port="12009" protocol="AJP/1.3"/> <!-- 아파치와 연동하기 위한 포트 --> <!-- jvmRoute 명 JK 커넥터에서 톰캣 프로세스를 구분하는데 사용. 프로세스 별로 다르게 적용해야 함 --> <Engine jvmRoute="tomcat2" name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps"/> </Engine> </Service> </Server>

리스트 3은 tomcat1의 환경 설정이고 리스트 4는 tomcat2의 환경 설정이다. 두 환경 설정의 차이는 3개의 포트번호와 <Engine> 태그의 jvmRoute 속성이다. <Server> 태그의 포트는 톰캣을 종료 시키는 작업을 할 때 사용하는 것이며 <Connector> 태그의 포트들은 아파치를 통하지 않고 직접 톰캣에 접속할 경우와 아파치와 연계하여 JK 커넥터와 연동할 때 사용하는 포트이다. 마지막으로 <Engine> 태그는 JK 커넥 터에서 로드밸런싱을 수행할 때 해당 값을 구분자로 활용하게 되는데 이 값을 반드시 다른 톰캣 프로세스와 다른 이름으로 지정해야 한다. 지금까지의 환경 설정은 하나의 아파치 웹서버와 두 개의 톰캣 간의 연계를 위한 것이며 톰캣은 동일한 하드웨어 장비에 설치되어 있다는 가정하에 적용한 것이다. 만일 각각의 톰캣이 서로 다른 하드웨어에 존재한다면 jvmRoute명만 다르게 하고 포트명은 동일해도 상관이 없다. 하지만 만일 하나의 장비에 4개의 톰캣 프로세스를 실행시키고 로드밸런싱을 하려고 한다면 어떻게 될까? 톰캣을 4번 설치하고 각각의 환경 설정 파일을 수정해 주어야 할까? 만일 필요한 환경 설정 내용이 변경된다면(예를 들어 JNDI Resource 정보) 모두 운영자가 환경 설정 파일을 수정해 주어야 할까? 다행히도 톰캣에서는 하나의 바이너리에 여러 개의 프로세스가 뜨도록 할 수 있다. 톰캣의 server.xml 태그는 다음과 같은 구조를 가지고 있다.
<Server> --> <Service> --> <Engine> --> <Host> --> <Context>

여기서 Server 태그는 유일해야 하며 Server 태그 밑에는 여러 개의 <Service> 태그가 올 수 있다. 여기서 말하는 <Service> 태그가 바로 하나의 톰캣 프로세스가 된다. 만일 2개의 <Service> 태그를 정의했다면 2개의 프로세스가 구동되는 것이다. 리스트 5는 이렇게 구현한 환경 설정 파일이다. 리스트 5. server.xml 
<Server port="8005" shutdown="SHUTDOWN"> <!-- Service 1 --> <Service name="Catalina1"> <Connector port="11080"/> <Connector port="11009" protocol="AJP/1.3"/> <Engine jvmRoute="tomcat1" name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps"/> </Engine> </Service> <!-- Service 1 --> <Service name="Catalina2"> <Connector port="12080"/> <Connector port="12009" protocol="AJP/1.3"/> <Engine jvmRoute="tomcat2" name="Catalina" defaultHost="localhost"> <Host name="localhost" appBase="webapps"/> </Engine> </Service> </Server>

리스트 5는 하나의 톰캣 바이너리를 통해 2개의 프로세스를 실행시키는 것이다. 이렇게 하면 환경 설정의 편리성을 가져올 수 있지만 특정 서비스만 실행하거나 종료 시키는 것은 아직 지원되지 않는다. 즉 모든 서비스가 동시에 실행되거나 혹은 동시에 종료되는 것을 의미한다. 이런 점을 잘 판단해서 두 가지 형태의 환경 설정 중 하나를 선택하면 되겠다. 
지금까지는 로드밸런싱에 대해 알아보았다. 위의 환경설정을 가지고 테스트를 하다 보면 한가지 문제가 발생한다. 예를 들어 어떤 사용자가 tomcat1을 이용해서 쇼핑몰 서비스를 받고 있다가 tomcat1이 비정상 종료를 하게 되었다. 이때 사용자가 웹 페이지를 요청하게 되면 아파치 웹서버는 tomcat1이 종료된 것을 인지하고 그 이후부터 서비스를 tomcat2로 요청하게 된다. 하지만 tomcat1에 저장되어 있던 쇼핑바구니 정보 즉 세션 정보는 사라진 상태다. 즉, 서비스는 유지되지만 사용자는 다시 이유도 모르게 처음부터 쇼핑 항목들을 등록해야 하는 문제를 가지게 된다. 이제부터는 이런 문제를 해결할 수 있는 톰캣 프로세스 간의 세션 정보 공유에 대해서 알아보겠다.




위로


세션 클러스터링 설정

클러스터링은 톰캣 5.x 버전부터 지원이 되고 있지만 아직은 초기 단계이고 세션 클러스터링만이 제공되고 있는 수준이다. 기능이 많이 부족하긴 하지만 로드밸런싱과 더불어 사용할 경우에는 좀 더 안정적인 서비스를 제공할 수 있다. 작업을 해주어야 할 것은 다음과 같다.

  • server.xml에 <Cluster> 태그 정의
  • 웹 어플리케이션의 web.xml에 <distributable/> 태그 추가
그럼 server.xml에 설정해 보자. <Cluster> 태그는 <Host> 태그의 하위에 정의해 주면 된다. 즉 여러 개의 호스트(예를 들어 가상 호스트) 를 설정했다면 각각의 경우에 맞게 설정해 주어야 한다. 여기서는 tomcat1과 tomcat2가 동일한 하드웨어에 별도의 바이너리 형태로 설치되어 있다고 가정하고 진행하겠다. 리스트 6. server.xml 
... <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster" managerClassName="org.apache.catalina.cluster.session.DeltaManager" expireSessionsOnShutdown="false" useDirtyFlag="true"> <Membership className="org.apache.catalina.cluster.mcast.McastService" mcastAddr="228.0.0.105" mcastPort="45564" mcastFrequency="500" mcastDropTime="3000"/> <Receiver className="org.apache.catalina.cluster.tcp.ReplicationListener" tcpListenAddress="auto" tcpListenPort="4001" tcpSelectorTimeout="100" tcpThreadCount="6"/> <Sender className="org.apache.catalina.cluster.tcp.ReplicationTransmitter" replicationMode="pooled"/> <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve" filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/> </Cluster> ...

리스트 6은 tomcat1의 server.xml에 적용한 <Cluster> 태그이다. 이 내용은 <Host> 태그 사이에 위치하게 된다. <Cluster> 태그 사이에는 <Membership>, <Receiver>, <Sender>라는 3개의 태그가 위치하는데 <Membership>은 멤버 그룹을 정의하는 것으로 해당 값이 동일한 모든 톰캣 프로세스는 클러스터로 묶이게 된다. <Receiver>는 클러스터 그룹에서 보내오는 메시지와 세션 정보 등을 받아오는 것이며 <Sender>는 자신의 세션 정보 및 메시지를 전송하는 것이다. 위의 내용을 tomcat2의 server.xml에 Receiver 태그의 tcpListenPort 값을 4002로 변경해서 적용하도록 하자.


위로


웹 어플리케이션 작성을 통한 테스트

먼저 테스트를 위해서 간단한 웹 어플리케이션을 작성하도록 하겠다. 여기서 웹 어플리케이션 이름은 lbtest라고 하겠다.

리스트 7. index.jsp 
<%@ page contentType="text/html; charset=euc-kr" %> <HTML> <HEAD> <TITLE>세션 JSP 테스트</TITLE> </HEAD> <BODY> <h1>세션 JSP 테스트</h1> <% Integer ival = (Integer)session.getAttribute("sessiontest.counter"); if(ival==null) { ival = new Integer(1); } else { ival = new Integer(ival.intValue() + 1); } session.setAttribute("sessiontest.counter", ival); %> 당신은 이곳을 <b> <%= ival %> </b>번 방문 했습니다.<p> 여기를 클릭하세요. <a href="index.jsp">여기</a> <p> <h3>request 객체와 관련된 세션 데이터</h3> 요청된 세션 ID : <%= request.getRequestedSessionId() %><br /> 쿠키로 부터 요청된 세션 ID 인가? : <%= request.isRequestedSessionIdFromCookie() %><br /> URL로부터 요청된 세션 ID 인가? : <%= request.isRequestedSessionIdFromURL() %><br /> 유효한 세션 ID 인가? : <%= request.isRequestedSessionIdValid() %><br /> </BODY> </HTML>

<span> 작성된 웹 애플리케이션을 tomcat1과 tomcat2에 배포한다. 이때 가장 중요한 것이 web.xml에 반드시 &lt;distributable/&gt;이라는 항목을 넣어 야 한다. 그럼 이제 테스트를 해보도록 하자. 먼저 아파치 웹서버, tomcat1, tomcat2를 차례로 실행시켜 보자. 그리고 <a class="smarterwiki-linkify" href="http://ipaddress/lbtest/index.jsp" style="color: rgb(92, 129, 167); ">http://ipaddress/lbtest/index.jsp</a> 접속하여 세션 객체를 생성해보자. 결과 화면은 그림 1과 같다. 여기서 요청된 세션ID를 보면 뒤에 어떤 톰캣에 접속한 상태인지를 알 수 있다. 이 화면상에서는 tomcat2에 접속한 세션이다. 그럼 tomcat2를 강제로 종료시켜 보도록 하자. 종료 후 화면에 보이는 “여기”를 계속 눌러 보자. 분명히 tomcat2가 종료되었음에도 불구하고 세션 값이 유지되고 있음을 알 수 있다. 이젠 반대로 tomcat2를 다시 실행시킨 후에 tomcat1을 종료시켜 보도록 하자. 역시 마찬가지로 세션 정보가 유지되는 것을 확인할 수 있을 것 이다. </span>test 결과화면
그림 1. 테스트 결과 화면

이상으로 톰캣을 이용한 로드밸런싱과 세션 클러스터링에 대해서 알아보았다. 일반적으로 로드밸런싱과 클러스터링은 성능 향상이라는 측면과 안정성 확보에 그 목적을 가지고 있다. 물론 고가의 상용 웹 어플리케이션 서버에 비하면 많이 부족하고 하드웨어를 이용한 로드밸런싱과 클러스터링에 비하면 안정성이 떨어질 수도 있지만 저렴한 비용으로 최대의 안정성과 성능을 얻고자 한다면 한번쯤 시도해 볼만한 좋은 기능이라고 할 수 있다. 아무쪼록 리눅스, 아파치, 톰캣 그리고 오픈소스를 통해 즐거운 웹 어플리케이션 개발 환경을 느껴보기 바란다.




위로


참고 자료
The Apache Tomcat Connector: http://tomcat.apache.org/connectors-doc/ 
Clustering/Session Replication HOW-TO: http://tomcat.apache.org/tomcat-5.5-doc/cluster-howto.html 


dW의 관련 기술 자료
Jakarta Tomcat을 갖춘 개발 환경으로서의 Eclipse (한글)

:
Posted by 라면스프
2010. 5. 12. 21:19

[Java] CallableStatement 예제 Enjoy/JAVA2010. 5. 12. 21:19


[Java]
CallableStatement
CallableStatement Sample   Java / Program  
 
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class CallableStatementDemo {
 public static void main(String[] args) {
  try {
   Class.forName("oracle.jdbc.driver.OracleDriver");
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  Connection con = null;
  CallableStatement cstmt = null;
  ResultSet rs = null;
  
  try {
   con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
   cstmt = con.prepareCall("{call adjust(?,?)}");
   cstmt.setString(1, "kts8395");
   cstmt.setFloat(2, 0.3f);
   cstmt.executeUpdate();
  } catch (SQLException e) {
   // TODO: handle exception
   e.printStackTrace();
  } finally {
    try {
     if(rs != null) rs.close();
     if(cstmt != null) cstmt.close();
     if(con != null) con.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
  }
 }
}






=======================================================


function 에서 Java로 cursor 넘기기   ORACLE  
=========================
1. ORACLE 처리
=========================

create or replace package types
as
    type cursorType is ref cursor;
end;
/


create or replace function sp_ListEmp return types.cursortype
as
    l_cursor    types.cursorType;
begin
    open l_cursor for select ename, empno from emp order by ename;
    return l_cursor;
end;
/



=========================
2. JAVA Program
=========================

import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;

public class ReturnCursor
{

  public static void main (String args [])
                     throws SQLException, ClassNotFoundException
  {
  String driver_class = "oracle.jdbc.driver.OracleDriver";
      String connect_string = "jdbc:oracle:thin:@211.111.111.111:1521:sid";
      String query = "begin ? := sp_listEmp; end;";
      Connection conn;
      Class.forName(driver_class);


      conn = DriverManager.getConnection(connect_string, "id", "passwd");
      CallableStatement cstmt = conn.prepareCall(query);
      cstmt.registerOutParameter(1,OracleTypes.CURSOR);
      cstmt.execute();
      ResultSet rset = (ResultSet)cstmt.getObject(1);
      while (rset.next ())
        System.out.println( rset.getString (1) + "\t" + rset.getInt (2) );
      cstmt.close();

  }
}



========================================================================================




CallableStatementTest.java(CallableStatement 예제)
 
: CallableStatement는 SQL의 스토어드프로시저(Stored Procedure)를 실행시키기 위해
  사용되는 인터페이스

 
import java.sql.*;
public class CallableStatementTest{
   public static void main(String[] args){
       try{
          Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
          Connection con = DriverManager.getConnection("jdbc:odbc:dbdsn", "id", "password");
          CallableStatement cs = con.prepareCall("{call myStoredProcedure(?,?,?)}");
          cs.setInt(1,2);
          cs.registerOutParameter(2, java.sql.Types.VARCHAR);
          cs.registerOutParameter(3, java.sql.Types.INTEGER);
          cs.execute();
          System.out.println("*name : "+ cs.getString(2) +"*age : "+ cs.getInt(3));
          cs.close();
          con.close();
       }catch(Exception e){System.out.println(e);}
   }
}




/*
create or replace function employ_ename (e_empno in emp.empno%TYPE) return varchar2 
is 
e_ename 

varchar2(10) := '홍길동'; 
begin 
  select ename into e_ename from emp 
  where  empno = e_empno; 
  return e_ename; 
exception 
  when no_data_found or too_many_rows then 
       return e_ename; 
end; 
*/
import java.sql.*;
public class TestCallable {
    public static void main(String args[]) throws Exception {

//예외처리를  main(String args[]) throws Exception 처름 하지 마세요

//여기서는 흐름을 쉽게 보이기 위해서 사용한 것입니다.
        String driverClass = "oracle.jdbc.driver.OracleDriver";
        String Url             = "jdbc:oracle:thin:@localhost:1521:sid";
        String User          = "scott";
        String Pwd           = "*****";
        
        Class.forName(driverClass);
        Connection conn = DriverManager.getConnection(Url,User,Pwd);
        // call 함수명
        String call = "{? = call employ_ename(?) }";
        int result = 0;
        
        CallableStatement c = conn.prepareCall(call);
        
        // IN parameter설정
        c.setInt(2, 7566);
        
        // Out parameter의 Type설정
        c.registerOutParameter(1, java.sql.Types.VARCHAR );
        
        // CallableStatement실행
        c.executeUpdate();
        
        // Out parameter의 값을 얻고, 출력한다.
        System.out.println("result : " + c.getString(1));
        conn.close();        
    }  

:
Posted by 라면스프
2010. 5. 4. 09:50

[Java] javadoc(API 문서) 작성 Enjoy/JAVA2010. 5. 4. 09:50



* API 문서작성 주석문
※ '@태그'를 사용한다.
@author : 클래스나 인터페이스의 제작자 표시 
@version : 버전정보 
@return : 메소드가 void형이 아닌경우 return value type을 기술 
@exception : 메소드가 발생 시킬수 있는 예외를 기술 
@throws : @exception Tag와 동일 
@deprecated : 다음버전에서 폐기된 메소드를 알림 
@param : 매개변수에 대한 설명(@param 변수 설명의 형태) 
@serial : 기본적으로 직렬화 할 수 있는 클래스의 멤버를 설명 
@see : 어떤 클래스 , 인터페이스,메소드, 생성자 혹은 URL에 대한 전후참조표시 
@since : Tag를 가진 객체가 언제 추가 되었는지 명시 

* API 문서작성법
javadoc -d . 소스파일.java

* 예제

/** 
* 자바 API문서 만들기 예제 소스 
*  
* @author 별소리
* @version 1.0 
*   
*/

public class JavaDocTest 
{
 /** 기본 생성자
 */
 public JavaDocTest()
 {
  //내용 없는 기본 생성자
 }


 /** 메서드입니다. 단순히 문자열을 프린트합니다.
 */
 public void printTest()
 {
  System.out.println("Hello World!");
 }


 /** 실행 main 메서드
 */

 public static void main(String[] args) 
 {
  new JavaDocTest().printTest();
 }
}



이를 [ javadoc -d . JavaDocTest.java ]로 컴파일하면...

이런 식으로 익숙한 형태의 API 문서가 만들어집니다.

:
Posted by 라면스프
2010. 4. 22. 18:44

회식 맛집 It's Me2010. 4. 22. 18:44

:
Posted by 라면스프

온더보더 3만원이상 결제시 1만원 할인권

신한카드 결제시 사용 가능

:
Posted by 라면스프
2010. 4. 22. 10:36

타임스퀘어 e-쿠폰 30종 (~4.30) It's Me/쿠폰2010. 4. 22. 10:36

:
Posted by 라면스프

3인 이상 방문시 사용 가능

:
Posted by 라면스프
2010. 4. 22. 10:32

매드포갈릭쿠폰4가지(~4/30) It's Me/쿠폰2010. 4. 22. 10:32

4월이 얼마 안 남았지만...


:
Posted by 라면스프