항간에 떠돌았던 노랑나비의 주술적 의미에 관련된 허무맹랑했던 내용을 다시 한번 생각해보려 한다.

노란 나비/노란 리본에 관련된 검색어로 검색해보면 여전히 악의적인 유언비어로 점철되어있다. 이 글을 통해 이 논란을 다시 한번 짚어보고 보다 올바른 의견을 제시하고자 한다.

from 위키트리 http://www.wikitree.co.kr/webdata/editor/201404/25/img_20140425154904_e3fef1d7.jpg

이미 이에 대한 반박의 글이 많이 올라와서 이 글이 전혀 성경적 세계관에 입각하지도 않은 완전히 잘못 된 내용임을 밝히고 있으나, 아직도 위의 스크린샷의 글을 그대로 믿는 기독교인 혹은 교회를 다니지 않는 믿지 않는 분들에게 참고하라는 뜻에서 좀 더 분명하게 이 글에서 밝히고자 한다.

※ 잘 정리된 리그베다 위키의 페이지 노란나비 주술 논란http://rigvedawiki.net/r1/wiki.php/%EC%B2%AD%ED%95%B4%EC%A7%84%ED%95%B4%EC%9A%B4%20%EC%84%B8%EC%9B%94%ED%98%B8%20%EC%B9%A8%EB%AA%B0%20%EC%82%AC%EA%B3%A0/%EC%82%AC%EA%B1%B4%EC%82%AC%EA%B3%A0#s-8.5

1. 노란 리본은 나비다 => 비약이고 엉터리. 완전히 헛소리.

2. 노란 나비가 저승으로 가는 영혼 => 설령 리본이 나비라고 해도 무슨 갑자기 저승으로 가는 영혼이라고 단정? 성경에 그런 얘기 없다.

3. 노란 리본/나비는 주술도 아니고, 종교 혼합주의도 아니다. 뭐 눈에는 뭐만 보인다고, 색안경을 끼고 보니 모두 주술이고 미신으로 보이는 것이다. 성경적 기독교적 세계관에 입각하지 않은 이러한 시각은 완전히 잘못 된 것이다.


노란 리본의 유래

먼저 이 논란의 키워드인 노란 리본의 유래부터 알아야 한다. 많은 분들이 이미 상식적으로 알고있듯이 노란 손수건은 무사히 귀환을 바라는 마음을 뜻한다. 이 노란 손수건의 유래는 상당히 오래되었다는 것을 알 수 있다. 귀환을 환영하는 '노란 손수건' 그 기원에 얽힌 이야기 (http://www.voakorea.com/content/a-35-2007-07-11-voa21-91253374/1304683.html)에 나와있는 것으로 알 수 있듯이 노란색 손수건은 용서와 화해의 의미뿐만이 아니라 무사히 귀환을 바라는 마음을 상징하였다. 처음에는 손수건이였다가, 매듭을 맺기 쉬운 리본을 쓰기도 했다는 것을 알 수 있다. 매듭은 종종 나비모양을 하였을 것이나 사실 애초부터 나비와는 별로 연관성이 없었다.

노란색의 의미

노란색은 종종 들판을 상징하고 익은 곡식, 풍요, 부귀를 상징하며, 자유와 방종을 동시에 의미하기도 하며, 겁쟁이 같은 좋지 않은 의미로 사용되기도 한다. 물론 동양에서는 황천길과 같은 저승길을 상징하는 부정적인 의미로도 쓰였다.

노란 나비가 상징하는게 과연 저승으로 가는 영혼인가?

"노란 나비는 바로 저승으로 가는 영혼이죠"라고 단정적으로 말하고 있는데 과연 그러할까?

노란 리본은 노란 손수건으로부터 유래되었고, 나비와의 연관성이 별로 없다고 이미 밝혔으나, 이를 백번 양보해서 노란 나비라고 할 수 있다고 해보자. 그러나 이것이 상징하는게 과연 저승으로 가는 영혼뿐일까? 그 근거로 삼은 노근리 평화공원의 노랑 나비가 과연 저승으로 가는 영혼을 상징한 것인가? 이러한 해석은 그냥 무/식/한 짜깁기에 불과하며, 성경적 세계관을 전혀 이해하지 못한 몰상식이며, 전혀 성경적이지 않은 해석이라 단언할 수 있다.

노란색은 앞서 밝힌대로 여러가지를 상징한다. 예수님이 탄생하셨을 때에 아시아의 동방 박사들이 예수에게 세가지 예물을 바친다. 드넓은 아시아를 상징하는 색상은 대개 노란색이다 (오륜기의 노란색). 세가지 예물은 황금과 유황과 몰약이며, 황금은 노란색이고, 유황도 노란색이며 심지어 몰약조차도 노란색이다. 노란색상은 사실 기독교에서 매우 고귀한 색상을 뜻하는 의미 깊은 색인 것으로도 볼 수 있을 것이다. 따라서 노란 나비를 불경스러운(?) 저승으로 가는 영혼이라고 쉽게 단정짓기 어려운 것이다. 이러한 유언비어를 퍼뜨린 사람이 과연 기독교인인지 의심스럽기까지 하다.

성경에서는 하나님은 만물을 창조하셨으며, 모든 만물이 모두 부족함이 없었다고 밝힌다. 노란 나비는 저급하고 흰 나비는 고귀하다는 구분이 없었다는 것이다. 따라서 올바른 성경적 세계관이라면 원래부터 무엇을 상징하거나 한 것은 단 하나도 없다. 노란 나비가 저승으로 가는 영혼을 단언할 수 없으며, 이러한 말로 혼란을 일으키는 것이야 말로 성경에 대한 무지함을 스스로 나타내는 것이다.

올바른 성경적 세계관으로

앞서 밝힌것 처럼 성경적 세계관으로 비추어본다면 세상의 그 어떤 것도 처음부터 무엇을 상징하거나 한 것은 없으며 모두 하나님의 창조물로 거룩하였다는 것이다. 인간의 타락으로 이러한 질서가 깨졌다가 예수의 은혜를 통해서 다시 회복되기에 이르렀다.

백번 양보해서 노랑나비가 정말 주술적 의미로 쓰였다고 치자. 그러나 그것은 성경적인 관점에서 보았을때 회복되어야 할 존재이며 창조물의 관점에서 거룩한 존재다. 한두번 좋지 않은 의미로 사용되었다고 해서 그 본래의 창조물로의 고귀함이 퇴색되지 않는다. 번데기가 나비로 화하는 기적적인 탈피가 부활을 의미하며, 나비는 성경적 관점에서 매우 고귀한 존재로의 상징성을 가졌다. 이러한 관점에서 보았을때에 노랑나비는 오히려 고귀한 부활을 상징하며, 세월호 실종자가 살아서 돌아오기를 바라는 간절한 염원을 담았다는 해석도 충분히 가능하다.

로마치하에 있던 유대인들에게 가장 미움을 받았던 세금을 부과했던 세리 마태를 예수는 제자로 삼았고, 세리 삭개오의 초청을 받아 같이 식사를 하며, 삭개오가 자신의 죄를 뉘우치고 자신의 재산의 절반을 가난한 사람에게 나누어주고 불법적으로 부과했던 세금을 세배로 갚겠다고 하는 다짐을 이끌어내었다. 성경적 세계관으로 비추어보면 처음부터 무엇이 특정한 무엇을 상징하거나 원래부터 나쁜 것은 없다. 온갖 미움을 받았던 세리 조차도 예수에게는 구원을 받아야 할 대상이였고 형제요 회복되어야 할 가족이였던 것이다.

마치며

SNS가 발달되어 개개인의 의견이 신속하게 전달되고 공유되는 시대에 살고 있다. 최근들어 전혀 기독교적이거나 성경적이지 않은 내용이 마치 성경적인 것인양 퍼뜨려지기도 하고 있는데, 대부분의 논란은 단순히 무시하면 될 수준의 것이였으나, 이번의 노란나비에 관련된 말도 안되는 낭설은 기독교인의 사이에 분란을 조장할뿐만 아니라, 같이 반성하고 같이 아파하고 고통을 나누어야 할 시점에서 나온 매우 악질적인 유언비어로 생각되는 바 이 글을 쓰게 되었다.

약간 복잡한 듯 하게 썼지만, 어렵게 생각할 것 없이 힘을 합쳐도 모자를 시점에 분란을 조장하는 이러한 노랑나비 논란과 비슷한 류는 기독교계에서 보다 적극적으로 대처해야 할 것으로 생각되며, 기독교인이 아니더라도 이러한 사고방식은 전혀 기독교적이거나 성경적이지 않다는 것을 쉽게 알 수 있다는 것을 이 글을 통해 밝히고 싶었다.

by dumpcookie 2014. 5. 9. 18:16

레노버 Thinkpad E145에 우분투를 설치하였습니다.

우분투를 단 한번도 기본 운영체제로 사용해보지는 않았지만 Thinkpad E145가 지원가능 목록에 있어서 우분투를 선택한 것입니다.

그러나 우분투에서 이를 잘 지원할 줄 알았는데 무선랜부터 제대로 설정이 안되더군요. 삽질의 예감이...

일단 lspci명령으로 무선랜 디바이스를 찾아보니 다음과 같이 나왔습니다.

01:00.0 Network controller: Broadcom Corporation BCM43142 802.11b/g/n (rev 01)
03:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (rev 07)

"ubuntu broadcom wifi" 등을 키워드로 검색해보니 맨 상단에 두개의 링크가 나오는데

http://askubuntu.com/questions/55868/how-to-install-broadcom-wireless-drivers-bcm43xx

https://help.ubuntu.com/community/WifiDocs/Driver/bcm43xx

두번째 링크를 잘 읽어보니 lspci -vvnn명령으로 PCI-ID를 살펴보라고 되어있어서 lspci -vvnn명령을 내려보면

...
01:00.0 Network controller [0280]: Broadcom Corporation BCM43142 802.11b/g/n [14e4:4365] (rev 01)
...

이것은 Chip ID가 bcm4322이며 wl 커널 모듈을 설치해야 한다고 나옵니다.

wl - Proprietary Broadcom STA Wireless driver 

문서 아래쪽에 나와있는 다음 명령을 통해서 bcmwl-kernel-source를 설치해보니 빙고~!!

apt-get --reinstall install bcmwl-kernel-source


by dumpcookie 2014. 4. 16. 03:22

앞의 일련의 포스트를 통해 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

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

최신 PHP에 대응하는 eAccelerator 빌드를 구하기 어려운 경우가 있는데, 더군다나 Win32 빌드가 버그가 있어서 캐시가 제대로 저장되지 않고 error_log에 오류를 뿌려대는 버그가 있습니다.

...
EACCELERATOR: Open for write failed for "C:/tmp/eaccelerator/0/3/2//eaccelerator-322dca16f42e18e9c9905165d150e901": No such file or directory
...

이를 수정하기 위해서 win32 빌드를 직접 해 보았습니다.

빌드하는 방식은 다음 사이트를 참고하여 정확히 따라하면 완벽하게 빌드됩니다.

 How to build APC or eAccelerator for PHP on windows

(블로그를 검색해보면 한글로 설명해놓은 곳도 많으니 참고하시기 바랍니다.)

캐시 디렉토리가 잘 못 지정되는 버그에 대한 패치는 다음과 같습니다.

--- a/eaccelerator.c
+++ b/eaccelerator.c
@@ -396,7 +396,11 @@ int eaccelerator_md5(char* s, const char* prefix, const char* key TSRMLS_DC)
     PHP_MD5Update(&context, (unsigned char*)key, strlen(key));
     PHP_MD5Final(digest, &context);
     make_digest(md5str, digest);
+#ifndef ZEND_WIN32
     snprintf(s, MAXPATHLEN-1, "%s/%d/", EAG(cache_dir), ea_mm_instance->cache_dir_uid);
+#else
+    snprintf(s, MAXPATHLEN-1, "%s/", EAG(cache_dir));
+#endif
     n = strlen(s);
     for (i = 0; i < EACCELERATOR_HASH_LEVEL && n < MAXPATHLEN - 1; i++) {
         s[n++] = md5str[i];


이 문제는 커밋 "Windows reverted to the old way, to hard to get a uid."의 부족분을 약간 더 수정한 것입니다.

다음 첨부파일은 PHP 5.4.19 소스를 바탕으로 컴파일된 결과물이며, TS / NTS 버전을 각각 포함하고 있습니다.

eAccelerator-v1.0-php-5.4.xy.zip

※ 주의: eAccelerator는 PHP 최신의 일부 기능이 제대로 안되는 문제가 있으며, 여기에 첨부된 dll은 이 문제에 관련된 패치가 전혀 적용되어 있지 않으니 주의하셔야 합니다.

by dumpcookie 2013. 8. 28. 19:38

예전부터 하려던 것을 이번 모니위키 1.2.0 릴리스를 내놓으면서 이것 저것 정리하면서 시도해보았습니다.

인터넷에 검색해보면 http://www.xpressengine.com/tip/15921874같은 내용처럼 모니위키를 구버전 XE에서 연동시키는 소스를 볼 수 있지만 위의 예에서 연동시키는 방식으로는 모니위키의 ACL 플러그인을 쓰지 못할 뿐만 아니라, XE의 구조가 조금만 바뀌어도 쓸 수 없게 되어버리기때문에 그리 권장할 만한 구현 방식이 아닙니다.

XE의 회원을 연동하기 위해서는 nFORGE 회원과 모니위키를 연동시킨 방식처럼 "회원이 로그인 된 상태인 경우 강제로 모니위키 회원 정보를 생성하는 방식"으로 접근하면 편리합니다. 이 경우에는 Security 플러그인을 확장하는 방식이 아니라 모니위키의 회원 클래스인 WikiUser 클래스를 확장하는 방식을 사용하게 됩니다.

class User_xe17 extends WikiUser {
    function User_xe17($id = '') {
        global $DBInfo;

        define('__XE__', true);

        $zbxe_root_dir = !empty($DBInfo->zbxe_root_dir) ?
                $DBInfo->zbxe_root_dir : __DIR__.'/../../../xe'; // XE root dir

        require_once($zbxe_root_dir."/config/config.inc.php");

        $context = &Context::getInstance();
        $context->init(); // 여기서 매우 느리다.
        ...

(위의 방식은 제가 직접 찾은 방법이나, 이러한 방식으로 할 수 있다는 내용을 블로그를 검색해보니 찾을 수 있더군요)

그러나 위와 같은 방식으로 하면 모니위키가 너무 너무 느려지기때문에 간소화된 init()을 다음과 같은 식으로 호출하는 것이 낫습니다.

    function xe_context_init($xe) {
        //
        // simplified XE context init method to speed up
        //

        // set context variables in $GLOBALS (to use in display handler)
        $xe->context = &$GLOBALS['__Context__'];
        $xe->context->_COOKIE = $_COOKIE;

        $xe->loadDBInfo();

        // set session handler
        if (Context::isInstalled() && $this->db_info->use_db_session == 'Y') {
            $oSessionModel = getModel('session');
            $oSessionController = getController('session');
            session_set_save_handler(
                    array(&$oSessionController, 'open'),
                    array(&$oSessionController, 'close'),
                    array(&$oSessionModel, 'read'),
                    array(&$oSessionController, 'write'),
                    array(&$oSessionController, 'destroy'),
                    array(&$oSessionController, 'gc')
           );
        }
        session_start();

        if ($sess = $_POST[session_name()]) {
            session_id($sess);
        }
    }

    function User_xe17($id = '') {
        global $DBInfo;

        define('__XE__', true);

        $zbxe_root_dir = !empty($DBInfo->zbxe_root_dir) ?
                $DBInfo->zbxe_root_dir : __DIR__.'/../../../xe'; // XE root dir

        require_once($zbxe_root_dir."/config/config.inc.php");

        $context = &Context::getInstance();
        $this->xe_context_init($context); // simplified init context method $context->init(); 대신에 사용.

        $oMemberModel = &getModel('member');
        $oMemberController = &getController('member');

        if ($oMemberModel->isLogged()) {
            ...

참고적으로 위와같이 간소화된 context 초기화 루틴을 사용하는 경우 기존의 context->init()을 사용하는 것보다 거의 20배가 빨랐습니다. (아파치 벤치 ab -n 500 -c 5로 로컬에서 측정한 경우. XE 회원 연동을 아예 하지 않는 경우가 그렇지 않은 경우보다 2.5배 빠름)

이를 좀 더 개선하여 Varnish cache를 사용할 수 있도록 고쳤으며, 최초 접속하는 경우에만 사용자 정보를 DB를 통해 가져오는 절차를 거치고 그 이후에는 세션을 통해서 인증을 하게 되므로 속도 저하가 없어졌습니다.

여기서 사용한 방식을 응용하면 XE1.7의 회원 정보를 보다 빠르게 타 PHP에서 연동시킬 수 있을 것으로 생각됩니다.

완전한 소스는 http://moniwiki.kldp.net/wiki.php/XeUserPlugin 에서 받으실 수 있습니다.

특징 및 기타 변경사항

- 버전 1.5부터는 모니위키 1.2.5에 기본 내장 예정 (2015/04/30)
- XE 1.7, XE 1.8 모두 지원함
- Varnish cache 지원 가능. XE 사용자 모듈을 사용하는데에 따르는 속도 저하가 없음 (2015/4/30 수정)

by dumpcookie 2013. 7. 5. 05:48
| 1 2 3 4 5 6 7 |