테스트 환경
OS : Red Hat Enterprise Linux AS release 4 (Nahant)
Kernel Version : 2.6.9-5.ELsmp
CPU & Cache : 2 Xeon(TM) CPU 3.06GHz 3057MHz, 512 KB Cache
Memory : 2G
Swap : 4G
Web server : Apache Http Server 2.0.52
Web test tool : ab, Httperf, flood
테스트 계획
rpm 설치후 기본 상태에서 설치된 웹서버에 동시 접속자 1000 명이 1000 번의 요청을 하는 경우를 테스트하여 웹서버의 성능을 측정한다.
다양한 환경설정을 변경해서 웹서버를 튜닝한 이후 다시 동일한 환경으로 테스트해서 실제적인 성능향상이 있는지를 점검한다.
테스트 케이스
1) ab -n 1000 -c 1000 -t 10 http://210.183.235.95/
2) httperf --server 210.183.235.95 --port 80 --rate 1000 --num-conns 20000 --hog
3) flood floodconf..xml > result.out (floodconf.xml 파일에 환경설정)
기본설치후 아파치 성능 테스트
웹사이트가 느리면 고객은 바로 다른 사이트로 이동하기 마련이다.
따라서 기업은 고객을 확보, 유지하기 위해 웹사이트의 성능을 최상의 상태로 유지해야하며 이로 인해 웹사이트의 성능을 진단하고 분석하는 도구들에 대해서 많은 관심을 가지고 있으며 현재 기업들마다 다양한 방법들로 성능을 관리하고 있다.
상용 SW |
공개 SW |
● WEBest ● SiteAngel ● sitemonitor ● WatchPro/TestPro ● WEBest |
● ab ● Flood ● Httperf ● Hammerhead ● Web Performance Tool (WPT) |
표 1. <웹서버 성능테스트 프로그램 비교>
웹서버의 성능을 측정하기 위해서 먼저 공개SW 벤치마크 프로그램 ab, Flood, Httperf 에 대해서 알아보기로 하자.
ab
ab는 "Apache HTTP server Benchmarking tool" 의 약어로서 아파치서버의 응답속도를 측정하는 밴치마킹툴이다. 이 툴은 현재 설치된 아파치서버의 실행속도 및 성능테스트를 위해서 제우스테크널리지(Zeus Technology Ltd, http://www.zeustech.net/)의 Adam Twiss가 개발한 툴이며. 아파치를 설치하고 나면 기본적으로 설치되므로 별도의 설치 과정 없이 바로 사용할 수 있다.
명령어위치: /usr/local/apache/bin/ab
(RPM설치시 : /usr/bin/ab)
아래는 ab를 이용해서 -c(한번에수행할 다중요구수) 값을 1000으로하고, -n(페이지요청수) 값을 1000 으로 하였으며 -t(테스트허용 최대시간)값을 10으로 주는 예이다.
[root@www ~]# ab -c 1000 -n 1000 -t 10 http://210.183.235.95/
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.141 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Server Software: Apache/2.0.52
Server Hostname: 210.183.235.95
Server Port: 80
Document Path: /
Document Length: 440 bytes
Concurrency Level: 1000
Time taken for tests: 10.6038 seconds
Complete requests: 13416
Failed requests: 0
Write errors: 0
Total transferred: 8176434 bytes
HTML transferred: 5907440 bytes
Requests per second: 1340.79 [#/sec] (mean)
Time per request: 745.829 [ms] (mean)
Time per request: 0.746 [ms] (mean, across all concurrent requests)
Transfer rate: 797.92 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 286 1301.0 4 9005
Processing: 21 148 467.1 95 6437
Waiting: 17 135 424.3 87 6434
Total: 57 434 1457.6 108 9703
Percentage of the requests served within a certain time (ms)
50% 108
66% 120
75% 127
80% 135
90% 179
95% 3076
98% 9068
99% 9076
100% 9703 (longest request)
ab 의 측정결과에서 다음과 같은 내용을 분석할수 있다.
Server Software |
아파치버전을 표시 |
Server Hostname |
특정사이트의 이름(도메인명) |
Server Port |
웹서비스 사용포트번호 |
Document Path |
초기 문서가 준재하는 웹문서 root위치 |
Time take for tests |
응답시간(매우 중요한 결과 값임) |
Document Length |
초기문서(대부분 index.html, index.htm)의 용량크기 |
Complete requests |
요구에 응답완료한 세션수 |
Failed requests |
요구에 응답실패한 세션수 |
Broken pipe errors |
실패한 에러수 |
Total transferred |
총 전송바이트수 |
HTTP transferred |
총 전송한 HTML바이트수 |
Requests per second |
초당응답요구수 |
Time per request |
요구에 응답한 시간(단위 micro second, 중요한 결과값) |
Time per request |
요구에 응답한 시간 |
Transfer rate |
초당전송가능한 용량 |
표 2. <ab 의 결과분석>
Httperf
Httperf 툴은 요청이 발생하는 비율, 총 연결 수, 타임아웃 한계 등을 제어할 수 있다.
다운로드는 http://www.hpl.hp.com/research/linux/httperf/ 에서 가능하며 설치는 일반적인 소스설치법과 동일하게 ./configure ; make; make install 로 진행할수 있다.
사용할 수 있는 옵션은 아래와 같다
--server 서버주소 |
여기에 적어 준 서버로 접속을 시도한다 |
--port 숫자 |
여기에 적어 준 포트로 접속을 시도한다 |
--num-conns 숫자 |
총 몇개의 접속을 만들 것인지를 결정한다. |
--rate 숫자 |
초당 몇개의 접속을 만들 것인지를 결정한다. |
--timeout 숫자 |
숫자만큼의 초 이후 응답이 없는 연결은 timeout 에러로 처리한다. |
--think-timeout 숫자 |
CGI등 서버쪽에서 처리해야 하는 일들이 있는 페이지의 경우 서버측에 이를 처리할 시간을 준다. timeout에서 이곳에 주어진 숫자만큼을 더한 값이 진짜 timeout값이 된다. |
--hog |
가능한 모든 포트를 사용한다. 이 옵션을 주지 않으면 기본적으로 1024부터 5000까지의 포트만 사용한다. |
표 3.<httperf 의 주요옵션>
아래 예제는 210.183.235.95 웹서버의 80번 포트로 1초에 1000개씩 총 20000개의 접속을 만들게 된다.
[root@www ~]# httperf --server 210.183.235.95 --port 80 --rate 1000 --num-conns 20000 --hog
httperf --hog --client=0/1 --server=210.183.235.95 --port=80 --uri=/ --rate=1000 --send-buffer=4096 --recv-buffer=16384 --num-conns=20000 --num-calls=1
Maximum connect burst length: 8
Total: connections 20000 requests 20000 replies 20000 test-duration 20.000 s
Connection rate: 1000.0 conn/s (1.0 ms/conn, <=540 concurrent connections)
Connection time [ms]: min 0.3 avg 70.5 max 3006.4 median 1.5 stddev 422.3
Connection time [ms]: connect 60.8
Connection length [replies/conn]: 1.000
Request rate: 1000.0 req/s (1.0 ms/req)
Request size [B]: 65.0
Reply rate [replies/s]: min 978.7 avg 1000.0 max 1021.5 stddev 17.5 (4 samples)
Reply time [ms]: response 9.6 transfer 0.0
Reply size [B]: header 169.0 content 440.0 footer 0.0 (total 609.0)
Reply status: 1xx=0 2xx=20000 3xx=0 4xx=0 5xx=0
CPU time [s]: user 3.83 system 14.57 (user 19.2% system 72.9% total 92.0%)
Net I/O: 658.2 KB/s (5.4*10^6 bps)
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
Flood - a profile-driven HTTP load tester
Flood 는 아파치 프로젝트 하위의 프로젝트이다
XML 설정파일을 필요로 하며, URL 과 POST data 를 여러 서버들에 테스트할수 있다.
현재 Flood 는 Subversion 으로 관리되고 있으며 설치시에 자동으로 소스 디렉토리 하위에서 apr 과 apr-util 패키지를 찾으므로 아래처럼 체크아웃해서 설치하면 된다.
만일 apr 과 apr-util을 이미 받아온 상태라면 configure 할때 --with-apr and --with-apr-util 옵션을 사용해서 경로를 지정해주면 된다
% svn co http://svn.apache.org/repos/asf/httpd/test/trunk/flood
% cd flood
% svn co http://svn.apache.org/repos/asf/apr/apr/trunk apr
% svn co http://svn.apache.org/repos/asf/apr/apr-util/trunk apr-util
% ./buildconf
% ./configure --disable-shared
% make all
설치가 정상적으로 진행되었으면 설치한 디렉토리에서 아래처럼 확인할수 있다
% ./flood examples/round-robin.xml > foo.out
결과 파일을 다른프로그램에서 활용하고 싶은 경우는
% ./examples/analyze-relative foo.out 를 실행해보면 참고할수 있다.
analyze-relative 파일은 테스트 결과값을 가공하는 간단한 스크립트이다.
Flood 에 대해서 보다 상세한 정보를 원한다면 http://httpd.apache.org/test/flood/faq.html 를 방문하자.
아래는 floodconf.xml 파일을 이용해서 테스트 하는 부분이다. xml형식의 환경설정 파일을 설정하는 방법은 http://httpd.apache.org/test/flood/ 를 방문해서 참고하기 바란다.
[root@www ~]# flood floodconf.xml > result.out
[root@www ~]# ./analyze-relative result.out
Slowest pages on average (worst 5):
Average times (sec)
connect write read close hits URL
0.0018 0.0019 0.0081 0.0082 29126 http://210.183.235.95/
Requests: 29127 Time: 0.80 Req/Sec: 41776.74
설정변경을 통한 아파치 성능 최적화
아파치는 httpd.conf 파일을 이용해서 성능과 안정성 그리고 보안을 각각 구현할수 있다. 이제부터 리눅스에서 아파치 웹서버를 최상의 상태로 운용하기 위하여 성능을 향상시킬수 있는 아파치의 설정 지시자들을 살펴보기로 하자.
Timeout
접속된 클라이언트가 서버에 아무런 요청이 없을 때 어느정도 시간이 지나면 연결을 끊을지를 초단위로 설정한다. 네트웍의 성능이 낮을수록 이 수치를 높게 설정하는 것이 좋다.
MaxClients
웹서버 성능에 가장 큰 영향을 주는 것은 메모리다. 방문자의 요청에 응답하기 위해서 프로세스가 생성되는되 이 지시자의 개수만큼만 생성가능하다. 여기서 지정한 개수 이상의 요청이 들어오면 아파치는 요청을 무시한다.
MaxClients 지시어를 조절하여 웹서버가 스왑을 할 정도로 많은 프로세스를 만들지 않도록 해야 한다. 스왑은 요청당 지연시간을 늘리기 때문에 웹서버는 스왑을 하면 안된다. top으로 프로세스 목록을 보고 아파치 프로세스의 평균 메모리 사용량을 알아낸후, 사용가능한 메모리의 양만큼 조절해준다
KeepAlive
아파치의 한 프로세스가 접속한 클라이언트의 지속적인 요청작업을 계속해서 처리하게 할 것인지를 결정하는 지시자. 이 지시자의 값을 On으로 되어 있어야 MaxKeepAliveRequests , KeepAliveTimeout 지시자가 유효하게 된다
MaxKeepAliveRequests
이전의 KeepAlive 지시어가 On 일때만 유효하다. KeepAlive 를 이용해서 한 프로세스가 접속한 클라인언트의 이어지는 요청을 모두 처리하도록 설정했는데, 이때 무한정 계속 처리하는것이 아니라 이 지시자를 이용해서 처리할 횟수를 지정해준다. MaxKeepAliveRequests 100 처럼 설정해두면 프로세스가 100번의 요청을 처리한후 자신은 죽고 그다음 프로세스가 다시 클라인언트의 요청을 이어서 처리하도록 하는것이다. 방문자가 많은 홈페이지라면 이 값을 좀 올려두는것이 좋다
KeepAliveTimeout
이전의 KeepAlive 지시어가 On 일때만 유효하다. KeepAlive 를 사용한다면 프로세스들은 이미 열린 연결에서 추가 요청을 기다리며 대기중이다.
KeepAliveTimeout 15 처럼 설정해두면 클라이언트가 15초동안 아무요청이 없으면 프로세스의 연결을 끊는다. 이 값을 60 초 이상으로 올리면 사용자의 요청을 기다리며 아무일을 하지않는 프로세스가 60초동안 떠있게 되는것이다. 자신의 네트웍대역과 부하에 따라 적절히 조절하자. 기본값 15 로도 무방하다
StartServers
아파치 시작시에 실행시킬 프로세스의 개수. 뒤에나오는 MinSpareServers, MaxSpareServers 등의 지시자에 의해서 프로세스는 생성되기도 하고 죽기도 하므로 큰 의미를 가지는것은 아니다.
MinSpareServers
항상 대기하고 있을 프로세스의 최소개수. 여기서 지정한 숫자보다 적은 프로세스가 대기되어 있다면 아파치는 가능한 이 숫자를 유지하기위해 노력한다.
MaxSpareServers
항상 대기하고 있을 프로세스의 최대개수. 여기서 지정한 숫자보다 많은 프로세스가 대기되어 있다면 아파치는 가능한 이 숫자를 유지하기위해 노력한다.
MaxRequestsPerChild
하나의 프로세스당 최대 처리할 수 있는 방문자의 요청횟수
서버사양이 좋다면 이 값을 높여 두는것이 시스템의 부하조절과 자원낭비를 방지하는데 좋다.
HostnameLookups
웹서버의 로그(access_log)에 보면 클라이언트의 IP가 기록되어있는데 이 지시자를 On으로 설정하면 IP주소를 도메인명으로 기록하기위해서 노력을 하게된다.
아파치 1.3 이전에 HostnameLookups의 기본값은 On이였다.
이말은 접속을 요청하면 DNS를 검색해서 접속자의 호스트명을 알아내어야 한다는것이다,. 아파치 1.3에서 이 설정의 기본값이 Off로 변경되었다.
아파치의 성능을 생각한다면 반드시 Off 로 설정하기 바란다.
만일 로그파일의 주소를 호스트명으로 변환할 필요가 있다면 아파치에 포함된 logresolve 프로그램을 사용해서 나중에 할수있으니 실제 사용하는 웹서버가 아닌 다른 컴퓨터에서 로그파일을 후처리하길 바란다.
다른 설정에서 DNS 질의 고려
Allow from domain이나 Deny from domain 지시어를 사용한다면 (즉, IP 주소가 아닌 호스트명이나 도메인명을 사용한다면) 부득이 중복-역 DNS 검색을 (역검색을 한후 악의로 변경되었는지 확인하기위해 다시 검색) 해야 한다. 그러므로 성능을 높이기 위해 이런 지시어에는 가능하면 이름대신 IP 주소를 사용하자
FollowSymLinks와 SymLinksIfOwnerMatch
가능하면 심볼릭링크를 허용하지 않는것이 보안상 좋다. 하지만 꼭 써야한다면 Options SymLinksIfOwnerMatch 보다는 Options FollowSymLinks를 사용하라
Options SymLinksIfOwnerMatch 일 경우 아파치는 심볼릭 링크를 검사하기위해 시스템호출을 한번 더 해야 한다. 좋은 성능을 얻으려면 SymLinksIfOwnerMatch는 피하자
AllowOverride
AllowOverride 는 이전에 설정된 아파치 환경설정을 무시하고 새로운 설정을 적용하는 방법에 대한 설정이다. AccessFileName 을 별도로 설정하지 않았다면 아파치는 .htaccess 파일을 디렉토리 접근인증에 사용한다.
설정할수 있는 지시자는 다음과 같다.
AuthConfig
AuthDBMGroupFile, AuthDBMUserFile, AuthGroupFile, AuthName, AuthType, AuthUserFile, require 등과 같은 클라이언트 인증지시자의 사용을 허용.
FileInfo
AccessFileName 으로 지정한 파일에 대하여 AddEncoding, AddLanguage, AddType, DefaultType, ErrorDocument, LanguagePriority 등과같은 문서유형을 제어하는 지시자 사용을 허용
Indexes
AccessFileName 으로 지정한 파일에 대하여 AddDescription, AddIcon, AddIconByEncoding, DirectoryIndex, FancyIndexing 등과같은 디렉토리 인덱싱을 제어하는 지시자 사용을 허용
Limit
AccessFileName 으로 지정한 파일에 대하여 allow, deny, order 같은 호스트접근을 제어하는 지시자사용을 허용
Options
AccessFileName 으로 지정한 파일에 대하여 Options 지시자를 이용한 재설정을 허용
All
위에서 이야기한 모든 것을 허용
None
AccessFileName 으로 지정한 파일을 무시. 어떠한 설정도 재설정 할수 없다.
만일 overrides를 허용한다면 아파치는 파일명의 각 부분마다 AccessFileName 으로 지정한 파일(대부분 .htaccess)을 열길 시도한다. 예를 들어 설정은 아래와 같고,
DocumentRoot /www/htdocs
<Directory />
AllowOverride all
</Directory>
/index.html URI에 대한 요청이 있다고 가정하자.
아파치는 /.htaccess, /www/.htaccess, /www/htdocs/.htaccess를 매번 열려고 시도한다. 최고의 성능을 얻으려면 항상 AllowOverride None을 사용하자.
EnableMMAP
커널에서 메모리매핑(mmap)을 지원한다면 아파치가 웹문서를 로딩하기 위하여 내부문서를 읽을때에 파일을 메모리 매핑하여 처리한다. 따라서 아파치의 성능이 크게 향상될수 있다.
그러나 메모리대응이 서버의 성능을 떨어트리고 심지어 안정성을 해치는 경우가 있고 smp Solaris 서버에서 아파치 2.0은 종종 mmap을 사용하지 않을때가 더 빠르다. 또한 NFS 마운트한 파일시스템에 있는 파일을 메모리 대응하는 도중에 다른 NFS 클라이언트에 있는 프로세스가 파일을 지우거나 파일크기를 줄이면, 웹서버 프로세스가 다음 번에 메모리대응한 파일내용을 읽을때 bus error가 발생할 수 있다.
위의 조건에 해당하면 전송하는 파일을 메모리대응하지 않도록 EnableMMAP off를 사용해야 한다.
EnableSendfile
아파치는 운영체제가 sendfile을 지원하면 커널 sendfile을 사용하여 정적 파일을 서비스하는 경우 전송할 파일을 직접 읽지않을 수 있다. sendfile을 사용하면 read와 send를 따로 할 필요가 없어서 매우 빨라진다.
그러나 sendfile을 사용하면 웹서버의 안정성을 해치게되는 경우가 있고, 커널은 자신의 캐쉬를 사용하여 NFS로 마운트한 파일을 안정적으로 서비스할 수 없는 경우가 있으므로
EnableSendfile off를 사용해서 파일을 sendfile 전송하지 않도록 할수 있다.
설정변경후 아파치 성능 테스트
이제까지 설명한 부분들을 자신의 환경에 맞게 각각 수정한 후 아파치 웹서버를 재시작하고 실제로 성능이 향상되었는지를 다시 테스트하기로 하자. 필자는 아래의 부분들을 수정해서 테스트했다.
변경이전 |
변경이후 |
Timeout 120 KeepAlive Off MaxKeepAliveRequests 100 KeepAliveTimeout 15 HostnameLookups On #EnableMMAP off #EnableSendfile off StartServers 8 MinSpareServers 5 MaxSpareServers 20 ServerLimit 256 MaxClients 256 |
Timeout 300 KeepAlive On MaxKeepAliveRequests 10000 KeepAliveTimeout 25 HostnameLookups Off EnableMMAP On EnableSendfile On StartServers 20 MinSpareServers 15 MaxSpareServers 45 ServerLimit 512 MaxClients 512 |
표 4. <httpd.conf 변경부분>
ab
[root@www ~]# ab -c 1000 -n 1000 -t 10 http://210.183.235.95/
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.141 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking 210.183.235.95 (be patient)
Completed 5000 requests
Completed 10000 requests
Finished 14033 requests
Server Software: Apache/2.0.52
Server Hostname: 210.183.235.95
Server Port: 80
Document Path: /
Document Length: 440 bytes
Concurrency Level: 1000
Time taken for tests: 10.61616 seconds
Complete requests: 14033
Failed requests: 0
Write errors: 0
Total transferred: 8608215 bytes
HTML transferred: 6219400 bytes
Requests per second: 1394.71 [#/sec] (mean)
Time per request: 716.997 [ms] (mean)
Time per request: 0.717 [ms] (mean, across all concurrent requests)
Transfer rate: 835.45 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 2 162 961.7 18 9049
Processing: 16 126 385.1 94 6459
Waiting: 13 114 383.5 81 6439
Total: 52 288 1147.4 118 9890
Percentage of the requests served within a certain time (ms)
50% 118
66% 123
75% 128
80% 132
90% 153
95% 175
98% 3139
99% 9188
100% 9890 (longest request)
httperf
[root@www ~]# httperf --server 210.183.235.95 --port 80 --rate 1000 --num-conns 20000 --hog
httperf --hog --client=0/1 --server=210.183.235.95 --port=80 --uri=/ --rate=1000 --send-buffer=4096 --recv-buffer=16384 --num-conns=20000 --num-calls=1
Maximum connect burst length: 14
Total: connections 20000 requests 20000 replies 20000 test-duration 19.999 s
Connection rate: 1000.0 conn/s (1.0 ms/conn, <=37 concurrent connections)
Connection time [ms]: min 0.5 avg 3.1 max 47.3 median 1.5 stddev 4.6
Connection time [ms]: connect 1.0
Connection length [replies/conn]: 1.000
Request rate: 1000.0 req/s (1.0 ms/req)
Request size [B]: 65.0
Reply rate [replies/s]: min 996.2 avg 1000.0 max 1004.0 stddev 3.4 (4 samples)
Reply time [ms]: response 2.1 transfer 0.0
Reply size [B]: header 150.0 content 440.0 footer 0.0 (total 590.0)
Reply status: 1xx=0 2xx=20000 3xx=0 4xx=0 5xx=0
CPU time [s]: user 2.95 system 10.76 (user 14.8% system 53.8% total 68.6%)
Net I/O: 639.7 KB/s (5.2*10^6 bps)
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
flood
[root@www ~]# flood floodconf.xml > result.out
[root@www ~]# ./analyze-relative result.out
Slowest pages on average (worst 5):
Average times (sec)
connect write read close hits URL
0.0019 0.0020 0.0045 0.0046 28999 http://210.183.235.95/
Requests: 28999 Time: 0.45 Req/Sec: 65931.82
최종 테스트 결과
벤치마크라는 것이 다양한 환경요인에 영향을 받으므로 항상 동일한 값을 기대하기는 어려운 관계로 3가지 벤치마크 프로그램들의 결과값이 모두 동일하게 나타나지는 않지만 설정을 변경하기 이전보다 전부 향상된 것을 확인할 수 있다.
|
ab |
httperf |
flood |
기본상태 |
Time per request: 745.829 [ms] |
Reply time [ms]: response 9.6 |
Time: 0.80 sec |
튜닝이후 |
Time per request: 716.997 [ms] |
Reply time [ms]: response 2.1 |
Time: 0.45 sec |
출처 : linux.co.kr