내용 목차
본 장에는 웹 애플리케이션의 성능 향상을 위한 JEUS WebCache를 적용하는 방법에 대해 설명한다.
동시 요청자 수의 증가로 인하여 응답 속도가 떨어지는 등의 웹 애플리케이션 성능 저하 문제가 발생한다면 하드웨어 측면과 소프트웨어 측면에서 해결할 수 있다.
하드웨어 측면의 해결 방법은 서버를 증설하여 계속 들어오는 요청(request)을 Load Balancing하여 부하를 분산시켜 응답 속도를 높이는 방법이다. 그러나 이 방법은 서버 추가에 대한 비용 증가와 클러스터링 등으로 인한 서버 운용 및 관리의 복잡함을 발생시킬 수 있다.
소프트웨어 측면의 해결 방법은 서버의 증설 없이 웹 애플리케이션에서 많이 사용되는 데이터를 Caching하는 것이다. 그러면 다음 요청에서는 데이터의 재생산 없이 Caching된 데이터를 이용함으로써 웹 애플리케이션의 응답시간을 줄여서 성능을 향상시킬 수 있다.
본 장에서는 JEUS 시스템에서 웹 애플리케이션의 성능 향상을 위해서 JEUS WebCache를 어떻게 적용할 수 있는지에 대해서 설명한다. 제공되는 Caching 방법은 다음과 같다.
JEUS WebCache에 Caching되는 엔트리는 SoftReference로 구현되어있다. 그래서 심각한 메모리 증가로 인한 OutOfMemory 에러를 미연에 방지할 수 있다.
Caching 기능을 효과적으로 사용하기 위해서 빈번하게 요청되거나, 수행 로직이 복잡해서 또는 데이터베이스로부터 데이터를 가져오는 시간이 오래 걸려 응답시간이 길어질수 있는 웹 페이지를 Caching 대상으로 선택하는 것이 바람직하다.
JSP Caching은 JSP 태그 라이브러리를 사용하여 JSP 페이지 내의 일부분을 JEUS WebCache에 저장함으로써 웹 애플리케이션의 성능을 향상시키는 방법이다.
JEUS WebCache에서는 사용자 정의(custom) 태그로 <jeus:cache>를 사용한다.
<jeus:cache> 내에 JSP 페이지 내에서 Caching을 원하는 콘텐츠가 있는 부분을 입력하면 첫 번째 요청에서 태그 내의 바디 콘텐츠(Body Contents)가 생성되어 브라우저에 전송되고 이 콘텐츠는 Caching된다. 다음 요청부터는 메모리에 Caching된 콘텐츠가 브라우저로 보내진다.
<jeus:cache> 태그를 사용하는 기본적인 형식은 다음과 같다.
<%@ taglib uri=”http://www.tmaxsoft.com/jeuscache” prefix=”jeus” %> <jeus:cache name=”...” key=”...” scope=”...” timeout=”...” size=”...” async=”...” df=”...”> . . . Body content to be cached. . . </jeus:cache>
위 설명에서 제외된 flush 속성은 닫힌 태그(/>)를 사용하는데 속성에 대한 설명은 “7.2.2. <cache> 태그”를 참고한다.
JSP Caching에서 사용하는 알고리즘은 LRU이다. 그래서 JEUS WebCache 최대 허용 개수를 초과하면 LRU 알고리즘에 의해서 기존에 Caching된 엔트리가 제거된다.
그리고 TLD(Tag Libarary Descriptor) 파일은 jeus.jar 파일에 포함되어 배포된다. jeuscache.tld 파일에 대한 URI 정보를 JSP 엔진에 전달하기 위해서 <jeus:cache> 태그 내의 'taglib uri'를 반드시 'http://www.tmaxsoft.com/jeuscache'으로 명시해야 한다.
다음은 'name' 속성, 'name' 속성 + 'key' 속성을 사용하여 엔트리를 Caching할 때 사용하는 자료 구조이다.
위 그림에서 Name1, Name3은 'key' 속성 없이 'name' 속성만으로 태그를 사용할 때 엔트리가 Caching되는 방식이며 'key' 속성은 물론 'name' 속성까지도 사용되지 않을 때도 이 방식이 사용된다. 그러나 'name' 속성과 'key' 속성 모두가 사용되는 태그에서는 Name2와 같은 방식으로 엔트리가 Caching된다.
<jeus:cache> 사용자 태그를 정의한 파일은 jeuscache.tld로 이 파일은 jeus.jar 내에 포함되며 위치는 다음과 같다.
jeus/servlet/cache/resource/jeuscache.tld
다음은 jeuscache.tld 파일의 <cache> 태그의 설정 예제이다.
[예 7.1] <cache> 태그 설정 : <<jeuscache.tld>>
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>jeuscache</short-name> <uri>http://www.tmaxsoft.com/jeuscache</uri> <display-name>JEUSCache Tag Library</display-name> <tag> <name>cache</name> <tag-class>jeus.servlet.cache.web.tag.CacheTag</tag-class> <body-content>JSP</body-content> <description>JEUS WebCache</description> <attribute> <name>flush</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>timeout</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>scope</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>name</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>size</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>key</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>async</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>df</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
다음은 각 태그를 설정할 때 각 속성에 대한 설명이다.
본 절에서는 예제를 사용하여 <jeus:cache> 태그 속성의 사용 방법을 설명한다.
다음은 cache.jsp 페이지를 요청하는 경우 현재 날짜와 caching된 날짜를 비교해보는 간단한 예제이다.
[예 7.2] <jeus:cache> 사용 예제 : <<cache.jsp>>
<%@ taglib uri=”http://www.tmaxsoft.com/jeuscache” prefix=”jeus” %> <HTML> <BODY> Current time: <%= new Date() %><br> <jeus:cache timeout="60s"> Cached time: <%= new Date() %> </jeus:cache> </BODY> </HTML>
<jeus:cache> 태그의 첫 번째 요청에서는 현재 날짜를 구하여 화면에 출력하고 JEUS WebCache에 저장된다. 다음 호출부터는 caching된 날짜가 출력될 것이다. 60초가 지난 다음에는 갱신된 날짜가 출력된다.
다음은 <jsp:include>를 사용하여 다른 페이지를 포함할 때 <jeus:cache> 태그를 사용하는 예이다.
[예 7.3] jsp:inclue를 이용한 <jeus:cache> 사용 예제 : <<main.jsp>>
<HTML>
<BODY>
<jsp:include page="cache.jsp"/>
</BODY>
</HTML>
main.jsp에 include된 cache.jsp 내의 <jeus:cache> 태그의 내용은 cache.jsp만 사용하는 첫 번째 예제와 동일한 수행 결과를 출력한다.
flush 기능은 caching된 엔트리를 강제로 제거하는 기능이다. 대상이 되는 엔트리를 지정하는 'name' 속성 또는 'name' 속성 + 'key' 속성을 반드시 명시해야 한다.
예를 들어 다음과 같이 'name' 속성 + 'key' 속성을 사용해서 stock content를 caching했다고 가정하자.
<jeus:cache name="stock" key="parameter.company" scope="application"> . . . stock content . . . </jeus:cache>
caching된 parameter.company에 해당하는 stock content를 제거하기 위해서는 다음과 같이 설정한다.
<jeus:cache name="stock" key="parameter.company" scope="application" flush=”true”/>
위와 같이 flush 기능을 성공적으로 수행했다면 다음 <jeus:cache> 태그 내의 stock content를 요청하는 경우에는 갱신된 stock content를 보게 된다. 만일 위 flush 속성을 다음과 같이 'key' 속성 없이 'name' 속성만을 사용한다면 parameter.company key 속성으로 저장된 모든 엔트리가 제거될 것이다.
<jeus:cache name=“stock” scope=”application” flush=”true”/>
물론 'key' 속성을 사용하지 않고 'name' 속성만으로 엔트리를 caching했다면 'name' 속성만 사용하면 된다.
모든 <jeus:cache> 태그를 호출할 때마다 바디 콘텐츠를 생성하게 하는 refresh 기능을 제공한다. 이 기능은 <jeus:cache> 태그 속성을 사용하지 않는다. 대신 '_jeuscache_refresh'를 key로, true를 값으로 해서 원하는 scope에 설정할 수 있다.
애플리케이션과 세션 scope의 모든 엔트리를 refresh하기 위해서는 다음과 같이 각각 작성한다.
<% application.setAttribute("_jeuscache_refresh", "true"); %> <% session.setAttribute("_jeuscache_refresh", "true"); %>
이 기능은 <jeus:cache> 태그에 접근했을 때 각각의 scope에 '_jeuscahe_refresh' 값을 조사하여 true일 경우 그 바디 콘텐츠를 갱신한다. 그리고 더 이상 refresh 기능을 사용하지 않기를 원한다면 '_jeuscahe_refresh'을 false로 지정한다. 'timeout', 'flush' 속성을 사용하면 하나 또는 일부분의 갱신된 엔트리를 볼 수 있는 반면, refresh기능을 사용하면 설정한 scope 내의 모든 바디 콘텐츠가 매번 갱신된다.
JEUS WebCache는 Servlet Filter를 사용하여 HTTP 응답 전체를 caching하는 방법으로 HTTP Response Caching 기능을 제공한다.
페이지 내용이 동적으로 변하는 웹 페이지에는 적절하지 않으며 정적 콘텐츠에 대한 HTTP 요청에 적합한 방법이다. 이미지 파일, PDF 등의 바이너리 콘텐츠를 요구하는 HTTP 요청이 여기에 해당된다. 물론 일정 시간 동안 웹 페이지의 내용이 변경되지 않거나 변경사항이 반영되지 않아도 되는 웹 페이지에도 이 방법을 사용할 수 있다.
http://www.sample.com/filter/respcacheTest.jsp?key=value
위와 같이 key, value를 포함해서 전체 HTTP URI가 엔트리 키로 적용된다. 만일 key, value 값이 다양하게 변화한다면 각각의 URI에 해당하는 HTTP Response가 Caching된다.
HTTP Response의 상태가 200 OK(HttpServletResponse.SC_OK)인 경우에만 해당 HTTP Response가 Caching된다는 것이다. HTTP Response를 JEUS WebCache에 저장할 때 사용되는 엔트리 키로 HTTP URI가 사용된다.
본 절에서는 HTTP Response Caching을 웹 애플리케이션에 적용하는 방법에 대해 설명한다.
웹 애플리케이션에서 HTTP Response Caching을 사용하기 위해서는 web.xml에 필터를 등록한다.
다음은 <url-pattern>이 '/filter/'인 모든 HTTP 요청에 대한 HTTP 응답을 10분 동안 caching하는 예제이다.
<filter-class>로 반드시 jeus.servlet.cache.web.filter.CacheFilter 클래스를 사용해야 한다.
[예 7.4] 필터 설정 : <<web.xml>>
<web-app>
. . .
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>jeus.servlet.cache.web.filter.CacheFilter</filter-class>
<init-param>
<param-name>timeout</param-name>
<param-value>600</param-value>
</init-param>
<init-param>
<param-name>lastModified</param-name>
<param-value>on</param-value>
</init-param>
<init-param>
<param-name>expires</param-name>
<param-value>off</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheFilter</filter-name>
<url-pattern>/filter/*</url-pattern>
</filter-mapping>
. . .
</web-app>
다음은 필터 클래스에 전달하는 초기화 파라미터에 대한 설명이다.
위의 파라미터 외에 추가로 scope, size, async, df 등을 설정할 수 있는데, 이들은 “7.2. JSP Caching”에서 설명한 것과 동일한 의미를 가지고 있으므로 해당 부분을 참고한다.