Wednesday, June 1, 2011

PHP 게시판에 파일 캐시를 달아보자 (file cache)

먼저 파일 캐시의 소스를 보자. 상당히 간단하다.



http://www.jongales.com/blog/2009/02/18/simple-file-based-php-cache-class/

<?php

class JG_Cache {

    function __construct($dir)
    {
        $this->dir = $dir;
    }

    private function _name($key)
    {
        return sprintf("%s/%s", $this->dir, sha1($key));
    }

    public function get($key, $expiration = 3600)
    {

        if ( !is_dir($this->dir) OR !is_writable($this->dir))
        {
            return FALSE;
        }

        $cache_path = $this->_name($key);

        if (!@file_exists($cache_path))
        {
            return FALSE;
        }

        if (filemtime($cache_path) < (time() - $expiration))
        {
            $this->clear($key);
            return FALSE;
        }

        if (!$fp = @fopen($cache_path, 'rb'))
        {
            return FALSE;
        }

        flock($fp, LOCK_SH);

        $cache = '';

        if (filesize($cache_path) > 0)
        {
            $cache = unserialize(fread($fp, filesize($cache_path)));
        }
        else

        {
            $cache = NULL;
        }

        flock($fp, LOCK_UN);
        fclose($fp);

        return $cache;
    }

    public function set($key, $data)
    {

        if ( !is_dir($this->dir) OR !is_writable($this->dir))
        {
            return FALSE;
        }

        $cache_path = $this->_name($key);

        if ( ! $fp = fopen($cache_path, 'wb'))
        {
            return FALSE;
        }

        if (flock($fp, LOCK_EX))
        {
            fwrite($fp, serialize($data));
            flock($fp, LOCK_UN);
        }
        else
        {
            return FALSE;
        }
        fclose($fp);
        @chmod($cache_path, 0777);
        return TRUE;
    }

    public function clear($key)
    {
        $cache_path = $this->_name($key);

        if (file_exists($cache_path))
        {
            unlink($cache_path);
            return TRUE;
        }


        return FALSE;
    }
}
?>



사용법은 다음과 같다.

$cache = new JG_Cache('/path/to/cache');  
 
$data = $cache->get('key');  
 
if ($data === FALSE)  
{  
    $data = 'This will be cached';  
    $cache->set('key', $data);  
}  
 
//Do something with $data




상당히 간단하다.





이제 어떻게 하면 게시판에 캐시를 달수 있을까?



우선 이 캐쉬는 로그인을 하지 않은 사람에게만 적용이 될 수 있다.



먼저 로그인이 되어있는지 안되어있는지를 체크한후, 로그인이 되어있지 않았다면 현재 화면에 해당하는 unique한 key를 만든다. 예를들어 viewtopic.php?id=3  이라면    $key= "viewtopic"."3"; 과 같은 식으로 key를 만들 수 있을것이다. 그런 후 그 파일을 불러오는 걸 시도 한다. ->get으로  불러오는것에 실패할경우 ->set 메소드로 현재 화면을 저장한다.



화면을 저장하기 위해서는 ob_start, ob_get_contents등의 방법을 이용해야 한다. ob_start를 호출한후 출력한 모든 것들은 buffering 되고 ob_get_contents를 호출함으로써 현재까지 출력된 스트링을 받아 올 수 있다. 이렇게 받아온 스트링을 set메소드로 저장하면 되는것이다.



결과적으로 파일의 앞부분과 뒷부분을 수정하면 파일 캐시를 사용할 수 있다.



이것을 사용할 경우 속도는 (제대로 적용한 경우) 대략 23배가 빨라진다.





다음은 punbb를 테스트한 결과이다. index.php를 테스트하였다. 기존 NG NAS N1T1결과와 비교하면 대략 23배 이상의 속도 향상이 있었다. 이러한 파일 캐시는 특히 블로그와 같은 서비스를 운영하는 경우 유리하다. 블로그는 사람들이 많이 로그인 하지 않기 때문.







Server Software:        Apache/2.2.14
Server Hostname:        example.lgnas.com
Server Port:            80

Document Path:          /punbb/index.php
Document Length:        9999 bytes

Concurrency Level:      10
Time taken for tests:   2.188965 seconds
Complete requests:      500
Failed requests:        96
   (Connect: 0, Length: 96, Exceptions: 0)
Write errors:           0
Total transferred:      5117904 bytes
HTML transferred:       4999404 bytes
Requests per second:    228.42 [#/sec] (mean)
Time per request:       43.779 [ms] (mean)
Time per request:       4.378 [ms] (mean, across all concurrent requests)
Transfer rate:          2282.81 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     4   42  41.4     19     209
Waiting:        3   32  36.6     15     187
Total:          4   42  41.4     19     209

Percentage of the requests served within a certain time (ms)
  50%     19
  66%     67
  75%     82
  80%     88
  90%     99
  95%    108
  98%    142
  99%    167
 100%    209 (longest request)

No comments:

Post a Comment