기본 콘텐츠로 건너뛰기

빠른 것이 미덕, Rasmus Lerdorf의 Simple is Hard 리뷰

빠른 것이 미덕, Rasmus Lerdorf의 Simple is Hard 리뷰

Rasmus 아저씨의 "Simple is Hard"라는 PT 중 PHP 성능에 관한 내용 일부를 소개해볼까 한다. 이 아저씨의 Simple is Hard라는 PT가 좀 여러 버전이 있는데, 2008년 DrupalCon 발표자료를 참고했다. 예전에 소개했던 자료랑 거의 비슷하긴 한데 좀 추가된 내용이 있어서 재탕을 해볼까 한다.

그나저나, 참 뭐 하나 만들고 운영하고 하는데 신경 쓸 일이 한두 가지가 아니다. 설계도 중요하고, 보안도 생각해야되고, 성능도 빼놓을 수 없고 ... 잘 한답시고 주구장창 붙잡고 있어도 안 된다. 인생은 타이밍이니까. 그런데 요즘 HipHop도 공개되고 그러는 분위기니까 '성능'이란 주제에 대해 좀 더 생각해보는 시간을 갖도록 하자. 안그래도 구글이 빠른 웹사이트에 랭킹 보너스를 줄지도 모른다는 얘기도 있고. 빠른 웹사이트가 빠르면 좋은거다.

오늘은 잡설은 짧게 끝내고 본론 바로 갑니다. 이 PT는 Scalability, Performance, Security 이렇게 세 부분으로 나뉜다. Scalability는 한국말로 옮기기가 참 애매한데, 확장성이라고 주로 옮기기는 하는 모양이지만 꼭 그 뜻은 아니고, 간혹 가용성 이렇게 옮기기도 하는데 꼭 그 뜻도 아닌 것 같다. 아.. 이것도 본론은 아닌데. 다음 문단부터 본론 나갑니다.

이 자료에서 Rasmus 아저씨는 "PHP가 성능상의 병목이 되는 경우는 흔치 않지만, 몇 가지 도구를 써서 성능을 향상하는 기법을 소개합니다.

8페이지부터 시작합니다. 우선 Laconica, Habari, Wordpress, Magento를 차례대로 Siege로 테스트합니다. 표 안의 숫자는 높을수록 빠른거에요. 1초에 몇 번의 트랜잭션(즉 페이지뷰)을 처리하는지. (Siege는 Apache ab랑 비슷한 벤치마킹 툴)

일단 APC를 안 쓸 이유가 없다는 걸 알 수가 있다. APC는 eAccelerator같은 OP Code Cache의 하나다. Rasmus 본인이 개발한거고. 보통은 eAccelerator를 많이들 쓰던데 특별한 이유는 모르겠다. 내 경우 APC나 eAccelerator에서 문제가 있던 부분을 xCache(lighttpd 개발자가 만든 OPCode cacher)를 써서 해결본 경험이 있기는 하다. 자세하게 분석하거나 벤치마킹 해본 건 아니니 그냥 참고하시라고.

이어서 10페이지부터는 System call overhead를 줄여서 성능상의 이득을 얻는 과정이 나온다. 이를테면 Apache httpd.conf에 DirectoryIndex index.php를 명시해줘서 index.html index.cgi index.pl index.php를 차례대로 찾는 수고를 줄이는 것 만으로도 시스템콜을 절약할 수 있다는 얘기다. 개발자로서는 놓치기 쉬운 부분 되겠다.

다음은 include_path다.

;include_path = ".:/usr/local/lib/php"

include_path = "/usr/local/lib/php:."

현재 디렉토리(.)를 먼저 찾은 다음에 /usr/local/lib/php를 찾도록 되어있던 걸 순서만 바꿔준건데 이것만으로 시스템콜이 많이 줄어든 걸 볼 수 있다.

수정하기전:

close(10) = 0

getcwd("/var/www/laconica", 4096) = 18

time(NULL) = 1216449985

lstat64("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

lstat64("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

lstat64("/var/www/laconica", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

lstat64("/var/www/laconica/PEAR.php", 0xbffcf5fc) = -1 ENOENT (No such file or directory)

open("/var/www/laconica/PEAR.php", O_RDONLY) = -1 ENOENT (No such file or directory)

time(NULL) = 1216449985

open("/usr/local/lib/php/PEAR.php", O_RDONLY) = 10

fstat64(10, {st_mode=S_IFREG|0644, st_size=34813, ...}) = 0

stat64("./PEAR.php", 0xbffd1654) = -1 ENOENT (No such file or directory)

stat64("/usr/local/lib/php/PEAR.php", {st_mode=S_IFREG|0644, st_size=34813, ...}) = 0

close(10) = 0

수정한다음:

close(10) = 0

time(NULL) = 1216450700

open("/usr/local/lib/php/PEAR.php", O_RDONLY) = 10

fstat64(10, {st_mode=S_IFREG|0644, st_size=34813, ...}) = 0

stat64("/usr/local/lib/php/PEAR.php", {st_mode=S_IFREG|0644, st_size=34813, ...}) = 0

close(10) = 0

각각이 뭐하는건지 자세히는 모르더라도, 여러 디렉토리에서 파일이 있나없나 찾아보는데 시간을 많이 썼었다는 걸 짐작해볼 수 있다. 이렇게 고치고 나니 45.37 trans/sec 나오던 것이 46.63 trans/sec으로 빨라졌다. 2.7% 빨라진건데, 큰 수치가 아니라 생각할지도 모르지만 소스코드 한 줄 안 고치고 이정도면 대단한거다. 시스템이 크고 바쁠수록 더.

그런데 혹시나 해서 부연 설명하는건데, 무조건 저렇게 고친다고 빨라지는게 아니라, 로그를 남기고 그걸 분석해서 뭘 할지 정해야된다. "아, include_path에 .를 무조건 마지막에 넣는구나."와 같은 결론을 내리면 곤란하다.

다음은 apc.stat값을 0으로 바꾸는 것이 어떤 영향을 미치는지를 보여주고 있다. apc.stst은 APC OP cache의 설정값 중 하나인데 소스코드가 거의 바뀌지 않는 상황(예를들어 실제 운영중인 서버)에서 유용하게 쓸 수 있다. 이 값은 기본이 켜진(1) 상태인데, 이 상태에서는 APC가 혹시 소스코드에 바뀐게 있나 계속 검사를 한다. 그런데 이걸 꺼버리면(apc.stat=0) 웹서버를 재시작하거나 강제로 캐시를 비우지 않는 한 계속 캐시된 OP Code를 쓴다. 메뉴얼에 다 나온 내용이니 RTFM하시기 바란다. 이런류의 설정은 굉장히 유용하긴 한데 정확한 의미를 모르고 쓰거나, apc.stat=0으로 해놓고 까먹거나 하게되면 "왜 고쳤는데 반영이 안 되는거야!?" 따위의 어이없는 혼선을 빚을 수 있다.

왼쪽이 apc.stat 고치기 전, 오른쪽이 후.

왼쪽에는 있는 것들 중에 오른쪽에는 안보이는 것들이 좀 있다. 그만큼은 절약이 된거라고 보면 되겠다. 벤치마크 결과를 확인해보면 46.15 trans/sec. 큰 의미는 없는 수치로 보인다. 하지만 로그에서 보았듯이 실제로는 절약되고 있기 때문에 아주 바쁜 상황에서라면 고려해볼 수 있는 방법이다.

14, 15장에서는 include hierarchy를 고쳐 성능상의 이득을 보는 방법을 설명한다. include 계층이 어떻게 되는지 조사하는데 PECL/Inclued(스펠링 주의. 오타아님)를 쓴다. 쪼고만 모니터에서 비교해보느라 눈 빠지는 줄 알았다.

위가 시술전 아래가 시술후다. 이 아저씨가 뭘 어떻게 고쳤는가 모르겠다만, 내가 이해한 건 이렇다. 시술전에는 common.php가 DataObject.php를 require_once함에도 불구하고, common.php가 불러들이는 다른 여러 파일들이 DataObject.php를 또 불러댄다. 즉 점선으로 표시된 의존관계 중 어떤 것들은 군더더기라는 뜻이다. 이런식으로 몇 군데를 고친 것 같은데 다들 숨은그림 찾듯이 찾아보시고 저도 좀 알려주세요. 30인치 모니터가 있으면 저도 볼 수 있는데....

중요한게, 그래서 얼마나 효과를 봤느냐? 46.15 에서 49.84로 뛰었다. 1%에 조금 못 미치지만 괜찮지 않습니까?

지금까지는 주로 설정이나 순서 이런걸 바꿔서 효과를 보는, 상대적으로 쉬운 방법들이었다. 이번에는 프로파일링을 해 본다. 프로파일링 툴로 valgrind나 xdebug를 쓴다. 프로파일링 결과를 여기서 보는것처럼 그래프로 그려서 볼 수도 있는데, 꼭 그래프로 안 봐도 되기는 하지만 이렇게 보면 멋있기는 하다. 암튼 결과를 보고 어느 함수가 자원을 많이 잡아먹는지를 확인할 수 있다. 확인했는게 그 루틴이 너무 중요한거면 어쩔 수 없지만 만약 대안이 있다면 .....

첫 번째 사례로 Remove some XMLWriter code라는걸 소개했는데, 아마 꼭 필요하지 않은 코드였거나 좀 더 가벼운 (자원 덜 먹는) 코드로 대체했다는 뜻인 것 같다. 특히 XML하고 관련된 것들이 메모리나 자원을 엄청 잡아먹는 경향이 있는데 간단한 XML이라면 DOM이나 OO스타일의 라이브러리 안 쓰고 그냥 문자열로 만들어도 된다는게 내 생각이다.

두 번째 케이스에서는 PHP가 시스템의 기본 Timezone을 쓰느라 헛짓하는 걸 간단하게 php.ini파일에 date.timezone 설정을 추가해서 정리해준다. 이렇게만 해줘도 160 trans/sec정도였던 것이 180으로 향상되었다.

다음이 진짜 재밌는데, 내가 이걸 보면서 "앗 정리해서 포스팅해봐야겠다"고 생각했었다. 간단하게 "Hello World"만 출력하는 루틴의 성능을 비교해보는건데 Plain HTML부터 CakePHP, CodeIgniter, Zend Framework 등 널리 쓰이는 프레임웍에다 .. 두둥 .. Drupal 6.4도 같이 비교를 해놔서 아주 재밌었다. (DrupalCon에서 발표한거니까 ㅋㅋ) 이 페이지부터 차례로 넘겨보면 되겠다. 행여나 이런 단순 벤치마크를 가지고 확대해석하는 분들은 없었으면 하는게 나의 작은 소망이자 바램이다.

Method transactions / sec Plain HTML 611.78 Trivial PHP 606.77 CakePHP 1.2.0.rc2 25.88 Symfony 1.1 100.63 Solar 1.0.0alpha1 271.18 Agavi 1.0-beta1 (production) 126.91 Zend Framework 1.6.0-rc1(with include_path tweak) 130.08 CodeIgniter 1.6.3 305.90 Prado 3.1.2 76.95 Drupal 6.4 51.37

참 가지각색이죠? 2년차 드루팔러로서 변호를 좀 해보자면, 드루팔은 다른 MVC 웹프레임웍하곤 좀 다르죠. 그것들보다는 좀 더 상위에 있다고 보는게 맞고, 아무리 Hello World만 출력하는 모듈을 짜넣었다고 해도 기본적으로 권한이라던가 캐시라던가 DB연결 이런게 다 돌아가고 있다는겁니다. 그러니까 단순비교는 무리.

자 지금까지 Simple is Hard라는 라스무스 아저씨의 발표자료를 살펴봤다. 직접 발표장에 간 것도 아니고 동영상을 본 것도 아니라 내가 잘못 이해한게 있을지도 모르겠지만 손가락을 보지 말고 달을 보는 지혜를 발휘해보도록 하자.

from http://hardworker.tistory.com/102 by ccl(A) rewrite - 2020-03-07 09:55:44

댓글

이 블로그의 인기 게시물

PHP framework 종류

PHP framework 종류 분류 전체보기 (1461) API (0) Android (19) Common (11) Component (0) adb (2) DDMS (1) GCM (4) HTTP (0) sqlite (1) View (0) build (0) Bigdata (4) Common (1) Hadoop (2) Spark (0) SQL on Hadoop (1) Cloud (12) Common (8) Multitenancy (2) OpenStack (0) UCloud (2) Computer Science (24) Common (4) Asynchronous IO (1) Cache (6) Distributed (0) Message Queue (1) Parallel Computing (5) Software Engineering (7) DB (172) Common (32) HSQLDB (1) In-memory DB (0) MariaDB (2) MongoDB (30) MySQL (69) NoSQL (8) Oracle (17) ORM (6) Redis (1) SQL Server (6) Design Pattern (7) Common (7) Programming paradigms (0) Reactor (0) Development (459) Common (37) AngularJS (3) Bootstrap (3) C (22) C++ (0) CSS (32) HTML (31) HTML5 (2) Java (118) JavaEssential (25) JSP & Servlet (33) JavaScript (69) jQuery (26) jQuery Mobile (4) Linux Programming (3) python (3) PHP (21) Reactive Streams (0) ShellScript (5) UML (6) Windows Programming (2) XML (14) Framework & Platform (161) Common (8) EFL (1) mybati

MariaDB 에서 access denied for user 'root' 문제

MariaDB 에서 access denied for user 'root' 문제 heidisql 등의 원격 접속 툴을 이용해도 접속이 안 됐다. 포트, 방화벽 설정 등등 모두 확인해 봤고 로컬에서 잘 돌아가는 데도 원격 접속이 안됐다. 사실 원격 접속만 안 되면 상관 없는데, codeigniter에서도 똑같이 로그인을 못해서 자꾸 에러가 났었다. 일단, MariaDB는 10.4부터 root 권한 소유자에게 따로 비밀번호를 물어보지 않는다. 즉, 루트 계정으로 로그인했으면 그냥 콘솔에 mysql 치면 접속이 된다. 물론 다른 유저는 전처럼 비밀번호를 물어본다. 나는 이 root 계정으로 로그인을 며칠째 계속 시도해 봤는데 계속 안됐다.... 포트 문제도 아니었고 딱히 통신 문제도 아니었다. 심지어 SSH 접속 계정도 root 였다. 해답은 새로운 계정을 파서, 그 계정으로 접속을 하니까 잘 됐다. 계정 만드는 SQL 문이야 검색하면 바로 나올 거니까 따로 적진 않겠다.사실 별 내용 없는 건 아는데 새 계정을 파서 시도하란 말을 며칠 내내 구글을 뒤진 다음에야 본 것 같아서, 혹시 같은 어려움을 겪는 사람들이 있다면 빨리 해결할 수 있었으면 좋겠다. from http://skyseven73.tistory.com/5 by ccl(A) rewrite - 2020-03-11 02:54:31

[공학] 목차

[공학] 목차 자동차공학 컴퓨터공학 컴퓨터공학 | 개발환경 컴퓨터공학 | 웹개발 컴퓨터공학 | 모바일개발 ✓ 컴퓨터공학 | 운영체제 컴퓨터공학 | 프로그래밍 컴퓨터공학 | 네트워크 컴퓨터공학 | 데이터베이스 from http://sanctacrux.tistory.com/679 by ccl(A) rewrite - 2020-03-12 16:54:22