[JSP & Servlet 배경지식] 2. WS & WAS / Container 2014-09-19

1. Web Server & Web Application Server

> 동적웹페이지를 서비스 하기 위해서는  WAS(웹 어플리케이션 서버)가 필요하다. 하지만 정의하는 기준에 따라 다르게 어떤건 WAS가 아니라고 하는 경우가 있지만 이는 해석하는 기준의 차이므로 무의미한 논쟁일 뿐이다. 일반적인 정의에 대하여 정리해 보자

>>> 웹 서버 (Web Server)
ex) Apache, Nginx, IIS, WebtoB 등
- 클라이언트의 요청을 받아 정적인페이지(웹페이지, 이미지)를 HTTP 프로토콜을 통해 전송한다.
- 클라이언트의 요청 중 자체적으로 처리할 수 없는 정보에 대해서는 WAS에 처리를 요청한다.
- 요청이 많을 경우 웹서버에서는 웹문서를 WAS에서는 JSP페이지를 양분하여 처리 함으로서 서버
의 부담을 줄여주는 역할도 한다.
>>> 웹 어플리케이션 서버 (Web Application Server)
ex) Tomcat, WebLogic, WebSphere, Jeus, JBoss 등
- 웹서버에서 처리할 수 없는 동적인 정보를 처리하여 웹서버에 정적인 정보를 제공한다.
- 일반적으로 웹서버의 기능을 내제하고 있어 웹 서버 없이도 서비스가 가능하다.
- PHP의 경우 WAS의 역할을 하지만 웹서버의 모듈형태로 작동하므로 WAS라 불리는데 이견이 많다.
- WAS의 내부 구조

was의 내부동작

>>>>>> description
– WAS의 내부구조
① 웹서버로 부터 요청이 들어오면 제일먼저 컨테이너가 이를 알맞게 처리한다.
② 컨테이너는 배포서술자(web.xml)를 참조하여 해당 서블릿에 대한 스레드를 생성하고 요청(httpServletRequest) 및 응답(httpServeletResponse) 객체를 생성하여 전달한다.
③ 다음으로 컨테이너는 서블릿을 호출(service())한다.
④ 호출된 서블릿의 작업을 담당하게 된 스레드(미리 생성된 스레드)는 요청에 따라 doPost() 또는 doGet()을 호출한다.
⑤ 호출된 doPost() 또는 doGet() 메소드는 생성된 동적페이지를 Response객체에 실어서 컨테이너에 전달한다.
⑥ 컨테이너는 전달받은 Response객체를 HTTPResponse형태로 전환하여 웹서버에 전달하고 생성되었던 스레드를 종료하고 요청(httpServletRequest) 및 응답(httpServeletResponse) 객체를 소멸시킨다.

2. Container

WAS별로 다양한 종류의 컨테이너를 내장하고 있으며 이들중 서블릿에 관련된 기능을 모아놓은 것을 서블릿 컨테이너라 부른다. 이외에도 여러 종류의 컨테이너가 있으며(Servlet 컨테이너, JSP 컨테이너, EJB 컨테이너 등)  다양한 컴포넌트 들을 내장하고 있다.

>>> 서블릿 컨테이너 (Servlet Container)
서블릿 컨테이너는 [그림:WAS의 내부 구조]에서와 같이 servlet를 실행하고 관리하는 역할을 하는데 개발자가 신경써야 할 복잡한 부분을 대신 처리하여 주기 때문에 편리하다. 한가지 예로 자바애플리케이션 개발시 필요한 main()메소드가 존재하지 않는 것이 이때문이다. 다음은 서블릿 컨테이너의 주된 역할이다.
- 생명 주기 관리 : 서블릿을 로드해 초기화(init 메소드) 한다. 또 클라이언트의 요청으로 서블릿 메소드를 호출하며, 서블릿 컨테이너가 종료되면 서블릿을 종료시키고(destroy 메소드 호출) 메모리를 정리한다.
- 통신 지원 : 웹서버로부터 받은 요청을 분석해 서블릿을 실행시키고 서블릿에서는 웹서버의 정보를 확인할 수 있도록 하는 기능을 제공한다.
- 멀티스레딩 지원 : 클라이언트의 요청에 따라 서블릿을 생성하고, 이미 생성된 서블릿에 대한 요청은 스레드를 생성해 실행한다.
>>> 컴포넌트 (Component)
- 특정 기능이나 관련된 기능이 재사용 가능한 형태로 만들어진 프로그램 빌딩 블록으로 소프트웨어 개발을 레고 블록 쌓듯이 진행할 수 있도록 하는 기술을 말한다.

[JSP & Servlet 배경지식] 1. 동적인 웹 페이지를 위한 CGI 2014-09-19

> 사용자는 브라우저를 켜고 원하는 웹사이트에 들어가 정보를 조회 한다. 하지만 웹사이트에서 모든 정보를 조회할 수 있는 것은 아니다. 권한을 부여받고 인증을 거쳐야 하는 정보도 있다. 사용자가 정보를 요청하면 다른서버에 데이터를 조회 해야하는 경우도 있다. 즉, 동적인 웹페이지를 나타내야 할 필요가 있고, 이를 위해 CGI(Common Gateway Interface)가 존재하며, 이를 이용하여 동적인 페이지를 HTML형태의 정적인 페이지화 하여 브라우저로 전송 받는다. CGI에 대한 자세한 설명은 위키 참고 [CGI : 공용 게이트웨이 인터페이스]

>>> 정적인 웹 페이지 : 서버에 이미 저장되어있는 페이지
ex) 단순 정보 알림페이지를 보여준다.

정적 웹페이지

>>>>>> description
– 정적웹페이지를 호출하는 과정
① 클라이언트가 웹서버에 정보를 요청한다.
② 웹서버는 이미준비되어 있는 정보를 조회한다.
③ 조회된 정보를 응답한다.
④ 응답받은 데이터를 브라우저가 해석하여 사용자에게 보여준다.
>>> 동적인 웹 페이지 : 요청된 정보를 처리 또는 서버의 정보를 조회하여 실시간으로 만들어진 페이지
ex) 상황별 또는 사용자별로 다른 페이지를 보여준다.

동적 웹페이지

>>>>>> description
– 동적웹페이지를 호출하는 과정
① 클라이언트가 웹서버에 정보를 요청한다.
② 웹서버는 웹어플리케이션서버에 클라이언트의 요청대로 처리를 의뢰한다.
③ 요청값을 구현된 로직 또는 연결된디비와의 통신을 통해 처리한다.
④ 처리된결과를 정적인형태로 웹서버에 반환한다.
⑤ 웹어플리케이션서버로 부터 받은 결과를 가공하여 응답한다.
⑥ 응답받은 데이터를 브라우저가 해석하여 사용자에게 보여준다.

 

[CentOS 7] step5. 서비스 설정 2014-09-02

1. Database

> MySQL 또는 MariaDB, MongoDB 기반 서비스를 설정한다.

>>> MySQL or MariaDB
## root 암호 등록
mysqladmin -u root password "[PASSWORD]"
## 개발 디비 생성
mysql -u root -p [PASSWORD]
create database {생성할 디비명} collate 'utf8_general_ci';
## 개발 디비 사용자 생성
create user '[ID]'@'localhost' identified by '[PASSWORD]';
grant all privileges on {생성할 디비명}.* to '[ID]'@'localhost';
flush privileges;
## 개발 디비 외부접근 사용자 생성
create user '[ID]'@'{접속할IP}' identified by '[PASSWORD]';
grant all privileges on {생성할 디비명}.* to '[ID]'@'{접속할IP}';
flush privileges;
>>>>>> description
– 개발에 사용할 디비 생성시 꼭 사용자를 따로 생성하여 권한을 부여
>>> MongoDB
## 관리자 계정 생성
mongo
use {사용할디비명}
db.createUser( { "user" : "[ID]","pwd": "[PASSWORD]", roles: [ "readWrite", "dbAdmin" ]})
show users
exit
## 인증 후 디비접속이 가능하도록 설정
vi /etc/mongod.conf
service mongod restart
## 개발 디비 생성
use {생성할 디비명}
## 개발 디비 사용자 생성
db.createUser( { "user" : "[ID]","pwd": "[PASSWORD]", roles: [ "readWrite" ]})
## 사용자 로그인
db.auth({"user" : "[ID]","pwd": "[PASSWORD]"});
## 사용자 비번 변경
db.changeUserPassword("[ID]", "[PASSWORD]")
## /etc/mongod.conf
auth=true
httpinterface=true
>>>>>> description
– 기본설치시 로그인 과정없이 디비에 접속됨
– 개발에 사용할 디비 생성시 꼭 사용자를 따로 생성하여 권한을 부여

2. Cache

> Redis, Memcached 기반 서비스를 설정한다.

>>> REDIS
vi /etc/redis.conf
## REDIS를 데몬으로 실행
daemonize yes
## REDIS를 PASSWORD인증 후 실행
requirepass {PASSWORD}
>>>>>> description
– REDIS는 지속성이 보장됨.(database로 활용이 가능)
– RDB, AOF의 두가지 형태의 데이터베이스로 활용 가능
– 데이터베이스로 활용시 REPLICATION 구성이 가능
>>> MEMCACHED
vi /etc/sysconfig/memcached
OPTIONS="-l {접속허용IP}"
>>>>>> description
– 인증기능 및 지속성을 제공하지 않음
– IP로 접속을 제한할 수 있음

3. World Wide Web

> JSP(Java server page) 또는 PHP(Personal Hypertext Preprocessor) 기반으로 웹서비스를 설정한다.

>>> JSP : Apache + Tomcat
## 연동설정 : mod_jk 설치
#### -- connector 다운로드
cd /usr/local/src
wget http://server.opendocs.co.kr/tomcat-connectors-1.2.40-src.tar.gz
#### -- 컴파일 & 설치
tar -xvf tomcat-connectors-1.2.40-src.tar.gz
cd tomcat-connectors-1.2.40-src/native
./configure -with-apxs=/usr/bin/apxs
make
make install
#### -- 공통 설정
vi /etc/httpd/conf.modules.d/00-base.conf
vi /etc/httpd/conf/httpd.conf
vi /etc/httpd/conf.d/mod_jk.conf
vi /etc/httpd/conf/workers.properties
#### -- 프로젝트 폴더 생성
mkdir /var/www/{PROJECT_NAME}-api
#### -- manager 복사
cp -R /usr/local/apache-tomcat-8.0.21/webapps/manager /var/www/{PROJECT_NAME}-api
#### -- apache 호스트 설정(conf.d 폴더의 전체 파일은 자동 인클루드됨)
vi /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### -- tomcat 호스트 설정
vi /usr/local/apache-tomcat-8.0.21/conf/server.xml
vi /usr/local/apache-tomcat-8.0.21/conf/Catalina/localhost/ROOT.xml
#### -- manager 설정
vi /usr/local/apache-tomcat-8.0.21/conf/tomcat-users.xml
## 공통 : /etc/httpd/conf.modules.d/00-base.conf
LoadModule jk_module modules/mod_jk.so
## 공통 : /etc/httpd/conf/httpd.conf
DirectoryIndex index.jsp
## 공통 : /etc/httpd/conf.d/mod_jk.conf
<IfModule jk_module>
     JkWorkersFile /etc/httpd/conf/workers.properties
     JkShmFile /var/log/httpd/mod_jk.shm
     JkLogFile /var/log/httpd/mod_jk.log
     JkLogLevel info
     JkLogStampFormat "[%a %b %d %H:%M:%S %Y]"
</ifModule>
## 공통 : /etc/httpd/conf/workers.properties
worker.list={PROJECT_NAME_1}, {PROJECT_NAME_2},...
#### 포트번호는 server.xml 파일의 AJP/1.3 프로토콜 컨넥터와 일치 시킴
worker.{PROJECT_NAME_1}.port=8009
worker.{PROJECT_NAME_1}.host={localhost or 외부서버IP}
worker.{PROJECT_NAME_1}.type=ajp13
worker.{PROJECT_NAME_1}.lbfactor=20
worker.{PROJECT_NAME_2}...
## 프로젝트별 : /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### {PROJECT_NAME}-api
<VirtualHost *:80>
     DocumentRoot /var/www/{PROJECT_NAME}-api
     ServerName api.{PROJECT_DOMAIN}
     JkMount /* {PROJECT_NAME_1}
     ErrorLog logs/error_log_{PROJECT_NAME}-api
     CustomLog logs/access_log_{PROJECT_NAME}-api common
     <Directory "/var/www/{PROJECT_NAME}-api">
          AllowOverride All
          Order Allow,Deny
          Allow From All
     </Directory>
</VirtualHost>
## /usr/local/apache-tomcat-8.0.21/conf/server.xml
<Engine name="Catalina">
   <Host name="api.{PROJECT_DOMAIN}"  appBase="/var/www/{PROJECT_NAME}-api" unpackWARs="true" autoDeploy="true">
      <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
            prefix="access_log_{PROJECT_NAME}-api." suffix=".txt"
            pattern="%h %l %u %t &quot;%r&quot; %s %b" />
   </Host>
</Engine>
## /usr/local/apache-tomcat-8.0.21/conf/Catalina/{localhost or 외부서버IP}/ROOT.xml
<?xml version='1.0' encoding='utf-8'?>
<!-- default virtual host\ROOT -->
<Context path="/" docBase="" reloadable="true">
</Context>
## /usr/local/apache-tomcat-8.0.21/conf/tomcat-users.xml
<tomcat-users>
   <role rolename="manager-script"/>
   <role rolename="manager-gui"/>
   <role rolename="manager-jmx"/>
   <role rolename="manager-status"/>
   <user username="manager" password="xxxxxxxxx" roles="manager-script,manager-gui,manager-jmx,manager-status"/>
</tomcat-users>
>>>>>> description
– 연동이 필요한 이유
==> Tomcat은 서블릿 컨테이너의 역할만 하고 Apache는 웹서버의 역할을 하여 기능을 분리
==> Apache에서 제공하는 편리한 기능을 사용할 수 있음
==> 부하 분산의 효과를 가질 수 있음(mod_jk의 Load Balancing과 FailOver기능을 사용)
– 연동에는 세가지 방법이 있다
==> mod_jk : 가장 많이 사용하므로 자료가 많고 유연한 설정이 가능 하나 톰캣에서만 사용이 가능함
==> mod_proxy or mod_proxy_ajp : 별도 설치가 필요없어 설치 및 설정이 간편하고 특정 WAS에 의존적이지 않음
– TOMCAT에서 제공하는 관리기능을 활용하면 배포, 상태 확인 등을 편리하게 할 수 있다. ({MANAGER_DOMAIN} 연결)
>>> PHP : Apache + PHP
#### -- 아파치 설정
vi /etc/httpd/conf.d/{PROJECT_NAME}.conf
#### -- PHP 설정
vi /etc/php.ini
## /etc/httpd/conf.d/{PROJECT_NAME}.conf
<VirtualHost *:80>
     DocumentRoot /var/www/{PROJECT_NAME}
     ServerName {HOSTNAME}
     ErrorLog logs/error_log_{PROJECT_NAME}
     CustomLog logs/access_log_{PROJECT_NAME} common
     <Directory "/var/www/{PROJECT_NAME}">
          AllowOverride All
          Order allow,deny
          Allow from all
     </Directory>
</VirtualHost>
## /etc/php.ini
#### <? 에 php 없이 설정 : 개발편의성
short_open_tag = On
#### timezone 설정
date.timezone = Asia/Seoul
>>>>>> description
– 프로젝트의 필요성에 따라 apache에서 제공하는 많은 모듈들을 적절히 활용할 수 있음
>>> NodeJS : Apache + NodeJS
## 시작 / 종료 / 재시작 스크립트 작성
vi /etc/init.d/{PROJECT_NAME}
## 실행권한 변경
chmod 755 /etc/init.d/{PROJECT_NAME}
## 시작시 자동실행
chkconfig --add {PROJECT_NAME}
chkconfig --level 234 {PROJECT_NAME} on
## 서비스 시작
service {PROJECT_NAME} start
## /etc/init.d/{PROJECT_NAME}
#!/bin/bash
# description: {PROJECT_NAME} Start Stop Restart
# processname: {PROJECT_NAME}
# chkconfig: 234 20 80 

case $1 in
start)
# 시작
forever start -a -l forever.log -o out.log -e err.log /var/www/{PROJECT_NAME}/app.js
;;
stop)
# 종료
forever stop /var/www/{PROJECT_NAME}/app.js
;;
restart)
# 재시작
forever stop /var/www/{PROJECT_NAME}/app.js
forever start -a -l forever.log -o out.log -e err.log /var/www/{PROJECT_NAME}/app.js
;;
esac
exit 0
>>>>>> description
– nodejs의 경우 오류 발생시 프로세스가 바로 죽게됨
– forever 모듈을 사용하여 운영함