내용 목차
본 장에서는 웹 애플리케이션의 성능 향상을 위한 Reverse Proxy의 기본 개념과 사용 방법을 예제를 통해 설명한다.
Reverse Proxy는 실제 요청을 처리하는 서버의 앞 단에 존재하며, 실제 서버로 들어오는 요청을 대신 받아서 해당 서버에 전달하고 그 결과를 받아서 요청한 곳으로 전달해주는 역할을 하는 서버를 의미한다. Reverse Proxy는 보안(실제 서버를 외부에 숨길 때) 및 부하 분산(여러 서버에서 요청을 처리할 때) 등의 이유로 필요하다.
example.com이라는 회사가 인터넷을 통해 접근이 가능한 public IP 주소와 DNS 엔트리를 가진 www.example.com이라는 웹 사이트를 가지고 있다고 가정하자.
이 회사는 또한 방화벽 내에 private IP 주소와 등록되지 않은 DNS 엔트리를 가진 여러 애플리케이션 서버를 가지고 있다. 이런 해당 네트워크 내의 애플리케이션 서버로 "internal1.example.com"과 "internal2.example.com"이 있다고 하자. 이 서버들은 public DNS 엔트리를 갖지 않으므로 회사 외부로부터 "internal1.example.com"으로 접근이 안되고 "no such host" 에러가 발생할 것이다.
그런데 이 애플리케이션 서버로 웹 접근을 해야 된다면 인터넷을 통해 직접적으로 Export할 수는 없고, 해당 웹 서버로 통합하기 위해 내부적으로 다음과 같이 매핑한다.
http://www.example.com/app1/any-path-here : http://internal1.example.com/any-path-here로 매핑한다.
http://www.example.com/app2/other-path-here : http://internal2.example.com/other-path-here로 매핑한다.
Reverse Proxy 사용을 위해 작성해야 하는 주요 파일은 다음과 같다.
파일명 | 설명 |
---|---|
web.xml | Reverse Proxy 기능을 하는 필터를 설정한다. 서버 내용이 있는 파일을 지정한다. |
jeus-web-dd.xml | <jeus-web-dd><context-path> 설정에 서비스를 제공하는 경로를 지정한다. |
config/data.xml | Reverse Proxy를 하는 서버를 지정한다. |
config/sample.xml | data.xml 파일 작성을 위한 샘플 파일이다. |
해당 파일들은 WEB-INF 디렉터리 하위에 위치한다.
Reverse Proxy를 사용하려면 ReverseProxy 기능을 활성화시키는 애플리케이션을 deploy해야 한다. 본 장의 예제에서는 애플리케이션의 이름을 ReverseProxy라고 가정한다.
다음은 Reverse Proxy 기능을 사용하기 위한 설정 과정이다.
Proxy 서버 설정
context-path 설정
Proxy 필터 설정
Deploy
Reverse Proxy 사용을 위해 먼저, ReverseProxy/WEB-INF/config/ 아래에 Proxy될 서버의 내용을 담은 data.xml 파일을 생성한다. 이 파일에서 설정하는 내용은 Proxy해야 할 실제적인 서버의 내용이다. Proxy할 서버의 주소와 이 서버로 서비스할 규칙(rule)을 설정할 수 있다. 실제로 사용자가 Proxy 서버를 설정할 때에는 “8.3. 설정 예”를 참고하여 항목을 수정해야 한다.
서버의 종류는 다음 2가지이다.
특정 요청에 대해서 하나의 서버를 Proxy할 때 설정한다.
<server>는 다음과 같은 하위 설정 항목을 가진다.
data.xml은 다음과 같은 내용의 문법 정의를 ReverseProxy/WEB-INF/config/proxy-config.dtd에 가지고 있어야 한다. 이 파일의 목적은 data.xml 파일의 정형성을 검증하는 것이다.
[예 8.1] data.xml의 dtd : <<proxy-config.dtd>>
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT config (single-server*, cluster-server*)> <!-- single-server: proxy로 오는 해당 요청 --> <!ELEMENT single-server (domain-name, send-proxy-specific-headers?, rewriting?, path?, (directory-rule|accept-everything-rule))> <!-- cluster-server: proxy로 오는 요청을 여러 서버에 round robin으로 보낼 때 설정 --> <!ELEMENT cluster-server (server*, (directory-rule|accept-everything-rule), send-proxy-specific-headers)> <!-- server: 클러스터된 하나의 서버를 말함 --> <!ELEMENT server (domain-name, path?)> <!-- directory rule: proxy 서버에 대한 요청을 구분하기 위한 규칙. 디렉터리명으로 구분한다. path를 "/dir"으로 설정하면 HOSTNAME/dir으로 요청에 맞는 server로 요청이 전달된다. --> <!ELEMENT directory-rule (path)> <!-- path: 디렉터리 설정 "/"로 시작한다. --> <!ELEMENT path (#PCDATA)> <!-- accept-everthing-rule: 모든 요청에 대해서 해당 서버로 요청을 전달하기 위한 규칙. 설정에서 가장 하위에 설정되어야 함 --> <!ELEMENT accept-everything-rule EMPTY> <!-- domain-name: 서버의 주소. HOSTNAME:PORT ex) www.server1.com, www.server2.com:9999 --> <!ELEMENT domain-name (#PCDATA)> <!--send-proxy-specific-headers: via 헤더, x-forwarded-* 헤더 사용 여부 결정. --> <!ELEMENT send-proxy-specific-headers (#PCDATA)> <!-- rewriting: proxy된 문서 내용 중 link들 중에 절대 주소를 rewriting할지 여부 결정. --> <!ELEMENT rewriting (#PCDATA)>
WEB-INF/jeus-web-dd.xml 파일의 <jeus-web-dd><context-path>를 수정하면 Proxy 서비스를 제공할 <context-path>를 설정할 수 있다. "/"로 설정하면 해당 서버의 아래의 모든 요청에 대해서 적용된다. 이에 대한 설정은 “3.3.1. jeus-web-dd.xml 설정”을 참고한다.
JEUS는 다음의 2가지 필터 클래스를 통해서 Reverse Proxy 기능을 제공하고 있다.
data.xml에 정의된 요청을 받아서 해당 서버의 결과를 전달하는 역할을 한다.
해당 서버에서 받은 결과물에서 링크를 자신의 주소로 Rewrite하는 역할을 한다.
예를 들어서 www.proxy.com/remote/index.html라는 요청에 www.server1.com/index.html을 요청자에게 보낸다고 할 때 실제 페이지 내용에 href="www.server1.com/links.html"과 같은 절대 주소나 href="/contents.html"과 같은 "/"로 시작하는 주소 등은 Proxy 서버의 주소에 알맞게 "www.proxy.com/remote/links.html"과 "/remote/contents.html"로 변경되어야 한다. 이렇게 html, javascript, css와 같은 문서 내의 주소를 변경하는 역할을 한다.
JEUS에서는 Proxy 필터만 사용하거나 Proxy 필터와 Rewriter 필터를 함께 사용할 수 있다. 각 경우에 따라 WEB-INF 디렉터리의 web.xml 파일을 다음과 같이 설정해야 한다.
Proxy 필터만 사용할 경우
[예 8.2] Proxy 필터만 사용할 경우 : <<web.xml>>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_1.xsd" version="3.1"> <display-name>j2ep</display-name> <description> A J2EE application implementing a reverse proxy. </description> <filter> <filter-name>Proxy</filter-name> <filter-class>jeus.servlet.reverseproxy.ProxyFilter</filter-class> <init-param> <param-name>dataUrl</param-name> <param-value>/WEB-INF/config/data.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Proxy 필터와 Rewrite 필터를 함께 사용할 경우
[예 8.3] Proxy 필터와 Rewrite 필터를 함께 사용할 경우 : <<web.xml>>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_1.xsd" version="3.1"> <display-name>j2ep</display-name> <description> A J2EE application implementing a reverse proxy. </description> <filter> <filter-name>Rewriter</filter-name> <filter-class>jeus.servlet.reverseproxy.RewriteFilter</filter-class> <init-param> <param-name>dataUrl</param-name> <param-value>/WEB-INF/config/data.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>Rewriter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>Proxy</filter-name> <filter-class>jeus.servlet.reverseproxy.ProxyFilter</filter-class> </filter> <filter-mapping> <filter-name>Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
위의 설정이 완료된 애플리케이션을 JEUS에 deploy한다. Deploy에 대한 자세한 내용은 “JEUS Applications & Deployment 안내서”의 “제4장 애플리케이션 작성 및 Deploy”를 참고한다.
다음은 몇 가지 경우에 대한 Reverse Proxy/WEB-INF/config/data.xml의 설정 예이다.
Proxy 서버의 호스트명이 "www.proxy.com"이고, 모든 요청에 대해서 "www.server1.com/content"를 Proxy할 "www.proxy.com/index.html"을 요청하면 "www.server1.com/content/index.html"의 내용을 출력하는 설정은 다음과 같다.
<config> <single-server> <domain-name>www.server1.com</domain-name> <send-proxy-specific-headers>true</send-proxy-specific-headers> <path>/content</path> <rewriting>true</rewriting> <accept-everything-rule/> </single-server> </config>
www.proxy.com/remote로의 요청은 www.server1.com을 proxy하고 www.proxy.com/internal로의 요청은 www.server2.com:8080을 proxy한다. 그외의 다른 요청에 대해서 www.server3.com을 proxy하는 설정은 다음과 같다.
<config> <single-server> <domain-name>www.server1.com</domain-name> <rewriting>true</rewriting> <directory-rule> <path>/remote</path> </directory-rule> </single-server> <single-server> <domain-name>www.server2.com:8080</domain-name> <rewriting>true</rewriting> <directory-rule> <path>/internal</path> </directory-rule> </single-server> <single-server> <domain-name>www.server3.com</domain-name> <rewriting>true</rewriting> <accept-everything-rule/> </single-server> </config>
모든 요청에 대해 www.server1.com/remote와 www.server2.com/remote로 proxy한다.
<config> <cluster-server> <server> <domain-name>www.server1.com</domain-name> <path>/remote</path> </server> <server> <domain-name>www.server2.com</domain-name> <path>/remote</path> </server> <accept-everything-rule/> <send-proxy-specific-headers>true</send-proxy-specific-headers> </cluster-server> </config>