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

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

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

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