XpressEngine에도 mod_disk_cache를 간단히 적용해보았습니다.

주의할 점

실제로 mod_disk_cache를 제대로 적용하기 위해서는 세션 쿠키 등등을 최소화하여 캐싱이 유리하도록 만들고, 익명 사용자에 대해서는 세션쿠키를 쓰지 말고 별도로 처리하면 캐싱이 유리하게 됩니다.

이 문서는 단순히 s-maxage=3으로 세팅하는 매우 간단한 패치이며, mod_disk_cache의 효과를 아파치벤치라는 간단한 벤치마크 툴로 테스트하는 결과를 보여주므로 실제로 사용자가 느낄 수 있는 성능 향상과는 괴리가 있을 수 있습니다.


XpressEngine에 적용하기

XE 버전 1.7.x에 대해서 작성했습니다. 패치로 만드는 대신에 다음과 같이 수동으로 고치는 방식을 설명합니다.

1) classes/display/DisplayHandler.class.php 파일에서 다음 함수를 찾아서 Expires, Cache-Control, Pragma 헤더 삭제.

        /**
         * print a HTTP HEADER for HTML, which is encoded in UTF-8
         * @return void
         */
        function _printHTMLHeader()
        {
                header("Content-Type: text/html; charset=UTF-8");
                #header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); # 제거
                header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
                #header("Cache-Control: no-store, no-cache, must-revalidate"); # 제거
                header("Cache-Control: s-maxage=3, max-age=0, must-revalidate");
                header("Cache-Control: post-check=0, pre-check=0", false);
                #header("Pragma: no-cache"); # 제거
        }


2) classes/context/Context.class.php 파일에서 session_start()를 찾아서 session_cache_limiter('') 추가

                session_cache_limiter(''); # 추가
                session_start();

이렇게 고치면 끝.

테스트 결과

아파치 벤치(ab -n 1000 -c 3 http://localhost/xe/)로 테스트해보니 다음과 같은 결과가 나왔습니다.

... Concurrency Level: 3 Time taken for tests: 0.433 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 9072075 bytes HTML transferred: 8596000 bytes Requests per second: 2309.36 [#/sec] (mean) Time per request: 1.299 [ms] (mean) Time per request: 0.433 [ms] (mean, across all concurrent requests) Transfer rate: 20459.63 [Kbytes/sec] received


by dumpcookie 2013. 11. 9. 00:46

하는김에 도쿠위키도 mod_disk_cache를 간단히 적용시켜 보았습니다.

이론대로라면 도쿠위키의 경우에도 mod_disk_cache를 적용시키면 static html를 서비스하는 것과 같은 효과를 보게 되므로, 제 테스트 서버에서 ~2000 RPS의 속도가 나와야 합니다.

우선 테스트 서버에서 도쿠위키 해더를 분석해보았습니다.

$ wget -S  -nd http://localhost/doku/doku.php
--2013-11-08 23:00:14--  http://localhost/doku/doku.php
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Fri, 08 Nov 2013 14:00:14 GMT
  Server: Apache/2.2.17 (Fedora)
  X-Powered-By: PHP/5.3.8
  Set-Cookie: DokuWiki=thd20jrlllcl784amndh49mrs3; path=/doku/; HttpOnly
  Expires: Thu, 19 Nov 1981 08:52:00 GMT
  Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
  Pragma: no-cache
  Set-Cookie: DWcc0cd92de073dc44ef3a8f01d4702539=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/doku/; httponly
  Vary: Accept-Encoding
  Connection: close
  Content-Type: text/html; charset=utf-8
Length: unspecified [text/html]

위의 예에서 살펴보면 Expires: Cache-Control: 및 Pragma: no-cache가 붙는데, 이는 도쿠위키에서 session을 쓸 때에 자동으로 붙게되는 헤더입니다. 이를 일단 무시하도록 하기 위해서 session_start()를 찾아서 session_cache_limiter('');를 넣어주면 Expires: Cache-Control:Pragma: no-cache가 붙지 않게 되며, Cache-Control 헤더에는 s-maxage=3를 수동으로 붙여넣어 주어야 합니다.

도쿠위키를 간단히 고쳐주면 다음과 같습니다.

--- inc/init.php        2013-11-08 22:40:43.606000239 +0900
+++ inc/init.php        2013-11-08 22:43:10.418000603 +0900
@@ -141,6 +141,7 @@

 // init session
 if (!headers_sent() && !defined('NOSESSION')){
+    session_cache_limiter('');
     session_name("DokuWiki");
     $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'];
     if (version_compare(PHP_VERSION, '5.2.0', '>')) {
@@ -148,6 +149,7 @@
     }else{
         session_set_cookie_params(0,$cookieDir,'',($conf['securecookie'] && is_ssl()));
     }
+    header('Cache-Control: public, s-maxage=3, max-age=0, post-check=0, pre-check=0');
     session_start();

     // load left over messages

이렇게 고쳐주고 헤더가 잘 변경되었는지 살펴보니

$ wget -S  -nd http://localhost/doku/doku.php
--2013-11-08 23:07:23--  http://localhost/doku/doku.php
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Fri, 08 Nov 2013 14:07:23 GMT
  Server: Apache/2.2.17 (Fedora)
  X-Powered-By: PHP/5.3.8
  Cache-Control: public, s-maxage=3, max-age=0, post-check=0, pre-check=0
  Set-Cookie: DokuWiki=u9upco5mfls4nv87uqel66l4r0; path=/doku/; HttpOnly
  Set-Cookie: DWcc0cd92de073dc44ef3a8f01d4702539=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/doku/; httponly
  Vary: Accept-Encoding
  Connection: close
  Content-Type: text/html; charset=utf-8
Length: unspecified [text/html
...

위와 같이 s-maxage가 잘 추가되어있음을 알 수 있습니다.

이렇게 고치고 난 후에 아파치벤치(ab -n 1000 -c 3)를 돌려보니, 패치 전에는 ~90 RPS가 나오던 도쿠위키가 패치 이후에는 ~1500~2000 RPS가 나오게 되었습니다.

$ ab -n 1000 -c 3 http://localhost/doku/doku.php
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache/2.2.17
Server Hostname:        localhost
Server Port:            80

Document Path:          /doku/doku.php
Document Length:        37282 bytes

Concurrency Level:      3
Time taken for tests:   0.641 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      37846542 bytes
HTML transferred:       37356564 bytes
Requests per second:    1560.62 [#/sec] (mean)
Time per request:       1.922 [ms] (mean)
Time per request:       0.641 [ms] (mean, across all concurrent requests)
Transfer rate:          57679.66 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       1
Processing:     1    1   0.4      1       3
Waiting:        0    1   0.4      1       2
Total:          1    2   0.4      2       3

Percentage of the requests served within a certain time (ms)
  50%      2
  66%      2
  75%      2
  80%      2
  90%      2
  95%      3
  98%      3
  99%      3
 100%      3 (longest request)

mod_disk_cache 적용시 주의할 점

주의할 점은 이 패치는 단지 mod_disk_cache를 이런 식으로 붙일 수 있다는 것을 보여줄 뿐이지, 도쿠위키와 긴밀하게 작동하지는 않는다는 점입니다. (도쿠위키의 경우 세션을 사용하기때문에 세션 쿠키가 헤더에 붙게되는데, 이러한 쿠키는 mod_disk_cahe가 캐시를 효율적으로 하기 어렵게 합니다. 도쿠위키 및 모니위키 모두 mod_disk_cache를 십분 활용하기 위해서는 session 쿠키 등등을 최소화해서 static html로 서비스하도록 고쳐주어야 합니다.)

by dumpcookie 2013. 11. 8. 23:14

미디어위키는 어떠한 방식으로 속도를 향상시키고 있는지 관련 문서를 살펴보다가 이와 관련된 한글 문서가 거의 없다시피 하다는 것을 알게 되어서 간략하게 mod_disk_cache를 모니위키에 적용하는 방식을 요약 보고해봅니다.


미디어위키 튜닝에 관련된 문서를 보다가 http://www.mediawiki.org/wiki/Manual:Performance_tuning

아래 문서에 관한 링크를 알게 되었는데 이에 의하면 그 느려터진 미디어위키도 엄청난 속도 향상이 있다고 합니다.


즉, 6 RPS(Requests Per second. 초당 페이지 요청 수) 수준의 느린 미디어위키가 800 RPS로 속도향상이 됩니다.

http://www.testbit.eu/2011/using-mod_disk_cache-with-mediawiki/

아마도 테스트 서버의 사양이 낮아서 800 RPS가 나온 것으로 추측되는데,

이론적으로 mod_disk_cache를 사용하게되면 static html이 저장하여 서비스하게 되므로, 로컬에서 아파치벤치로 테스트하면 static html 속도가 나와야 합니다.


그래서 이것을 모니위키에 적용해보면 어떨까 하여서 모니위키에 간단한 패치로 캐시 컨트롤하는 부분에 s-maxage를 넣어서 패치시키고 mod_disk_cache를 적용해봤습니다.


약 200~300 RPS 속도가 나오던 모니위키가 문서에 거의 상관 없이 로컬 서버에서 1500~2000 RPS의 속도가 나오는군요. (~2000 RPS 수준이면 제 로컬 서버에서 정적(static) HTML 속도 수준입니다)


s-maxage를 설정하는 부분은 위의 링크에 자세하게 설명되었지만, s-maxage를 3으로 설정해서 dynamic/static 페이지에 상관 없이 약 3초간 모든 문서를 static문서로 간주하게끔 해서 mod_disk_cache 기능이 작동되도록 하는 것입니다. 이 경우 dynamic PHP 문서가 static으로 3초간 유지되기때문에 사용자는 문서가 약간 지연이 되면서 갱신되는 듯한 느낌을 받을 수 있습니다.


모니위키에 mod_disk_cache 적용해보기


미디어위키에 관련된 자세한 내용은 위의 링크를 통해 알 수 있으므로, 모니위키의 경우에 대해서 s-maxage를 적용시킨 부분을 간단히 적어보겠습니다. (패치라고 할 것도 없이 매우 간단한 패치입니다. wiki.php의 소스 맨 아래쪽에 있는 부분을 고치면 됩니다)


패치 이전에 다음 명령을 내려보면

$ wget -S --delete-after -nd http://moniwiki.kldp.net/wiki.php/HelpContents

--2013-11-08 21:27:22--  http://moniwiki.kldp.net/wiki.php/HelpContents
Resolving moniwiki.kldp.net... 115.145.209.51
Connecting to moniwiki.kldp.net|115.145.209.51|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Fri, 08 Nov 2013 12:27:22 GMT
  Server: Apache/2.2.17 (Fedora)
  X-Powered-By: PHP/5.3.8
  Cache-Control: public, max-age=0, post-check=0, pre-check=0
  Set-Cookie: MONIWIKI-%2A-41a4c8ea773d14d5de8455aeee1d0600-%2A-Anonymous=ujh7bu4e4aidsfn9lkq0j0b482; expires=Fri, 08-Nov-2013 13:27:22 GMT; path=/wiki.php
  Set-Cookie: MONI_TRAIL=En%7EMoniWiki%09HelpContents; expires=Sun, 08-Dec-2013 12:27:22 GMT; path=/wiki.php
  Vary: Accept-Encoding
  Connection: close
  Content-Type: text/html
Length: unspecified [text/html]
....

Cache-Control이 다음과 같이 나오도록 간단히 패치해줍니다. (wiki.php 소스의 아래쪽을 고치면 됨)

(실제로 아래와 같이 고치지는 않았으나 좀 더 명확하게 보여주기 위해서 패치의 핵심만을 포함시켰습니다)

diff --git a/wiki.php b/wiki.php
index d2cc150..ab8a0e7 100644
--- a/wiki.php
+++ b/wiki.php
@@ -5828,7 +5828,7 @@ if (session_id() == '' and empty($Config['nosession']) and is_writable(ini_get('
   else
     $private = 'private';
   if (empty($_GET['action']) or $_GET['action'] == 'show')
-    header('Cache-Control: '.$private.', max-age=0, post-check=0, pre-check=0');
+    header('Cache-Control: '.$private.', s-maxage=3, max-age=0, post-check=0, pre-check=0');
   //else if (!empty($_GET['action']) and in_array($_GET['action'], array('edit', 'info', 'diff')))
   //  header('Cache-Control: '.$private.', max-age=600, post-check=0, pre-check=0');

...
  Cache-Control: public, s-maxage=3, max-age=0, post-check=0, pre-check=0
...

이렇게만 하면 mod_disk_cache가 작동되게 되며 로컬 서버에서 ab -n 5000 -c 3 -k로 다음과 같은 속도가 나오게됩니다.

$ ab -n 5000 -c 3 -k http://moniwiki.kldp.net/wiki.php/HelpContents
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking moniwiki.kldp.net (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests


Server Software:        Apache/2.2.17
Server Hostname:        moniwiki.kldp.net
Server Port:            80

Document Path:          /wiki.php/HelpContents
Document Length:        14845 bytes

Concurrency Level:      3
Time taken for tests:   2.204 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      76975299 bytes
HTML transferred:       74239845 bytes
Requests per second:    2269.11 [#/sec] (mean)
Time per request:       1.322 [ms] (mean)
Time per request:       0.441 [ms] (mean, across all concurrent requests)
Transfer rate:          34114.34 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       7
Processing:     0    1  26.5      0    1507
Waiting:        0    1  16.1      0    1009
Total:          0    1  26.5      1    1508

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      1
  98%      1
  99%      1
 100%   1508 (longest request)

위의 예에서 2269 RPS가 나왔는데, 평균적으로 2000 RPS정도 나옵니다. @@



mod_disk_cache를 사용할 때에 주의할 점은

1. 이 경우 익명 사용자의 경우 대해서만 s-maxage가 적용되고 mod_disk_cache에 의해 캐싱된다.

2. mod_disk_cache가 좀 더 완벽하게 적용되려면 모든 PHP 결과를 dynamic 컨텐츠가 아닌 static 컨텐츠가 될 수 있도록 고치면 더욱 좋다. 이렇게 하면 s-maxage가 3초가 아니라 좀 더 길게 잡을 수 있게 된다. (이 문제는 미디어위키의 경우도 마찬가지)

3. 3초간의 짧은 시간동안 캐시가 유지되므로 접속이 많이 몰리는 경우에 서버에 부담을 덜 수 있게 된다.

4. 캐시가 3초간의 짧은 시간동안에만 유지되므로 실제로 체감 속도는 크게 달라지지는 않는다. 단, 서버의 로드가 줄어들기때문에 사용자가 많은 위키의 경우에 효과를 볼 수 있게 된다.


차기버전의 모니위키 1.2.2에서는 mod_disk_cache를 지원하도록 하는 패치가 같이 포함될 예정입니다.



그밖에 mod_cache/mod_disk_cache를 사용할 때에 유용한 팁이 있는 링크입니다.

http://www.philchen.com/2009/02/09/some-tuning-tips-for-apache-mod_cache-mod_disk_cache




by dumpcookie 2013. 11. 8. 21:54
| 1 |