잠깐 국내의 웹서비스와 사용자에 대하여 간단하게 이야기 해 볼까요. 일방문자가 10,000명이 되는 사이트의 경우는 시간당 약 420명, 분당 7명, 초당 0.1명 정도가 방문하게 됩니다. 평균적으로 한명의 방문자가 10페이지를 조회한다고 했을 경우에도 해당 사이트는 시간당 4,200 정도의 Transaction이 발생하게 됩니다. Peak-Time을 고려한다고 해도 그렇게 큰 숫자는 되지 않습니다. 안정성을 고려하지 않고 일반 Content 기반의 서비스라고 생각할때 Intel Pentium4 [2.0G] 정도의 중저급의 서버면 충분히 서비스 할수 있는 숫자입니다. 그리고 일방문자가 만명정도 되는 사이트는 국내에는 약 1500개정도 밖에 되지 않구요.
위와 같은 이유로 대부분의 국내사이트는 크게 성능과 로딩 속도가 문제가 되지 않습니다. 만약 문제가 된다면 프로그램을 잘못 작성했거나 아님 많은 수익을 발생하거나 둘중 하나 일것입니다. 그러나 메인페이지,DB 접속을 통하여 다량의 자료 검색을 해야 하는 경우 그리고 복잡한 연산을 수행하는 경우와 같은 Web Application 은 단일 요청에 대하여도 많은 부하와 이에 따른 결과로 로딩 속도가 느려지게 되어 원할한 서비스를 제공하는데 문제가 있습니다. 이런 경우에 Cache 기술을 유용하게 사용할 수 있습니다.
Cahce 기술은 아래와 같은 제한점이 있지만 잘 응용하게 되면 경쟁 사이트 보다 10배 더 빠르게 고객에서 나가갈수 있습니다.
- 일정 부분 실시간 서비스를 포기하여야 한다. ( lifetime 을 조정하여 페이지의 Refresh 간격을 설정하여야 한다. )
- 검색서비스와 같이 다양한 Query를 사용하는 경우는 적용할 수 없다.
본인의 경우는 검색 Query중에서 상위 N개에만 해당 기술을 적용하여 상당히 성능향상을 경험하였습니다. - 자료 등록과 MyPage 구현( 사용자별로 다른 페이지를 서비스하여야 하기 때문에 구현이 불가능하거나 상당히 복잡하다. )
demo.php
<?php require "lib/jmrss/URLCache.php"; // Cache 적용하기 Cache(true,"./cache",3600); // Database 연결 $conn = mysql_connect("mysql.ihelpers.co.kr", "xxxxx", "xxxxx"); mysql_select_db("xxxxx",$conn); $sql = "SHOW TABLES"; $result = mysql_query($sql,$conn); echo "<pre>"; while($row = mysql_fetch_array($result)){ print_r($row); } echo "</pre>"; mysql_close($conn); ?> |
기존의 Web Application에 Cache 모듈을 적용하는 방법은 상당히 간단합니다. URLCache.php 파일을 include 하고 Cache함수를 호출하면 됩니다. URLCache.php 파일은 사용자가 원하는 디렉토리에 두면 됩니다. Cache 함수의 첫번째 인자는 Cache 여부이며 두번째 인자는 Cache 디렉토리입니다. 해당 디렉토리 역시 원하는 곳으로 설정하면 됩니다. 셋번째 인자는 Cache의 lifetime 입니다.
require "lib/jmrss/URLCache.php";Cache(true,"./cache",3600);
위와 같이 설정 후에 최초로 URL이 호출이 되면 Cache디렉토리에 아래와 같이 Cache된 파일이 저장됩니다. 주의 할것은 저장하기 원하는 Cache 디렉토리는 미리 생성되어 있어야 합니다. 당연히 권한은 웹사용자의 쓰기 권한( chmod 766 ./cache )이 있어야 합니다. 사용자가 설정한 lifetime에 따라서 일정 시간 동안 Cache된 파일을 통하여 서비스가 되며, Cache파일은 설정된 lifetime을 주기로 갱신됩니다. Cache 파일명은 호출된 URL를 MD5 함수로 인코딩한 값입니다.
lsh804:~/www/cache$ ls -al total 12 drwxr-sr-x 2 ihelpers ihelpers 4096 11¿u 2 00:17 ./ drwxr-s--x 26 ihelpers ihelpers 4096 11¿u 2 00:15 ../ -rw-r--r-- 1 ihelpers ihelpers 2526 11¿u 2 00:17 0736bf2173b64ba30a47079fd0670e54 |
2. URLCache.php Class
URLCache.php 파일은 URLCache 클래스 와 Cache 함수로 이루어져 있습니다. URLCache 클래스는 Cache 파일의 상태를 점검하고 Cache파일에 객체정보를 쓰고 읽는 역할을 수행합니다. Cache 함수는 URLCache 클래스를 기반으로 Cache 여부를 점검하여 Cache읽거나 아님 URL 정보를 읽어와 Cache 파일에 저장하는 함수입니다. Cache 함수는 기존에 사용하고 있는 WebApplication 에 Cache 기술을 쉽게 적용하기 위한 함수입니다.
<? /*/////////////////////////////////////////////////////////////// 작성자 : 손상모<smson@ihelpers.co.kr> 웹사이트 : http://www.ihelpers.co.kr 최초작성일 : 2004.10.25 변경내용 : 2004.11.01 Class외에 Cache 함수 추가 /////////////////////////////////////////////////////////////////*/ /** * URLCache Class * * URL 정보를 Cache 하는 Class입니다. * * @author Sang Mo,Son <smson@ihelpers.co.kr> * @version 0.9 beta * @access public */ class URLCache { var $CacheDir; var $Interval; /** * Constructor * * @param String Cache Directory * @param int Url Stale Time(s) * @access public * @return void */ function URLCache($CacheDir = './cache',$Interval = 3600){ $this->CacheDir = $CacheDir; $this->Interval = $Interval; } /** * Set Cache Directory * * @param int Url Stale Time * @access public * @return void */ function setCacheDir($CacheDir){ $this->CacheDir = $CacheDir; } /** * Set Url Stale Time(s) * * @access public * @return void */ function setInterval($Interval){ $this->Interval = $Interval; } /** * URL 정보에 해당하는 정보를 저장 * * @param string url * @param object content * @access public * @return void */ function set($url,$obj){ $fname = $this->_makeFileName($url); $fp = fopen($fname,'w'); if($fp){ fwrite($fp,$this->_serialize($obj)); fclose($fp); return true; } else { $this->Error("Unable to open file for writing : $fname"); return false; } } /** * URL 정보에 해당하는 정보 읽기 * * @param string url * @access public * @return object */ function get($url){ $fname = $this->_makeFileName($url); $fp = fopen($fname,'r'); if($fp){ $data = fread($fp,filesize($fname)); fclose($fp); return $this->_unserialize($data); } else { $this->Error("Cache doesn't contain : $url"); return false; } } /** * Cache 파일 점검 * * @param string url * @access public * @return int( -1 : not found, 0 : Stale, 1 : Hit ) */ function CheckCache($url){ $fname = $this->_makeFileName($url); if(file_exists($fname)){ if((time()- filemtime($fname)) >= $this->Interval){ return 0; } else { return 1; } } else { return -1; } } /** * URL 정보를 파일명으로 변경 * * @param string url * @access private * @return string */ function _makeFileName($url){ return $this->CacheDir."/".md5($url); } /** * Serialize The Content * * @param object content * @access private * @return string */ function _serialize($object){ return serialize($object); } /** * Unserialize The Content * * @param string content * @access private * @return object */ function _unserialize($content){ return unserialize($content); } /** * Error 정보 처리 * * @param string error message * @access public * @return void */ function Error($errmsg){ printf($errmsg); } } /** * URL 정보에 대한 Cache 함수 * * @access public * @param boolean isCache * @param string Cache Directory * @param int lifetime * @return boolean */ function Cache($iscache = true,$cachedir = './cache',$lifetime = 3600){ global $HTTP_GET_VARS,$HTTP_POST_VARS,$HTTP_SERVER_VARS; if($iscache == true && $HTTP_GET_VARS['CACHE'] != "NOCACHE" && count($HTTP_POST_VARS) == 0){ $url = sprintf("http://%s%s",$HTTP_SERVER_VARS['HTTP_HOST'],$HTTP_SERVER_VARS['REQUEST_URI']); $urlcache = new URLCache($cachedir,$lifetime); $result = $urlcache->CheckCache($url); if($result == 1){ // lifetime 이전 $html = $urlcache->get($url); } else { // lfietime 이후 또는 Cache파일이 없을 경우 $curl = sprintf("http://%s%s?CACHE=NOCACHE&%s",$HTTP_SERVER_VARS['HTTP_HOST'], $HTTP_SERVER_VARS['PHP_SELF'],$HTTP_SERVER_VARS['QUERY_STRING']); $fd = fopen ("$curl", "r"); $content = ""; while (!feof ($fd)) { $buffer = fgets($fd, 4096); $content .= $buffer; } $html['body'] = $content; $urlcache->set($url,$html); } echo $html['body']; exit; } else { return false; } } ?> |
URLCache 클래스는 자세히 살펴 보면 크게 어려운 부분이 없습니다. CheckCache,set,get Method만 잘 살면보면 그 원리를 쉽게 이해할수 있습니니다. CheckCache Method는 위의 코드에서 보는 것 처럼 호출된 URL를 MD5함수로 인코딩한 후에 Cache 디렉토리에 Cache 파일의 존재 여부 확인하고 파일의 수정된 시간을 기반으로 설정된 lifetime의 만료여부를 확인 해 줍니다. set method 는 object 정보를 serialize 함수를 이용하여 직렬화 하여 Cache 파일에 저장하고 get method는 반대로 해당 내용을 읽어옵니다.
Cache 함수는 URLCache 클래스의 CheckCache 함수를 통하여 Cache 파일의 상태를 구분하여 lifetime 이전인 경우는 Cache파일에서 자료를 읽고 Cache파일이 존재하지 않거나 lifetime 보다 오래 되었을 경우는 Cache파일을 새롭게 갱신해 줍니다.
$curl = sprintf("http://%s%s?CACHE=NOCACHE&%s",$HTTP_SERVER_VARS['HTTP_HOST'], $HTTP_SERVER_VARS['PHP_SELF'],$HTTP_SERVER_VARS['QUERY_STRING']);
Parameter 값중에 "CACHE=NOCACHE" 를 전달하여 해당 Page가 Cache 기술을 사용하지 않고 직접 실행되도록 한 부분을 주의깊게 살펴보기 바랍니다. 잘못 사용하게 되면 무한반복실행을 하게 됩니다.
Cache를 사용하므로써 매번 복잡한 연산과 DB 접속을 해야 하는 페이지가 Cache 된 파일을 엑세스만 하여 저장된 내용을 출력해 주므로써 서버의 부하를 줄여주고 사용자에게 빠른 로딩속도를 제공할수 있게 되는 것입니다. DB에서 많은 양의 자료를 실시간으로 조회하는 것이 문제가 되어 시간 또는 일단위로 배치작업을 하여 Summary Table에서 자료를 조회하는 방법과 비슷하다고 할수 있겠습니다.
3. 성능 및 속도 비교다음은 웹사이트 성능 분석 프로그램을 이용하여 Cache를 사용할때와 사
용하지 않을 경우의 성능 및 속도를 비교한 결과입니다.
Active Users | 1 | 5 | 10 | 15 | 20 | 25 | |
No Cache | TPS | 3.7 | 11.9 | 14.7 | 15.8 | 15.7 | 16.0 |
Total Requests | 222 | 713 | 881 | 949 | 944 | 962 | |
Average RPS | 0.076 | 0.262 | 0.558 | 0.816 | 1.190 | 1.429 | |
Cache | TPS | 5.4 | 16.0 | 19.1 | 20.3 | 21.2 | 20.9 |
Total Requests | 325 | 962 | 1148 | 1216 | 1272 | 1251 | |
Average RPS | 0.084 | 0.212 | 0.368 | 0.627 | 0.797 | 1.071 |
* TPS(Transaction Per Second, Request Per Second), RPS(Response Second)
* 테스트 조건 : Thinking Time - 0.1 초, 단위테스트 시간 - 1분
[출처] 웹디황용
"쇼핑몰·홈페이지·오픈마켓
블로그·페이스북·이메일 등의 각종 마케팅 글쓰기, 각종 광고, 영업, 판매, 제안서, 전단지 반응율 3배×10배 이상 높이는 마법의 8단계 공식" |
☞자세히보기 |
|
|