짧은 시간 동안 PHP는 웹 애플리케이션을 위한 대중적인 프로그래밍 언어가 되었다. 초보자도 PHP를 쉽게 설치할 수 있고 배우기도 쉽다. 보다 숙련된 개발자에게는, (V5부터) 강력한 객체 지향 기능을 제공한다. PHP 개발자 커뮤니티는 방대하고, 상당히 많은 오픈 소스와 상용 라이브러리와 툴들이 언어 기능을 확장하고 있다. PHP는 시각적인 결과를 빠르게 나타내기 때문에 많은 사람들로부터 사랑을 받는다.

Perl, Python, Ruby 등 웹 애플리케이션에 사용되는 다른 스크립팅 언어와 마찬가지로 PHP 코드는 파싱되어, opcodes (PHP 엔진을 직접 실행하는 기본 명령)로 변환되고 HTTP가 이를 요청할 때마다 실행된다. 하찮거나 작은 요구에도, 서버는 복잡한 렌더링 프로세스를 즉각적으로 완벽하게 실행한다. 제공되는 페이지의 수가 증가하면서, 해석(interpretation)-즉 재작업(rework)-은 시스템에 부담을 주게 된다. 어떤 경우, PHP 코드의 "컴파일(compilation)"은 코드를 실행하는데 드는 시간보다 더 많이 든다. 따라서, 요구가 많아질수록, 보다 동적으로 해석되고, 생성된 페이지들은 더 많은 리소스들을 요구하게 된다.

여러분의 사이트에서 프로세서와 메모리에 대해 무제한 예산이 할당되었다면, 사이트의 응답시간을 보장하기 위하여 애플리케이션 스택(하드웨어, OS, 데이터베이스, 웹 서버, PHP 코드)를 최적화할 필요가 없을 것이다. 하지만, 돈은 늘 모자라기 마련이므로, 성능 튜닝은 불가피하다. 튜닝은 부족한 시스템에 메모리를 추가하고, OS 매개변수들을 수정하고, 웹 또는 데이터베이스 서버 속도를 앞당기고, 효율성 있는 코드를 재작성 하거나 결합하는 것을 의미한다. 이러한 모든 것들이 효과를 발휘한다.

리사이클(Recycle)

CPU 사이클을 유지하는 방법은 PHP 애플리케이션을 실행하는데 필요한 재작업 양을 줄이는 것이다. 확실히, 매번 같은 PHP 코드를 변환할 필요 없이, PHP 코드가 opcode로 변환된 후에, 원래 코드가 수정될 때까지 계속해서 공급 및 재사용 된다. 사실, 캐싱(caching)-중간 PHP 코드(opcode)를 저장 및 재사용하는 것-은 오픈 소스 Alternative PHP Cache (APC), Turck MMCache for PHP, XCache, eAccelerator, 그리고 상용 Zend Platform 등 여러 PHP 가속기들의 핵심 개념이다. 뒤에 세 가지는 바이트 코드를 캐싱 및 최적화 하면서, 더욱 빠른 속도를 제공한다.

이번 달에는 XCache를 설치, 전개, 설정하는 방법을 연구해 보자. XCache는 비교적 새로운 것으로서, 많은 사이트들은 이를 사용하여 좋은 결과를 얻고 있다. 게다가, PHP 확장으로 구현되기 때문에 구현, 설치, 설정이 쉽다. Apache와 PHP의 재컴파일이 필요하지 않다.

이 글은 XCache V1.2.0에 기반하고 있다. PHP V4.3.11에서 V4.4.4, PHP V5.1.x 에서 V5.2.x, 그리고 PHP V6의 초기 버전들을 지원하고 있다. (XCache는 PHP V5.0.x는 지원하지 않는다.) XCache는 Common Gateway Interface (CGI) 또는 명령행 PHP 인터프리터가 아닌, mod_php와 FastCGI를 사용하여 실행된다. XCache 소스 코드는 FreeBSD, Sun Solaris, Linux®, Mac OS X 등 다양한 시스템에서 구현된다. XCache는 Microsoft® Windows®에서도 구현될 수 있으며, Cygwin UNIX® 에뮬레이션 환경이나 Visual C를 사용한다. Cygwin 또는 원래의 Win32용 XCache를 구현할 수 있다. 마지막의 목표는 PHP의 공식 Win32 릴리스와의 호환성이다.

이 글에서 설명하는 데모는 Apache V2.2.3, PHP V5.2.0, XCache V1.2.0 (2006년 12월 10일 릴리스), Xcode V2.4.1 on Mac OS X V10.4.8 Tiger를 기반으로 한다. 하드웨어 플랫폼은 2-GHz Intel® Core Duo와 2 GB RAM을 갖춘 Apple MacBook이다.

XCache 구현 단계

진행하기 전에, PHP는 그 자체로 실행되고, 여러분 쉘(Shell)의 PATH phpize가 있는 것을 확인한다. GNU Compiler Collection (GCC) 같은 C 컴파일러가 있어야 하고, make m4를 포함하고 있는 개발 툴 수트가 있어야 한다. Mac OS X에서, 무료 Xcode 소프트웨어 개발 환경은 필요한 빌드 툴을 제공한다.

아래 명령어를 완성하여 Mac OS X에서 XCache를 구현, 전개, 벤치마크 한다. 다른 플랫폼에서의 구현도 비슷하다. 리눅스를 사용하고 있다면, 그 배포판에는 XCache가 이미 포함되어 있고, 이를 사전 패키징 된 형태로 사용할 수 있다.

Mac OS X의 공유 메모리 늘리기

Mac OS X의 공유 메모리의 양을 늘리는 것부터 시작한다. /etc/sysctl.conf 파일을 생성(또는 편집)하고 다음 엔트리들을 만든다.


Listing 1. Mac OS X의 공유 메모리 양 늘리기
                
kern.sysv.shmmax=33554432
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.sysv.shmall=8192

이러한 설정으로 공유 메모리의 양이 32MB로 늘어났다. 공유 메모리를 더욱 확장해야 한다면, 하드웨어 페이지 크기로 나뉜kern.sysv.shmmax 값에 kern.sysv.shmall을 설정한다. 이렇게 하면 sysctl hw.pagesize를 사용할 수 있을 것이다. 예를 들어, 128 MB의 공유 메모리가 필요하다면, kern.sysv.shmmax=134217728 kern.sysv.shmall=32768을 설정하라.

수정 사항을 적용하려면 Mac OS X를 재시작 한다. 재부팅 되면 다음을 타이핑 하여 새로운 설정이 적용되었는지를 확인한다.

sysctl -a | grep kern.sysv

소스에서 XCache 구현하기

다음에는, 소스 코드에서 XCache를 구현한다. http://xcache.lighttpd.net에서 소스를 다운로드 한다. 코드가 있다면 이것의 압축을 풀어서 .tar 파일이 만든 새로운 디렉토리로 옮긴다.


Listing 2. 소스에서 XCache 구현하기
                
$ cd /tmp
$ wget http://210.51.190.228/pub/XCache/Releases/xcache-1.2.0.tar.gz
$ tar xzf xcache-1.2.0.tar.gz
$ cd xcache

phpize를 실행하여 XCache가 컴파일을 할 수 있도록 한다.


Listing 3. phpize 실행하기
                
$ phpize
Configuring for:
PHP Api Version:         20020918
Zend Module Api No:      20020429
Zend Extension Api No:   20050606

configure를 실행하여 원래의 OS에 맞는 makefile을 만든다.


Listing 4. configure를 실행하여 makefile 만들기
                
$ ./configure --enable-xcache --enable-xcache-coverager 
checking build system type... i686-apple-darwin8.8.1
checking host system type... i686-apple-darwin8.8.1
...
creating libtool
configure: creating ./config.status
config.status: creating config.h

여기에서, --enable-xcache 옵션에는 XCache 지원이 포함되고, --enable-xcache-coverager에는 가속기의 효율성을 측정할 수 있는 부가 기능이 포함되어 있다. opcode 옵티마이저를 실행하려면 --enable-xcache-optimizer를 추가한다.

물론, 다음 단계는 make 명령어를 사용하여 코드를 구현 및 설치하는 단계이다. make를 실행한 다음, 루트(root)로서 make install을 실행한다.


Listing 5. make를 사용하여 코드를 구현 및 설치하기
                
$ make
...
cp ./xcache.so /Users/strike/tmp/xcache/modules/xcache.so
Build complete.

$ sudo make install
Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20020429/

앞서 두 가지 작업들이 무리 없이 수행되었다면 /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so에 XCache가 있어야 한다.( /usr/lib/php/extensions/no-debug-non-zts-20020429 경로는 사용 중인 API의 버전과 PHP 구현에 사용되는 컴파일 옵션을 반영한다. Zend Thread Safety 기능을 실행했다면 "no-debug"가 "debug"가 되고 "non-zts"가 "zts"가 될 수 있다.)

php.ini 파일 바꾸기

확장본이 설치되었기 때문에, php.ini 파일을 변경하여 XCache 확장을 추가하고 설정하도록 해야 한다. /private/etc/php.ini를 열고 다음 라인을 파일에 추가한다.


Listing 6. XCache 확장용으로 php.ini 변경하기
                
[xcache-common]
zend_extension      = /usr/lib/php/extensions/no-debug-non-zts-20020429/xcache.so

[xcache.admin]
; Change xcache.admin.user to your preferred login name 
xcache.admin.user   = "admin"

; Change xcache.admin.pass to the MD5 fingerprint of your password
; Use md5 -s "your_secret_password" to find the fingerprint
xcache.admin.pass   = "0ad72f3f352fcd8acdf266bafd0ac48d"

[xcache]
; Change xcache.size to tune the size of the opcode cache
xcache.size         = 24M
xcache.shm_scheme   = "mmap"
xcache.count        = 2
xcache.slots        = 8K
xcache.ttl          = 0
xcache.gc_interval  = 0

; Change xcache.var_size to adjust the size of variable cache
xcache.var_size     = 8M
xcache.var_count    = 1
xcache.var_slots    = 8K
xcache.var_ttl      = 0
xcache.var_maxttl   = 0
xcache.var_gc_interval =     300
xcache.test         = Off
xcache.readonly_protection = On
xcache.mmap_path    = "/tmp/xcache"
xcache.coredump_directory =   ""
xcache.cacher       = On
xcache.stat         = On
xcache.optimizer    = Off

[xcache.coverager]
xcache.coverager    = On
xcache.coveragedump_directory = ""

주: 간단히 하기 위해 일부 주석들은 생략했다. 각각의 매개변수가 무엇을 제어하는지를 알고 싶다면 XCache 소스 코드에 포함된 xcache.ini 파일의 샘플 설정을 참조하라.

opcode와 변수 캐시의 크기는 32MB이고, 이것은 /etc/rc에 설정된 최대 사이즈이다. Mac OS X의 경우, xcache.mmap_path는 파일 이름이며, PHP 코드는 MacBook에서 실행되기 때문에, xcache.count  2로 설정된다. 이 숫자는 MacBook에 있는 CPU의 수이다. XCache 통계 페이지로 접근 하려면, xcache.admin.pass 설정을 변경해야 한다. 다음을 실행한다:

$ md5 -s "password"

여기에서 password 는 여러분의 패스워드이다. 결과를 xcache.admin.pass에 복사한다. 예를 들어, 패스워드를 op3nsesam3으로 하고 싶다면, 다음과 같이 한다:

$ md5 -s "op3nsesam3"
MD5 ("op3nsesam3") = cd959ac3debe8f587546a3fa353b3268

그리고 cd959ac3debe8f587546a3fa353b3268 xcache.admin.pass에 복사한다.

웹 서버 재시작

XCache를 설정했다면, Apache 웹 서버를 재시작 한다. 대부분의 시스템에서 루트로서 apachectl restart를 사용할 수 있다.

$ sudo apachectl restart
/usr/sbin/apachectl restart: httpd restarted

phpinfo()를 호출하는 프로그램 만들기

XCache가 실행되는지를 확인하려면, phpinfo()를 호출하는 PHP 프로그램을 만들고 그 파일을 웹 브라우저에서 연다. 아래 그림과 같은 XCache 섹션을 볼 수 있다.


그림 1. phpinfo() 메소드가 XCache 설정을 요약하고 있다.
phpinfo() 메소드가 XCache 설정을 요약하고 있다. 

XCache 모니터링

XCache를 모니터링 하려면, XCache 소스 코드의 admin 디렉토리에 있는 관리 페이지를 설치한다. 전체 admin 디렉토리를 Apache 문서 루트에 복사한다. (Mac OS X에서, 문서 루트는 일반적으로 /Library/WebServer/Documents이다.)

$ cp -pr admin /Library/WebServer/Documents

복사가 완료되면, sudo apachectl restart로 웹 서버를 재시작 한다. 관리 패널이 실행되는 것을 확인하려면 브라우저에서 http://localhost/admin 입력한다. 그림 2와 비슷한 대시보드를 볼 수 있다.


그림 2. XCache Administration 대시보드
XCache Administration 대시보드 

애플리케이션 테스트하기

테스트 할 애플리케이션 한 두 가지를 선택한다. 여러분 코드를 사용하거나, 보다 복잡한 것을 원한다면 phpMyAdmin 또는Serendipity 같은 대형 PHP 애플리케이션을 사용하라.

벤치마크 실행하기

Apache HTTP 웹 서버에는 ab라고 하는 유틸리티가 포함되어 있고, Apache HTTP server benchmarking tool의 약자이다. ab를 사용하여 많은 PHP 페이지에 대한 요청들을 자동화 한다. phpMyAdmin 애플리케이션은 시스템에 이미 설치되어 있으므로 좋은 예시가 된다.

ab 유틸리티는 사용이 간단하며 반복 카운트와 URL을 제공한다. ab 유틸리티는 그 URL을 여러 번 요청하고 통계를 리턴한다. XCache가 이미 실행 중이기 때문에, 첫 번째 벤치마크는 가속화 된 성능을 보여줄 것이다.

ab를 실행하기 전에, 브라우저에서 http://localhost/phpmyadmin/으로 간다. 이 페이지를 한번 방분하면 이 페이지를 캐시로 렌더링 하는데 사용되는 모든 PHP 코드를 로딩한 것이 된다. 아래 벤치마크를 실행하고, 100,000회 반복한다.


Listing 7. phpMyAdmin용 벤치마크
                
$ ab -n 100000 http://localhost/phpmyadmin
...
Concurrency Level:      1
Time taken for tests:   14.597 seconds
Complete requests:      100000
Failed requests:        98262
   (Connect: 49131, Length: 49131, Exceptions: 0)
Broken pipe errors:     0
Non-2xx responses:      50869
Total transferred:      25739714 bytes
HTML transferred:       12005084 bytes
Requests per second:    6850.72 [#/sec] (mean)
Time per request:       0.15 [ms] (mean)
Time per request:       0.15 [ms] (mean, across all concurrent requests)
Transfer rate:          1763.36 [Kbytes/sec] received

위에서 재미있는 통계라 한다면, 초당 요청과 모든 테스트를 완료하는데 드는 총 시간이다. 전자의 경우, 값이 클수록 더 나은 것이다. 후자는 값이 낮을수록 더 나은 것이다.

이제 Listing 8과 같이 php.ini 파일에서 XCache 실행을 멈추고 벤치마크를 다시 실행한다. XCache 확장에 대한 레퍼런스에 주석을 달거나, 모든 XCache 기능들을 꺼둘 수 있다. 벤치마크를 다시 실행하기 전에 Apache를 재시작한다.


Listing 8. XCache를 실행시키지 않은 phpMyAdmin용 벤치마크 
                
$ sudo apachectl restart
$ ab -n 100000 http://localhost/phpmyadmin
Concurrency Level:      1
Time taken for tests:   17.771 seconds
Complete requests:      100000
Failed requests:        98256
   (Connect: 49128, Length: 49128, Exceptions: 0)
Broken pipe errors:     0
Non-2xx responses:      50872
Total transferred:      25741232 bytes
HTML transferred:       12005792 bytes
Requests per second:    5627.15 [#/sec] (mean)
Time per request:       0.18 [ms] (mean)
Time per request:       0.18 [ms] (mean, across all concurrent requests)
Transfer rate:          1448.50 [Kbytes/sec] received

여기에서는 XCache를 실행시키지 않았는데, 초당 요청의 수가 줄어들고, Apache 서버가 각 요청에 더 오랜 시간이 걸린다는 것을 반영하고 있다. 테스트의 전체 수트를 실행하는데 드는 시간도 올라갔다.

비록 이것은 단순한 벤치마크이고, 데이터베이스로 phpMyAdmin을 연결하지 않아 PHP를 해석하는데 프로세싱 시간에 제한이 있었고, 과학적이지도 않았지만, XCache을 이용하여 무엇을 얻을 수 있는지는 확실히 알 수 있다. PHP나 Apache를 재컴파일 할 필요가 없는 적은 투자로 XCache는 비교적 좋은 결과를 만들어 낸다. 이것은 코드가 복잡할수록 그의 효용도 더욱 크다.

XCache가 얼마나 일을 잘하는지 궁금하다면, http://localhost/xadmin으로 가서 List PHP를 클릭하라. 캐시에 PHP 파일 리스트, 캐시 히트, opcode에서 측정된 코드의 크기, 바이트로 측정된 소스 파일의 크기 등을 볼 수 있다. 그림 3은 XCache가 XAMPP 스택 패키지용으로 구현되었을 때 나타난 결과이다.


그림 3. XCache 관리 페이지는 캐시의 상태와 내용을 보여준다.
XCache 관리 페이지는 캐시의 상태와 내용을 보여준다. 

XCache는 많은 가속기 옵션들 중 하나이다. 기타 다른 무료 오픈 소스 대안책들도 있고 강력한 Zend 소프트웨어에 상용 옵션들도 있다. 각각의 PHP 가속기 마다 고유의 시스템 요구 사항들이 있기 때문에, 애플리케이션의 설정과 특성에 맞게 선택해야 한다. 이들 중 어떤 것이 더 낫다고 말하기 어렵지만, 컴파일러 캐시를 설치할 것을 권하고 싶다.

수 많은 튜닝 옵션들

캐싱 외에도, 애플리케이션 속도를 높일 수 있는 다른 대안들도 있다. 많은 난해한 기능들을 제거하여 PHP 엔진에서 지방질을 빼낼 수 있다. 예를 들어, TCP/IP V6 (IPv6) 네트워킹을 사용하지 않는다면, PHP를 구현할 때 이 기능을 실행하지 않으면 된다. PHP 소스 코드 트리의 맨 위에서 ./configure --help를 타이핑 하면 PHP 설정 옵션들의 전체 리스트를 볼 수 있다. 어떤 설정 옵션들을 선택하든지 간에,

--enable-inline-optimization --disable-debug

위 라인을 최종 설정 명령어에 추가한다. 전자 옵션은 가장 빠른 PHP 실행 파일을 만들어 낸다. (Zend Engine 같은 소프트웨어로 추가적인 opcode 최적화가 필요 없다.) 후자 옵션은 디버그 모드에서 PHP를 활용하는데, PHP 애플리케이션 서버의 문제를 해결할 때에만 필요하다.

물론, 다른 C 애플리케이션처럼, C 컴파일러를 활용하여 더 나은 실행 파일을 구현할 수 있다. Apache Dynamic Shared Object (DSO)(Linux) 또는 FreeBSD(x86 프로세서)로서 PHP를 실행한다면 -prefer-non-pic 옵션을 CFLAGS (C 컴파일러 옵션을 저장하고 있는 환경 변수)에 추가하는 것도 고려해 볼만하다. Non-PIC는 위치 독립 코드를 사용하여 PHP를 구현하고, 10%정도의 성능 향상을 보인다.CFLAGS -march를 사용하여 프로세서 유형을 규명할 수 있다. AMD Opteron 프로세서에는 -march=opteron을 사용한다.

또 다른 속도 향상 옵션으로는 opcode optimization이 있다. Zend Engine 같은 소프트웨어는 컴파일 동안 생성된 opcode를 최적화 하기 때문에 코드가 수행하는 작업량이 줄어든다.

캐싱과 최적화는 투명할 뿐만아니라 부가적인 프로그래밍 요소들이 필요 없다. 보다 힘든 작업에 적용하려면 프로파일링(profiling) 또는 코드가 어디에서 시간을 소비하는지를 검사하는 것도 좋다. 낭비가 많고 느린 알고리즘만큼, 병목 현상도 분명한 재작업의 원인이 된다. 사이클을 보강하기 위해 코드를 조정하는 것도 좋지만, 프로파일링을 선행하지 않고 어떤 최적화도 시도해서는 안된다.

예고

다음 회에는 최적화를 주제로 여러분을 찾아오겠다. 디버깅, 빠른 텍스트 검색, 대안 웹 서버 등에 대해서도 설명하겠다. 그 동안 여러분은 PHP 가속기와 opcode 최적화에 대해 복습하기 바란다. 조금만 시간을 들여 공부하면 많은 깨달음을 얻을 수 있을 것이다. 여러분의 머신이 여유 사이클로 무엇을 할 수 있는지를 상상해 보라.

기사의 원문보기


참고자료

교육

  • PHP.net - PHP 개발자를 위한 관련 자료

  • 추천 PHP 문서 리스트 

  • PHP 관련 기술자료 리스트 (developerWorks)

  • PHP 관련 기술자료 리스트 (한국 developerWorks)

  • PHP 스킬을 넓히고 싶다면 IBM developerWorks의 PHP project resources를 참고하세요.

  • developerWorks podcasts에서 소프트웨어 개발자들의 재미있는 인터뷰나 토론을 볼 수 있습니다.

  • developerWorks technical events and webcasts.

  • IBM 오픈 소스 개발자들의 최신 컨퍼런스, trade show, webcast와 기타 이벤트 

  • 한국 developerWorks 오픈 소스 존 - 오픈 소스 기술을 사용하고, IBM의 제품들과 함께 사용하는데 있어서 도움이 될 만한 HOT-TO 정보, 툴, 프로젝트 업데이트를 만나보십시오. Eclipse, Globus/Grid, Apache, Derby/Cloudscape, Linux, PHP, Perl, Python을 비롯하여 라이센싱과 오픈 소스 개발과 관련한 주제들을 다루고 있습니다.

  • Safari Books Online 방문하면 오픈 소스 기술에 대한 좋은 자료를 찾아 볼 수 있습니다.

제품 및 기술 얻기

토론

필자소개

Martin Streicher는 Linux Magazine의 편집장이며, Hesketh.com에서는 웹 개발자로, developerWorks의 기고자로 활동하고 있다. 퍼듀대학교에서 컴퓨터 공학 석사 학위를 받았으며, 1986년부터 유닉스 계열 시스템을 프로그래밍 하고 있다.

'Language > PHP' 카테고리의 다른 글

PHP 자동링크생성  (0) 2011.03.16
php 회원가입폼 제작시 유용한 정규표현식함수  (0) 2009.04.21

+ Recent posts