리그베다위키의 전신 엔하위키를 본인이 처음 봤을때가 아마도 2008년정도 였을것이다. 그때는 "아... 이런 희안한 사이트도 있구나"라는 정도로 스쳐지나갔다가, 한 2년 후에 다시 보게 되었을때는 거의 ~8만여 페이지 규모의 국내 최대 모니위키 사이트가 되어있었다. 규모에도 놀랐지만 너무 너무 느려서 더 놀랬던 것으로 기억한다. 검색은 당연히 먹통이고, 반응 속도가 너무 느려서 이대로 두면 안되겠다 싶어서 위키 게시판에 글을 올렸고, 병목현상을 일으키던 부분을 찾아내어 수정하고 모니위키 1.1.5 개발자판으로 판올림을 했던 것으로 기억한다.(2010년 10월) 그 당시 엔하위키는 모니위키 렌더러에 자잘한 수정을 하고 (버그 수정 포함), 일부 사용자 관리/필터링 등등의 일부 기능을 추가 했을 뿐이라서, 엔하위키측에서 제공한 모니위키 변경분에 대해서 선별적으로 적용하고 추가적으로 여러 수정을 해서 모니위키 1.1.5 버전이 나왔고, 엔하위키 관리/운영진은 이를 바탕으로 어렵지 않게 판올림을 하였고 정상적인 속도도 나오게 되었다. 그 뒤에 엔하위키 사용자의 피드백을 받아서 모니위키 1.1.6CVS 개발판이 나왔다.


https://kldp.org/node/118619 참조

1.1.5 판올림 당시 구 엔하위키게시판에 올라온 짤방



그러다가 다시 15만~20만 페이지 규모가 되었던 시점이었을때에 또 다시 엔하위키는 느려져 있었고, 또 다시 병목현상의 원인을 찾아 수정하고 모니위키 1.2.0 판올림도 같이 병행하였다. (2013년 8월)


당시 병목 현상의 원인은?

2010년 당시 5만여 페이지 규모였을때에, 병목현상의 원인은 사실 별거 없었다. 매크로중에 페이지 개수를 카운팅하는 기능이 너무 느렸던 것이었다. 엔하위키의 경우 페이지 개수 표시가 오른쪽 사이드바에 항상 표시가 되었다. 그런데 카운팅 매크로는 5만여 페이지의 목록을 모두 가져오고 그것의 개수를 매번 세었던 것이였다. 그래서 이 부분에 대해서 페이지 개수를 보다 효율적으로 세도록 고치고, 페이지 개수 정보를 캐싱하게 만들었다. 그밖에 여러 개선과 수정이 물론 있었지만 이 변경이 구 엔하위키의 속도를 원상복구 시키는 주요한 고침이였다. 그밖에 5만여 페이지 규모에서도 문제없도록 간단한 n-gram 인덱서를 추가해서 5만여 페이지 규모의 위키에서도 본문 검색을 할 수 있도록 만들었다.


2013년 8월의 고침도 사실 따지고 보면 대동소이했다. 페이지 개수 세는 부분을 보다 영리하게 만들고, 전체 페이지 목록을 매번 가져올 것이 아니라 주기적으로 업데이트 하고, 페이지 삭제/추가시 페이지 개수를 부분 업데이트 하도록 고쳤다. 물론 1.2.0 판올림의 경우에는 모니위키의 캐싱 방법을 더 뜯어고쳐서 대규모 위키에 문제 없도록 하는 등등의 여러 고침도 함께 포함하고 있었다.


DBMS vs 파일 시스템

많은 사람들이 말하기를 모니위키가 DBMS 기반이 아니라서 대규모 위키 대응이 불가능할 것이라 하지만, 사실 위키의 경우에는 flat한 key-value 구조라서 DBMS보다는 NoSQL이 더 유리하고, key-value구조는 파일 시스템 친화적이다. git/cvs/rcs같은 훌륭한 버전컨트롤 시스템이 모두 파일 기반이며 이를 그대로 써먹을 수 있다. 특히 RCS의 경우는 각 페이지별로 버전 히스토리가 별도로 저장되므로 위키엔진의 버전 컨트롤용으로 적합하다. 미디어위키처럼 DBMS로 구현하는 경우에는 버전 컨트롤을 다시 구현해야 한다. (또한 미디어위키는 여러 이미지 자료들을 DBMS로 저장하거나 하지는 않으며 이미지 자료는 파일시스템에 저장하는 방식을 여전히 쓰고 있다.) 그러나 모니위키의 경우처럼 파일기반인 경우에는 버전컨트롤을 RCS와 같은 외부프로그램이 별도로 담당하고 있어서 따로 구현할 필요가 없다. 위키엔진은 페이지 이름에 해당하는 페이지의 최종 버전을 가져와서 렌더링해서 뿌려주면 그만이다. 페이지 이름이 고유한 key-value구조라서 NoSQL에 대응하기 어렵지 않다. 위키 규모가 100만페이지 이상이 되더라고 대응이 그리 어려운 일이 아니라는 얘기다. 리눅스의 경우 파일시스템의 성능이 비약적으로 좋아졌다는 사실도 한몫 하고 있다. 버전 정보는 파일시스템으로 저장하고, 프론트엔드 단에서는 NoSQL을 써서 최종 버전을 저장하고, 검색은 elastic 검색 엔진을 쓰면된다. (모니위키는 이미 개발판에 elastic 검색 엔진을 실험적으로 넣었다. 가까운 미래에 NoSQL 백엔드를 만들게 될지도 모르겠다)


미디어위키는 훌륭한 위키엔진이다. 그러나 이것을 개인사용자가 사용하기 적합할까? 미디어위키를 처음 설치해보고는 그 속도가 생각보다 느리다는 사실에 놀랬었다. 미디어위키의 경우 자신의 위키 규모에 맞춰서 적절하게 설정을 해주어야 한다. (미디어위키의 속도를 향상시키는 법은 다른 글 #1 #2 참조.) 도쿠위키도 아주 좋은 위키엔진임에 분명하다. 파일기반이라서 단촐하고 개인사용자에게 적합하다. 그런데 본인의 테스트에 의하면 5천 페이지 정도만 되어도 쉽게 대응할 방법을 찾지 못하였다. 물론 개인위키 사용자라면 1천 페이지 만들기도 어렵기때문에 사용하는데 지장이 없을 것이다.


엔하 미러의 속도와 비교

종종 리그베다 본관의 속도와 엔하미러의 속도가 비교대상이 되고는 하였다. 사실 엔하미러의 속도는 상상을 초월할 정도로 빠르다. 엔하미러가 얼마나 빠르냐 하면, 로컬에서 아파치 벤치로 속도를 측정한다고 했을때에 거의 static html 페이지 속도급으로 빠르다. 이정도로 빠르기때문에 사실 엔하미러 속도를 다른 위키엔진과 비교하는 것은 무의미할 수 있다. 모니위키의 속도는 여러 최적화 옵션을 키면 엔하미러의 속도의 1/10에 해당한다 보면 된다. 사양에 따라 다르겠지만 로컬에서 static html 속도가 ~2000RPS 정도라고 한다면 모니위키의 경우에는 ~200RPS이다. (만약 모니위키를 아파치서버 + varnish 캐싱 서버와 함께 사용하면 ~7000RPS 정도로 올라가게 된다.)


그렇다면 미디어위키의 속도는 어떨까? 기본 설정으로 설치가 끝난 상태에서는 서버사양에 따라 달라지겠지만 위에서 언급한 것처럼 static html이 ~2000RPS정도 나온다고 했을때에 미디어위키는 ~5RPS도 안된다. 최적화 옵션을 켜면 ~10~15RPS 수준으로 올라간다. (이 경우도 아파치 + varnish캐시서버를 사용하면 비약적으로 빨라지게 되는데 자세한 내용은 미디어위키의 문서를 참고하라)


마치며

지금은 상당히 좋은 위키 엔진이 많이 있기때문에 모니위키의 인기가 많이 사라진 편이지만, 모니위키가 최초 나왔을 무렵 노스모크의 위키 엔진이었던 python으로 구현된 모인모인의 클론을 표방하고, 웹 호스팅에 좀 더 유리했던 PHP로 새롭게 작성했었다. 모니위키는 기존의 모인모인을 금방 대신하여 자리를 차지하게 되었고, 한동안 모니위키는 개인위키 사용자들의 대세였던 적도 있었다. 뿐만 아니라 지인의 증언(?)에 의하면 모니위키는 많은 회사 인트라넷에서도 사용되어졌고 처음 위키위키를 사용하는 사용자들에게 영향을 끼쳤다.


모니위키는 여전히 개인위키를 지향하며, 코어 코드를 좀더 줄이려고 노력하고 있다. 그러면서도 리그베다위키의 규모에 대응하기 위해서 확장이 보다 손쉽도록 개선하고 있으며, 최근에는 마크다운의 문법과 거의 유사한 것에 착안하여 마크다운 문법을 섞어서 쓰더라도 문제가 없도록 MixDown 파서를 개발하고 테스트하였고 한편으로는 기존 모니위키 문법 파서를 재작성 및 테스트 하였다.


개인 사정으로 2014년 거의 개발 중단 상태였다가 다시 모니위키 소스를 건드리고 있는데, 모니위키가 앞으로 어떠한 방향으로 개발되게 될지는 나도 장담하지 못하겠지만, 리그베다위키가 사라지지 않는한, 일부 개인 사용자의 피드백이 지속되고 있는 이상 계속 개발하게 되지 않을까 생각한다.


다음에는 리그베다위키와 그 클론들에 대한 이야기와 전망에 대해 써보려 한다.

by dumpcookie 2015. 4. 28. 14:44

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

미디어위키는 어떠한 방식으로 속도를 향상시키고 있는지 관련 문서를 살펴보다가 이와 관련된 한글 문서가 거의 없다시피 하다는 것을 알게 되어서 간략하게 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.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

드디어 모니위키 속도가 300RPS의 벽을 깼다.

불필요한 초기화 부분 한 줄 제거했는데 이렇게 나옴;; https://github.com/wkpark/moniwiki/commit/bc662afdc2268e86154da8a6abfe61c0a93432c8 참조

아래는 nginx + php-fpm + eaccelerator를 설정하고 모니위키 1.2.0 개발판 테스트해본 결과.

아파치를 쓰더라도 거의 비슷하지만 nginx + php-fpm의 경우가 좀 더 빠른 듯.


아래는 몇 번을 반복했을 때 가장 높은 측정값이 나온 경우.

$ ab -c 5 -n 300 http://localhost:8800/moniwiki/wiki.php?FrontPage
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
Finished 300 requests


Server Software:        nginx/0.8.54
Server Hostname:        localhost
Server Port:            8800

Document Path:          /moniwiki/wiki.php?FrontPage
Document Length:        30134 bytes

Concurrency Level:      5
Time taken for tests:   0.778 seconds
Complete requests:      300
Failed requests:        0
Write errors:           0
Total transferred:      9088800 bytes
HTML transferred:       9040200 bytes
Requests per second:    385.65 [#/sec] (mean)
Time per request:       12.965 [ms] (mean)
Time per request:       2.593 [ms] (mean, across all concurrent requests)
Transfer rate:          11409.94 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   1.2      0      16
Processing:     5   13   4.7     12      43
Waiting:        0   12   4.7     11      43
Total:          5   13   4.9     12      44

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     13
  75%     14
  80%     15
  90%     18
  95%     22
  98%     27
  99%     29
 100%     44 (longest request)

config.php의 설정값

$trail=0; // trail 끔
$cachetime=60*60*24; // 캐시 설정

by dumpcookie 2013. 5. 21. 08:56

최근에 엔하위키 속도 문제에 관련되어서 모니위키를 업데이트하게 되었고,

관련 작업이 모니위키 개발자 버전에 반영되었으며, 차일 피일 미루던 모니위키 1.2.0 릴리스 준비를 하고 있습니다.


엔하위키가 느린 점에 대해서 말들이 많았는데,

현재 엔하위키에는 간단한 몇가지 속도 패치가 적용된 상태입니다.

- 페이지 캐싱 활성화 - 모니위키 1.1.3부터 지원하였던 이 기능을 비로소 최근에 활성화 시켰습니다.

- 모니위키 1.1.5부터 지원했던 랜덤 페이지 전용 페이지 목록 인덱싱 기능을 활성화 시켰습니다.

- 기타 페이지 목록이 빈번하게 갱신되던 문제를 해결한 패치를 적용시켰습니다.



현재 엔하위키는 그나마 예전보다는 나은 속도를 내고 있습니다만 여전히 다음과 같은 문제가 있습니다.


1. 전체 페이지 리스트가 여전히 빈번하게 갱신되고 있다.

  - 현재 랜덤페이지에 의해서 사용되는 전체 페이지 목록을 가져오는 부분이 문제가 있는 듯 여전히 전체 페이지 목록이 자주 갱신되고 있습니다.

  - 이 문제는 패치 자체 버그로 보입니다. 그러나 예전보다 크기가 작고 빠른 속도로 갱신이 되어서 큰 문제를 느끼지 못하고 있는 듯.


2. 검색 - 역링크 / 제목검색 / 본문검색 포함

  - 현재 DBA 인덱서 패치가 추가로 엔하위키에 적용된 상태이지만 몇가지 문제로 사용되지 않고 있습니다.

  - DBA 인덱서를 적용한다 하더라도 역링크 및 제목검색은 상당히 빠르지만 본문검색은 적게는 수초가 걸리고 그 이상으로 느린 경우도 있습니다.

  - 인덱서 패치를 적용했는데 오히려 제목 목차가 느려졌습니다. (효율적이지 않은 제목 인덱싱)



이러한 문제를 해결하기 위해서

1. DBA를 사용한 본문/제목/링크 등등의 인덱싱 처리를 일차적으로 최적화 과정에서 배제시켰습니다.

2. 본문 검색보다는 제목 검색에 초점을 두었습니다. 본문 검색은 외부 검색엔진을 도입하는 것이 여러모로 나을 것으로 생각되며,

3. 전체 페이지 목록을 갱신하는 부분을 모듈화하고, 일단 매우 간단한 구현을 하였습니다. (기존의 페이지 목록 인덱서 개량)

4. 페이지 내용 검색(Fulltext search) 및 이와 관련된 느린 검색에 대해서 일단 시간 제한 혹은 개수 제한을 걸고 페이징 처리를 하도록 하였습니다.


이렇게 방향을 변경하고 다음의 작업이 진행되었습니다.

1. 전체 페이지 목록을 한꺼번에 갱신할 필요가 아예 없게 만들었습니다.

 - 랜덤 페이지 이외에 전체 페이지목록이 필요한 부분에 대해서 통합하고

 - 느린 전체 페이지 갱신을 아예 할 필요가 없게 만들었습니다. (페이지 추가/제거/이름 변경시에 전체 리스트를 업데이트만 함)

 - 이는 기존의 페이지이름 인덱서를 업데이트한 것입니다.


2. 역링크는 이제 검색이 아닙니다.

 - 역링크를 검색기능이 아니게 되었습니다.

  (그런데 모니위키의 역링크는 그 구현상 원래부터 검색이 아니였습니다 ^^;; 이번에 버그를 잡았습니다.)

 - 역링크는 페이지가 만들어지거나 갱신될 때에 즉각적으로 아주 빠르게 갱신됩니다.

 - 실제로 역링크를 사용시에는 그냥 역링크 정보를 가져오기만 합니다.


3. 페이지 이름검색이 빨라지고 유연해졌습니다.

 - 공백이 들어있거나 공백이 아예 없거나, 특수문자가 일부 들어간다고 해도 잘 찾아냅니다.

 - 특별히 이름 검색에 대해서 인덱싱 처리하거나 하지 않는데도 20만 페이지 규모에서도 매우 빠릅니다.


4. 본문 검색에 시간 제한을 걸고, 페이징처리를 하였습니다.

 - 일단 본문검색에 대해서 이러한 방식으로 처리하여 서버에 줄 수 있는 부담을 최소화했습니다.



일단 이러한 일련의 대규모 위키사이트에 대한 작업은 모니위키 1.2.0 개발자 버전에 대해서 진행중입니다.



참고적으로 로컬로 측정한 아파치 벤치마크 값입니다.

- 모니위키의 경우 19만 페이지가 있습니다. / 도쿠위키는 전체 10페이지 미만.

- 페이지는 단순한 HelpContents 페이지를 기준으로 삼았습니다. (static html은 그 랜더링된 결과)

- ab -c 2 -n 500을 기준으로 했습니다. (단순 측정값입니다.)

- 서버사양 AMD dual core 5200 / 2GB 램


static html의 경우 ~1000RPS

모니위키 1.2.0 개발판의 경우 ~300RPS (eaccelerator + 내장 캐시 사용)

모니위키 1.1.5 구버전의 경우 ~220RPS (eaccelerator + 내장 캐시)

도쿠위키 2012-10-13일 판 ~120RPS (eaccelerator + 내장 캐시 사용)

(미디어위키는 기본 설치 설정으로는 너무 느려서 논외.)



모니위키 1.2.0 최신 개발자 버전 맛보기 (임시적으로 엔하위키 19만 페이지가 읽기 전용으로 되어있음)

http://moniwiki.kldp.net/moniwiki/wiki.php


및 모니위키 github 사이트

https://github.com/wkpark/moniwiki


http://moniwiki.kldp.net/wiki.php/MoniWikiFeatures/1.2.0 그밖에 모니위키에 포함될 새로운 기능들

by dumpcookie 2013. 5. 18. 18:31

XE 게시판과 위키를 연동하는 경우

위키 링크라던지 위키에 관련된 기능이 게시판에도 필요한 경우가 종종 있습니다.

([[위키백과]]같은 위키 링크)


이 애드온은 위키의 링크를 손쉽게 연결시켜 주는 xe 게시판용 애드온입니다



이와 관련된 기능은 xe 사이트의 애드온을 찾아보면 이미 있습니다. (wikilink로 검색하면 몇 개 나옴)


여기서 소개하는 애드온은 위키네임을 링크시켜주는 기능 말고도 모니위키에서 지원하는 일부 기능인 URL을 고쳐주는 기능이 같이 들어있습니다.


예를 들어서 http://rigvedawiki.org/r1/wiki/FrontPage 같은 식으로 예전 링크가 있다면 이것을 rigvedawiki.net으로 고쳐서 자동으로 보여줍니다.


급조한 것이지만 xe 1.7에서 아무런 문제없이 동작하는 것을 확인하였습니다~

1.5에서도 문제없이 될 것으로 생각됩니다.


아직 urlmapping은 xe 사이트에 정식등록한 상태가 아닙니다.


urlmapping 애드온은 위키 관련된 링크를 고쳐주거나 하는 애드온이므로 이것과 관련된 기능 제안을 환영합니다~


TODO

- 인터위키 연결 지원 외


스크린샷 (관리자 메뉴)



다운로드


urlmapping-0.1.tar.gz


by dumpcookie 2013. 5. 10. 15:22
| 1 |