앞의 일련의 포스트를 통해 mod_disk_cache를 사용하면 엄청난 성능의 향상이 가능하다는 것을 알 수 있습니다.

물론 mod_disk_cache를 제대로 지원하기위해서는 몇가지 제한사항이 있기는 하지만 특히 위키위키와 같은 경우에는 큰 변경 없이도 mod_disk_cache가 어렵지 않게 적용 가능한 경우입니다.

이번에는 보다 전문적이고 사실상 표준으로 자리 잡았다 해도 과언이 아닌 웹 가속기인 Varnish를 모니위키에서 사용해도 문제가 없도록 고쳐보았습니다.

참고로 Varnish는 FreeBSD 커널 해커가 만든 엄청난 성능의 웹가속기입니다. 2006년도에 첫 릴리스가 나온 후에 꾸준히 개발되어 현재 버전 3.0.4가 되었으며, 트위터, facebook을 비롯해서 수많은 사이트가 사이트의 속도를 높이고 동시에 부하를 낮춰 사이트 서비스를 안정적으로 할 수 있도록 도와주는, 미디어위키에서도 사용할 수 있는 유명한 웹 가속기입니다.

Varnish는 보통 아파치/nginx 앞단에 reverse proxy 방식으로 붙여두어 웹서버의 동적/정적 페이지를 캐싱하여 서비스를 하게 되는 방식을 주로 취하게 되는데, Varnish의 성능이 어느 정도냐면 정적 페이지에 대해서는 아파치 속도를 능가하며, php와 같은 동적 웹페이지에 대해서는 아파치는 물론 nginx보다 빠른 속도 및 낮은 시스템 로드로 웹 서비스를 가능하게 해줍니다. php같은 동적 웹페이지에 대해서 최소 10배 최대 1000배의 속도를 내게끔 해주게 됩니다.

다음은 약 1.4 kB 크기의 정적 페이지에 대한 로컬 서버에서의 간단한 아파치벤치 성능 테스트입니다.

 데몬 구성

 속도 (ab -n 10000 -c 10)

 아파치

 ~4000 RPS (편차가 심한 편)

 nginx

 ~8000 RPS

 Varnish + 아파치

 ~5000 RPS

 데몬 구성

 속도 (ab -n 10000 -c 3)

 아파치

 ~4000 RPS (편차가 심한 편)

 nginx

 ~8000 RPS

 Varnish + 아파치

 ~7000 RPS

그런데 동적 웹페이지에선 그 성능 향상이 가히 비약적입니다. (Varnish가 적용된 모니위키의 경우)

 데몬 구성

 속도 (ab -n 10000 -c 3)

 아파치

 ~300 RPS

 Varnish + 아파치

  ~7000 RPS

즉 Varnish를 통해 캐싱을 하게 되면 정적 웹페이지와 거의 같은 속도로 서비스를 하게 된다는 것을 확인할 수 있습니다.

모니위키에 Varnish 지원 추가

모니위키는 이러한 웹 가속기를 통해서 성능이 최대한 발휘될 수 있도록 그간 꾸준하게 작업을 하였습니다. HTTP Conditional GET를 지원하기 위해서 Last-Modified 헤더 및 ETag를 지원하고 있으며, 동적으로 변화할 수 있는 매크로를 자바스크립트를 통해 부분 업데이트가 가능하도록 하는 등등의 작업이 이루어졌습니다. (ESI방식은 mod_disk_cache를 사용할 수 없으므로 모두 사용 가능하도록 자바스크립트/ajax 방식을 사용)

일부 위키 매크로는 동적으로 컨텐츠가 변동이 있으나, 상당수의 매크로는 정적인 컨텐츠였기 때문에 이 둘을 구분하여 처리하였으며, 페이지가 추가되거나 삭제되면 ETag 및 Last-Modified가 변경되도록 처리하여 Varnish에서 특별히 purge를 통하지 않아도 자동으로 캐시가 업데이트 되도록 하였습니다.

또한 Cache-Control을 익명과 로그인사용자를 구별하였고, 위키 문서를 읽는 액션(action=show 혹은 action 쿼리 없는 경우)에 대해서 프록시 캐시 옵션 s-maxage=1을 붙여주었습니다.

마지막으로 익명 사용자의 경우에는 Cookie를 제한적으로 사용하여 Varnish에 의해 캐싱이 가능하도록 고쳤습니다.

이러한 일련의 변경을 mod_disk_cache를 통해서 그 가능성을 확인하였고 Varnish를 성공적으로 지원할 수 있게 되었습니다.

속도 비교

다음은 개략적인 속도 비교입니다.

- 모니위키 (캐싱 없음) - 50 RPS 수준

- 모니위키 + 내장 캐싱 사용 - 200 RPS

- 모니위키 + mod_disk_cache - 1500 ~ 2000 RPS (아파치 정적 웹페이지 서비스 속도에 준하는 속도)

- 모니위키 + Varnish - 5000 ~ 7000 RPS (Varnish의 정적 웹페이지 서비스 속도에 준하는 속도)



참고사이트

https://www.varnish-cache.org/

http://en.wikipedia.org/wiki/Varnish_(software)

http://phk.freebsd.dk/

by dumpcookie 2013. 11. 23. 20:00

앞에서 설명한 내용은 미디어위키 설정에 관련된 검색을 해보면 상당히 잘 설명되어 있는 부분입니다. 간단한 설정을 통해서 어느정도 미디어위키의 속도를 손쉽게 향상시킬 수 있지요.

그러나 이렇게 설정을 하더라도 성능이 원하는 만큼 손쉽게 향상이 되지 않고 있습니다. 그래서 미디어위키의 프로파일링 옵션을 켜고 어떤 부분이 느린지 살펴보았습니다.

미디어위키는 프로파일링 방식을 자체 내장하고 있는데 다음과 같은 설정 변경을 통해서 프로파일링을 활성화시킬 수 있습니다.

1. StartProfiler.php 파일을 만들어 최상위 디렉토리(index.php가 있는 디렉토리)에 넣는다.

2. StartProfiler.php에 다음과 같은 내용을 넣는다.

$wgProfiler['class'] = 'ProfilerSimpleText'; $wgProfiling = true; $wgDebugComments = true;

이렇게 한 후에 임의의 문서를 열고나서 문서의 html 소스를 보면 다음과 같은 내용을 볼 수 있습니다. 다음은 위키의 최근 바뀜(RecentChanges)문서를 본 것입니다.

최근 바뀜(RecentChanges) 문서 말고도 몇가지 문서를 열어보면 "MediaWiki::doJobs-exec"라는 항목이 공통적으로 상당한 시간을 잡아먹고 있다는 사실을 알 수 있습니다.

이것을 역추적해서 살펴보니 위키 메인함수는 MediaWiki::run()에 의해 호출되며

        /**
         * Run the current MediaWiki instance
         * index.php just calls this
         */
        public function run() {
                try {
                        $this->checkMaxLag();
                        $this->main(); // 메인 루틴
                        $this->restInPeace(); // 여기서 doJobs()가 호출되는데 이것이 매우 느림.
                } catch ( Exception $e ) {
                        MWExceptionHandler::handle( $e );
                }
        }

MediaWiki::restInPeace()에서 호출되고있는 doJobs() 메쏘드가 매우 느린 문제가 있었습니다.

단지 doJobs()가 실행되고 있는 줄을 커멘트 아웃 시키니 전체적인 성능이 ~70 RPS 수준으로, 기본 ~6 RPS 정도로 형편없이 느리던 속도가 10배 이상의 향상이 있는 것이였습니다.

        /**
         * Ends this task peacefully
         */
        public function restInPeace() {
                // Do any deferred jobs
                DeferredUpdates::doUpdates( 'commit' );

                // Execute a job from the queue
                $this->doJobs(); // 매우 느림
....

        /**
         * Do a job from the job queue
         */
        private function doJobs() {
                global $wgJobRunRate, $wgPhpCli, $IP;

                if ( $wgJobRunRate <= 0 || wfReadOnly() ) {
                        return;
                }
...
                if ( !wfShellExecDisabled() && is_executable( $wgPhpCli ) ) {
                        // Start a background process to run some of the jobs.
                        // This will be asynchronous on *nix though not on Windows.
                        wfProfileIn( __METHOD__ . '-exec' );
                        $retVal = 1;
                        $cmd = wfShellWikiCmd( "$IP/maintenance/runJobs.php", array( '--maxjobs', $n ) );
                        wfShellExec( "$cmd &", $retVal ); // 이 부분.
                        wfProfileOut( __METHOD__ . '-exec' );
                } else {
...


위에서 볼 수 있는 것처럼 doJobs()는 문서를 출력하고(main()이 실행된 다음) 그 이후에 실행되는데, shell을 사용하여 maintenance/runJobs.php 스크립트를 실행시키고 있었습니다. 이러니 아파치벤치같은 속도측정 방식으로는 형편없는 속도가 나올 수 밖에 없는 것이지요.

그래서 이 옵션에 대한 문서를 검색해보니 다음과 같은 문서를 찾을 수 있었습니다.

http://www.mediawiki.org/wiki/Manual:$wgJobRunRate

이 문서 내용에 의하면 $wgJobRunRate = 0.01; 옵션을 추가하여 doJobs() 실행회수를 줄여주면 성능향상을 기대할 수 있게 되며, 문서에 나와있는데로 $wgJobRunRate 값을 0.01로 조정해보니 ~60 RPS 수준으로 속도가 향상되었습니다.

주의해야 할 점은 $wgJobRunRate를 조절하고 난 후에는 job queue가 너무 많아지는 것을 방지하기 위해서 링크된 문서에서 설명되어있는 것처럼 cron을 통해서 주기적으로 doJobs()를 실행하도록 설정해야 한다는 점입니다. 단, 개인 위키로 사용할 경우에는 아래 설정을 굳이 하지 않아도 되리라 예상할 수 있습니다. 자세한 내용은 아래 문서를 참조하시기 바랍니다.

http://www.mediawiki.org/wiki/Manual:Job_queue


정리하면 다음과 같은 옵션을 LocalSettings.php에 추가하면 약 10배의 속도 향상을 얻을 수 있습니다.

$wgMainCacheType = CACHE_ACCEL;
$wgCacheDirectory = "$IP/cache";
$wgFileCacheDirectory="$IP/cache";

$wgEnableSidebarCache=true;
$wgUseFileCache=true;

$wgDisableCounters = true;

$wgJobRunRate = 0.01;

이 설정으로 변경하고 난 후에 앞에서 잠깐 설명했던 미디어위키 + mod_disk_cache 패치를 적용하면 static html 속도에 준하는 비약적인 성능 향상을 제대로 얻을 수 있었습니다. 즉 로컬로 ~6PRS 수준이던 속도가 캐시 관련 설정 + mod_disk_cache 패치를 하면 ~2000 RPS ~ 3000 RPS에 달하는 static html의 속도를 얻을 수 있게 됩니다~!

참고사이트

http://www.mediawiki.org/wiki/Manual:Performance_tuning

by dumpcookie 2013. 11. 19. 17:49

미디어위키를 처음 설치하고 난 후에 기본 설정을 그대로 두는 경우에는 미디어위키의 느린 성능에 많은 실망을 할 수도 있습니다. 이것은 미디어위키의 기본 옵션은 성능 향상을 위한 설정이 모두 비활성화 되어있는 상태라서 그렇습니다. 약간 손이 가기는 하지만 캐싱에 관련된 기능을 몇가지 활성화시키면 미디어 위키의 성능을 어느정도 향상시킬 수 있습니다.

기본 캐시 타입을 APC로

미디어위키를 처음 설치하면 기본 캐시 타입이 CACHE_NONE이 됩니다. 기본 캐시 타입을 APC 캐시로 설정해주려면 다음과 같은 내용을 LocalSettings.php에 넣어줍니다.

$wgMainCacheType = CACHE_ACCEL;

내장 캐시를 켜라

미디어위키에서는 몇가지 캐싱을 통해서 그 속도를 좀 더 끌어올릴 수 있습니다. 첫번째는 기본 캐시 옵션을 켜는 것이고, 두번째로는 파일 캐시 옵션(모든 문서의 랜더링 결과를 파일로 저장)을 활성화 시키는 것입니다. 이 두가지 캐시 옵션을 활성화시키면 전체적으로 두배가까운 성능으로 끌어올릴 수 있습니다.

캐시 디렉토리 설정

LocalSettings.php 세팅 파일을 열어서 다음 줄을 추가해주면 cache 디렉토리가 설정이 되며

$wgCacheDirectory = "$IP/cache";

미디어위키가 설치된 최상위 디렉토리($IP) 아래에 있는 cache 디렉토리의 퍼미션을 조정하는 최소 설정만으로도 약간의 성능향상을 얻을 수 있습니다. 이 경우 지역화 메시지가 자동으로 캐싱이 되어 cache 디렉토리 아래에 저장되게 됩니다.

주의할 점은 cache 디렉토리의 퍼미션을 적절히 맞춰주어야 한다는 것입니다. 예를 들어 chmod 777 cache 혹은 chown apache.apache cache 등등으로 적절히 조절해야만 캐시 파일이 cache 디렉토리 아래에 저장되게끔 됩니다.

파일 캐시 설정

LocalSettings.php 세팅 파일을 열어서 다음 줄을 추가해주면 위키 문서의 랜더링 결과를 파일로 저장하여 캐싱하게됩니다.

$wgUseFileCache=true;
$wgFileCacheDirectory="$IP/cache";

그밖에 추가적인 성능향상 옵션

다음의 추가적인 옵션을 통해 약간의 성능향상을 끌어올릴 수 있습니다.

$wgDisableCounters = true; // 카운터 비활성화 (약간의 성능 향상)
$wgEnableSidebarCache = true; // 사이드바 캐시 켜기

여기까지 설명한 캐시 옵션을 모두 활성화시키면 기존에 아파치벤치(ab -kt3 http://localhost/mediawiki/index.php/Main_Page) 속도측정으로 ~5RPS 정도 되던 속도가 ~10 RPS 정도로 성능이 향상이 됩니다.

여기까지의 내용은 사실 미디어위키 속도 향상에 관심을 가졌던 분들이라면 검색을 통해서 이미 이 옵션을 켜고 사용중이실 것입니다. 그러나 이것만 가지고는 예상한 것 만큼의 성능향상이 나오지 않아서 미디어위키에서 자체 내장하고 있는 프로파일링을 활성화 시키고 원인을 살펴보았습니다.

계속되는 내용은 다음 문서에서 이어집니다.

참고 사이트

http://www.mediawiki.org/wiki/Manual:Performance_tuning

by dumpcookie 2013. 11. 19. 17:25