- 시스템이 어떻게 움직이고 있는가?
1. 시스템 모니터링 결과에 대해서 정확히 알고 있자
ㅇ 메모리가 왜 이리 모자라지? - free 에 대하여
밤에 잠을 자고 있는데 사무실에서 급하게 전화가 왔다. 웹서비스가 엄청 느려져서 도저히 웹사이트를 볼 수가 없다는 것이다. 잽싸게 일어나서 컴퓨터를 켰다. 원격으로 접속을 해서 서버를 관찰한다. 가장 먼저 무엇을 해야할까? 어디에서 시스템이 느려지고 있는지 찾아야한다. 그리고 평상시의 상태와 비교를 해야한다. 시스템 관리자라면 흔히 일어나는 경우이다. 시스템 관리의 첫 출발은 평상시에 계속 시스템의 상태를 파악하고 모니터링 결과를 비교하는 작업이다. 또한 나온 결과를 제대로 파악하고 있어야하는데 주기적으로 시스템을 모니터링해놓고도 그 결과를 엉뚱하게 해석한다면 전혀 다른 결과를 초래할 수 있다.
예를 한번 들어보자. 리눅스에서 메모리를 점검하기 위해 흔히 free를 사용한다. 그런데 free의 결과를 잘못 이해하는 경우가 상당히 많고 필자도 마찬가지였다. 아래 결과를 보자. 512M의 메모리를 가진 시스템이다.
$ free
total used free shared buffers cached
Mem: 513368 503180 10188 0 3772 332740
-/+ buffers/cache: 166668 346700
Swap: 1028152 84908 943244
이상하게 쓰는 것도 없는데 513M에서 현재 사용하는 것이 503M이다. 아무래도 시스템에 문제가 생겼나해서 재부팅을 했는데 조금 지나자 또 대부분의 메모리를 used에서 잡아먹는다. 에라 모르겠다 메모리를 512M 더 추가시키자. 농담이 아니라 실제로 충분히 발생할 수 있는 상황이다.
디스크를 읽는 일은 메모리에 비해서 아주 느리다. 수많은 사람들이 접속해서 ls 명령어를 모두 디스크에 읽어서 실행을 한다면 그 시스템의 속도가 아주 느려질 것이다. 물론 여기서는 ls라는 간단한 명령을 말했지만 시스템의 자원을 엄청 잡아먹는 프로그램이라면 문제가 또 달라질 것이다. 이런 경우 디스크에서 한번 읽어들인 정보를 메모리에 일정기간 보관하고 있다면 처음 읽을때만 속도가 느리지 이후에는 전반적으로 빨라질 것이다. 이것을 가르켜 디스크 버퍼링이라고 하며 이런 목적으로 사용되는 메모리가 위에서 나오는 버퍼 캐쉬이다.**주1 (실제로 버퍼 캐쉬는 파일을 버퍼링하는 것은 아니고 디스크 입출력의 가장 작은 단위인 블록을 버퍼링한다. 블록 디바이스 드라이버가 사용하는 데이터 버퍼를 가지고 있는 것이다) 만일 캐쉬의 크기가 고정되어 있다면 그 크기가 너무 커도 메모리 부족현상이 생길 수 있을 것이고 지나친 스와핑을 발생하게 해서 시스템이 느려질 가능성이 크다. 리눅스에서는 자동적으로 모든 램의 빈 공간을 버퍼 캐쉬로 사용하여 메모리를 효율성을 높이고 있으며 프로그램에서 많은 메모리를 필요로 하는 경우에는 자동으로 캐쉬의 크기를 줄인다. 그렇다면 위에서 실제로 사용가능한 메모리는 free+buffers+cached 이다. -/+ buffers/cache: 이 줄이 이러한 내용을 반영하고 있다. 일반적인 리눅스 시스템관리와 관련된 서적에는 이 부분에 대하여 지적을 한 곳이 거의 없으며 맨페이지에도 이런 설명은 아직 찾지 못했다. 운영체제와 커널의 원리에 대해서 모른다면 같은 결과를 놓고도 정말 엉뚱한 분석을 할 수 있는 것이다. 위의 내용을 아는 분이라면 모르겠지만 이 글을 보는 사람들중에 위의 내용을 몰랐던 사람들은 정말 모르고 있었구나 하는 생각이 들지 않을까?
2. 현재 시스템의 문제를 찾자
시스템의 성능은 현재의 시스템 자원을 여러 가지 프로그램들의 요청에 대하여 얼마나 효율적으로 적용을 하는가에 달려있다. 요즘처럼 인터넷이 보편화된 상황에서 네트워크도 중요한 부분이기는 하지만 일반적으로 성능에서 가장 중요한 시스템 자원은 CPU, 메모리, 디스크 입출력이다. 그래서 위의 부분들을 중심으로 성능에 문제가 생기기 전에 미리 시스템을 분석하는 것이 중요하다. 시스템에 문제가 생긴다면 다음을 먼저 점검해보자
CPU 문제 점검 - top, ps, uptime, vmstat, pstree 등
메모리 문제 점검 - free, vmstat 등
메모리에 문제가 없다면 디스크 I/O 점검 - df, du, 쿼타 등
디스크와 메모리에 문제가 없는데도 시스템에 문제가 생기면 CPU의 오버헤드에 문제가 있을 가능성이 크다
ㅇ 네트웍 문제 점검 - netstat, ping, traceroute, tcpdump 등
3. 사전 점검 사항
시스템이 정상적으로 작동하고 있을 때 정기적으로 모니터링을 해 두어야 시스템에 문제가 생겼을 때 대처를 할 수 있다. 아래를 참고로 하여 주기적으로 시스템 모니터링 결과를 모아두자.
주요 사용자들한테 성능이 괜찮다는 동의를 먼저 얻어야한다. 그리고 시스템 성능을 계속 유지할 수 있도록 정기적으로 점검한다.
시스템 accounting 프로그램을 이용한다. 시스템에서 CPU, I/O, 메모리 집약적인 프로그램들을 알고 있어야한다. (**주2)
$ sa
75563 169479.02re 510.44cp 0avio 506k
14056 450.37re 448.85cp 0avio 497k webalizer
361 91931.12re 37.86cp 0avio 1355k httpd*
275 7.50re 5.38cp 0avio 402k gawk
14056 455.55re 4.95cp 0avio 438k weblog
14226 588.92re 2.57cp 0avio 437k sh
11 18.88re 2.45cp 0avio 332k slocate
162 670.85re 1.46cp 0avio 666k in.telnetd
2298 45.83re 1.09cp 0avio 2858k mysqld*
325 0.86re 0.76cp 0avio 642k ps
358 1185.61re 0.66cp 0avio 454k bash
1419 0.48re 0.47cp 0avio 283k rmmod
accounting 결과 예제
vmstat 등의 프로그램을 이용 I/O연산이 얼마나 분산되어있는지, CPU가 작동하지 않고 노는 시간(idle)은 얼마인지, 정상적인 부하가 걸릴 경우 메모리를 얼마나 사용하고 있는지 확인한다.
주기적으로 시스템 상황을 자동으로 모니터링하는 방법에 대해서는 세 번째 강좌에서 설명을 할 예정이다.
4. 문제가 발생했을 경우의 대처 방법
시스템이 정상적으로 작동하고 있을때 제대로 모니터링을 하고 분석을 해 두었다면, 사용자가 불평하거나 문제가 터지기 않더라도 언제 시스템의 성능이 나빠질지 알 수 있다. 그러면 시스템에 문제가 발생하였을 경우에는 어떻게 대처를 해야 할까?
어떤 프로그램을 실행하고 있으며 어떻게 사용하고 있는가? 현재 시스템에서 주요하게 제공하는 서비스는 어떤 것인가? 예를 들어 NFS를 통해 파일에 접근을 한다면 네트웍 성능이 떨어지는게 문제의 한 부분이라는 것을 알 수 있다. 웹서비스를 한다면 시스템 자체의 부하가 아니라 네트웍 회선의 문제로 속도가 느려질 가능성도 있다.
uptime을 이용하여 시스템의 부하를 확인한다. 시스템의 부하가 어떤 추세로 움직이고 있고 어느 정도 수치로 작동하는지 확인을 한다. 웹서비스의 경우 보통 낮시간대에 접속이 폭주하므로 S자 형태로 시스템 부하가 변화될 것이다. 그런데 최대 접속할 시간이 아닌데도 시스템의 부하가 높아진다면 불필요한 프로그램이 계속 돌면서 시스템의 자원을 소비할 가능성도 있고 DOS 공격 등을 받고 있을 가능성도 크다.
$ uptime
9:23pm up 61 days, 5:23, 1 user, load average: 0.02, 0.05, 0.00
ps와 top를 활용한다.
- 디스크 액세스나 페이징을 기다리고 이는 프로세스가 있는가? 그렇다면 I/O와 메모리를 점검하자. 리눅스에서 프로세스 대기 상태는 인터럽트 허용과 인터럽트 금지의 두가지 형태가 있다. 세마포어를 기다리거나 파일을 읽을 수 있게 되길 기다리는 것처럼 자원을 기다리는 일반적인 대기상태는 대개 인터럽트로 처리가 가능하다. (인터럽트가 허용되는 sleep 상태는 ps,top 등에서 S로 나타난다.) 그렇지만 인터럽트가 금지되는 대기상태는 스왑파일에서 메모리로 페이지를 읽어들이는 것과 같이 임계지역에서 일이 끝마치기를 기다리고 있는 상태이다. 프로세스 상태에서 D 는 uninterruptible sleep로서 page fault 등을 의미하며 page fault 등을 통해 I/O중인 상태를 나타낸다. W는 has no resident pages를 의미하며 프로세스가 스왑아웃된 상태를 나타낸다. (W는 커널 프로세스에 대해서는 정확히 동작을 하지않는다.
- CPU와 메모리를 가장 많이 사용하는 프로세스를 찾으면 부하를 분산시키는데 도움이 될 것이다.
$ ps auxw
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 1120 68 ? S Jun17 0:06 init [3]
root 2 0.0 0.0 0 0 ? SW Jun17 0:00 [keventd]
root 3 0.0 0.0 0 0 ? SW Jun17 0:00 [kswapd]
root 4 0.0 0.0 0 0 ? SW Jun17 0:00 [kreclaimd]
root 5 0.0 0.0 0 0 ? SW Jun17 0:32 [bdflush]
root 6 0.0 0.0 0 0 ? SW Jun17 0:02 [kupdated]
root 351 0.0 0.0 1164 284 ? S Jun17 0:01 syslogd -m 0
root 360 0.0 0.0 1728 356 ? S Jun17 0:00 klogd
root 388 0.0 0.0 1156 220 ? S Jun17 0:00 inetd
root 402 0.0 0.2 3824 1452 ? S Jun17 3:09 /usr/sbin/snmpd
named 416 0.0 0.3 3376 1904 ? S Jun17 0:27 named -u named
$ top
7:34pm up 14:19, 3 users, load average: 1.20, 0.54, 0.20
57 processes: 53 sleeping, 4 running, 0 zombie, 0 stopped
CPU states: 94.6% user, 5.3% system, 0.0% nice, 0.0% idle
Mem: 513368K av, 321260K used, 192108K free, 0K shrd, 9208K buff
Swap: 1028152K av, 115000K used, 913152K free 270924K cached
PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND
12436 root 20 0 6428 6428 1564 R 0 13.1 1.2 0:00 cc1
3570 nobody 12 0 11148 6140 5016 R 0 2.5 1.1 0:09 httpd
12435 root 8 0 1528 1528 388 S 0 1.3 0.2 0:00 cpp
4185 root 9 0 512 328 312 S 0 0.3 0.0 0:01 sshd2
11364 taejun 10 0 876 876 680 R 0 0.3 0.1 0:00 top
1 root 8 0 120 68 68 S 0 0.0 0.0 0:04 init
2 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 keventd
3 root 9 0 0 0 0 SW 0 0.0 0.0 0:03 kswapd
4 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 kreclaimd
5 root 9 0 0 0 0 SW 0 0.0 0.0 0:01 bdflush
6 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 kupdated
348 root 9 0 208 156 156 S 0 0.0 0.0 0:00 syslogd
357 root 9 0 608 4 4 S 0 0.0 0.0 0:00 klogd
371 root 8 0 180 124 120 S 0 0.0 0.0 0:00 crond
vmstat를 이용한다. (vmstat 5 5)
$ vmstat 5 5
procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
3 0 0 115000 189428 9220 272608 1 28 10 36 108 25 2 0 98
1 0 0 115000 189972 9220 272680 0 0 0 205 196 416 95 5 0
1 0 0 115000 187060 9220 272740 0 0 0 157 156 229 95 5 0
2 0 0 115000 194852 9220 272856 0 0 0 149 142 229 96 4 0
- vmstat에서 첫 번째 줄은 부팅 이후의 각 통계치에 대한 평균치를 보여주는데 이것은 무시해야 한다. 두 번째 줄부터 보면 된다.
- cpu에서 시스템에서 사용하는 cpu시간이 지나치게 높다면(50% 이상) 디스크 I/O에서 문제가 있을 가능성이 크다. 해당 프로그램의 소스코드를 구할 수 있다면 프로그램에서 얼마나 효율적으로 I/O를 사용하는지 확인해 보아야 한다. vmstat에서 sy 항목은 system time을 의미하며 커널모드로 넘어간 상태이다.
- 시스템 전체의 부하가 높은데도 cpu에서 휴지시간(idle time, id 항목)이 일반적으로 10%를 넘는다면 I/O나 메모리에 문제가 있을 가능성이 크다.
- 휴지시간이 항상 0이라면 CPU를 완전하게 100% 사용하고 있는 상태이다. CPU의 기능을 최대한 활용하는 것은 좋은 현상이다. 그런데 항상 100% 로 바쁜 상태라면 어떤 작업이 계속 축적되고 있다는 것이며 CPU의 과부하를 의미한다. CPU를 계속 사용하고 있는 프로세스를 찾아야한다.
- 디스크의 활동이 분산되지 않았다면, I/O 작업을 효율적으로 분산시켜야한다. 그런데 현재 리눅스용 vmstat에서는 이에 대한 정보는 나오지 않는다. 다른 유닉스의 경우에는 iostat나 sar을 이용하는데 인터넷에서 패키지를 받아서 설치할 수 있다. 이러한 프로그램이 sysstat 로 리눅스용 sar, iostat 패키지이다. 사이트 주소는 다음과 같다. (최근 레드햇 배포판 등에는 들어가고 있다)
http://perso.wanadoo.fr/sebastien.godard/
아래에서는 현재 두 개의 HDD가 장착되어 있는 시스템의 상태를 보여준다.
$ iostat
Linux 2.4.4 (tunelinux.pe.kr) 07/08/01
avg-cpu: %user %nice %sys %idle
5.55 0.00 1.20 93.26
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
dev8-0 6.06 9.49 102.23 50185324 540747898
dev8-1 1.99 1.51 25.05 7964700 132509976
위 사항에서 해당하는 것이 없고 메모리와 I/O 관련 튜닝을 할 필요가 없다고 분석이 되면 CPU쪽에서 과부하가 걸린 상태이다. CPU 과부하의 경우 대처할 수 있는 몇가지 방법은 있지만 CPU의 과부하는 메모리와 I/O 문제로 나누어지기 때문에 찾아내기 힘든 부분이다.
CPU의 과부하를 줄일 방법에 대해서 설명한다.
- 필요없는 데몬과 서비스를 줄인다. rwhod와 routed는 시스템의 성능을 저해하는 프로그램으로 이를 없애는 것만으로 많은 도움이 될 것이다. kudzu, portmap, nfslock, apmd, random, netfs, identd, atd, pcmcia, lpd, sendmail, gpm, xfs, linuxconf 등이 불필요하다면 사용하지 않아도 될 서비스들이다. cpu의 부하를 줄일 뿐만 아니라 보안 관점에서도 필요없으면 내리는 것이 낫다. 여기서 잘못 이해하기 쉬운 것이 sendmail 부분이다. pine등을 이용하여 메일을 발송할 때에는 센드메일 데몬을 이용하지 않는다. 센드메일을 백그라운드 작업으로 계속 작동시키는 목적은 외부로부터 메일을 받는데 있다. 그러므로 일반적인 메일서버의 기능을 하지 않고 단지 메일을 보내는 것이 목적이라면 sendmail을 가동시킬 필요가 없다. (**주3)
- at이나 cron 등을 이용 작업을 밤이나 시스템의 부하가 적을 때 실행하는 것도 좋은 방법이다. 보통 로그 로테이션, 백업, 로그분석 등은 새벽 시간을 이용하여 처리하는게 바람직하며 기본설정되어 있는 cron 작업은 대부분 새벽 4시에 가동이 된다.
- CPU 집약적인 작업은 nice를 이용 실행우선순위를 낮추면 편집작업과 갈은 상호대화적인 작업의 성능이 향상될 것이다.
- cpu 집약적인 작업의 실행우선순위를 높이면 작업 자체는 빨라지겠지만 상호대화적인 작업의 성능은 떨어질 것이다. 그런데 보통 일반적인 인터넷 서버로 운영을 한다면 CPU 집약적인 작업은 그렇게 많은 편은 아니며 꼭 서버에서 실행시켜도 되지 않는 작업이라면 다른 시스템을 이용하는 것이 좋다. 웹로그 분석도 이러한 경우에 속한다.
- nice를 이용하는것은 임시방편일 뿐이다. 부하가 계속 증가한다면 nice를 이용하는 것에도 한계가 있다. 시스템을 업그레이드하거나 부하를 분산할 시스템을 구입해야한다.
- 커널이나 프로그램의 컴파일을 하는 경우에도 nice를 이용하면 조금이나마 속도의 향상이 있다. 그렇지만 때로 nice를 잘못 사용하면 문제가 생길 수가 있으니 조심해야 한다. 예를 들어 오라클에서는 오라클 사용자 프로세스와 백그라운드 프로세스들을 같은 우선순위에 유지해야 한다. 설계가 그렇게 되어 있기 때문이다. 우선 순위를 변경할 경우 내용과 반응시간에 원치 않는 효과를 초래할 수도 있다. 예를 들어 log write process(LGWR)에 낮은 우선 순위를 부여할 경우, 이 프로세스는 충분한 횟수만큼 작동하지 못하고 LGWR은 병목현상을 일으키게 된다. 다른 한편, 만약 LGWR이 높은 우선 순위를 부여받게 되면, 사용자 프로세스는 느린 반응시간에 시달리게 될 것이다. 무엇이든 그냥 적용하는게 아니라 그 원리를 이해하고 조심스럽게 해야 한다. (**주4)
5. 메모리 문제 파악하기
시스템에 과부하가 걸려있는데도 휴지기간(idle time)이 많거나 ps에서 많은 양의 메모리를 필요로 하는 프로그램이 실행되고 있다면 메모리 문제를 생각해 볼 수 있다.
vmstat 5 를 실행해보자.
- swap-out이 지속적으로 항상 발생한다면 메모리가 부족한 것이다. 주기적으로 swap-outs이 발생하는건 정상적인 것이다. BSD 시스템에서는 비상호대화적인 작업을 스왑아웃한다. 현재 실행하고 있는 프로그램에서 스왑아웃이 계속 발생한다면 프로그램이 죽을 수도 있으며심각하게 메모리가 부족하다는것을 가리킨다. 스왑아웃필드(so)가 항상 0에 가까워야한다. 그렇지 않다면 프로세스들간에 가상 메모리에 대하여 경쟁하고 있으며 시스템은 페이징 상태에 있다. 페이징 활동은 또한 심각한 가용 메모리(free)의 부족과 직접적인 관련을 가지고 있으며 간접적으로는 시스템의 높은 CPU 사용시간 비율(sy)과 관련이 있다. 프로세스가 시작을 할 때 항상 이미지(text)와 데이터를 page-in 해야 하므로 page-in 열에서 높은 숫자가 항상 심각한 것은 아니라는 사실은 기억하고 있어야 한다.
- ps나 accounting 시스템에서 메모리 집약적인 작업이 있는지 확인을 한다. RSS필드나 storage integral이 큰 프로그램을 찾아보자. ps나 top에서 RSS는 프로세스가 사용중인 물리적 메모리 크기로 kbytes 단위로 보여준다. ELF 프로세스에서 사용된 라이브러리 페이지도 여기에 같이 계산이 된다. storage integral은 accounting 패키지에 들어있는 sa -K 옵션을 이용해 볼수있다.
메모리 문제를 해결할 몇가지 방법을 찾아보자.
- 시스템에서 버퍼 캐쉬가 있다면 크기를 줄인다. 대신 디스크 I/O성능에 영향을 줄 수있다. 리눅스는 /proc를 이용 전체 메모리에서 버퍼 캐쉬의 사용량을 조절할 수 있다. 이에 대해서는 마지막 장 에서 다루겠다.
- 네트워크 버퍼를 줄인다. 웹서버의 응답은 클라이언트에 직접 전달되는 것이 아니라 소켓 버퍼라는 네트워크 버퍼에 저장을 한다. OS에서는 적절한 수와 크기의 네트워크 버퍼를 가지고 있어야 메모리를 낭비하지도 않고 서버에서 필요한 버퍼를 기다리는 동안 서버의 작업이 중단되지도 않는 상태로 클라이언트의 접속을 처리할 수 있다. 갑작스럽게 접속이 중단되는 클라이언트에서 차지하고 있던 네트워크 버퍼는 웹 서버에서 메모리가 낭비되는 주요한 원인중의 하나이다. 아파치에는 SendBufferSize 지시자가 있어서 운영체제에서 지정되어 있는 TCP의 전송 버퍼를 늘릴 수 있다. 그런데 아직까지 필자도 리눅스쪽에서는 이 부분에 대하여 자세히 소개된 자료를 찾지 못했다. 아직 정확히 이해하지 못하고 있는 부분이지만 도움이 될까하여 고민 끝에 관련 내용을 포함한다. (**주5)
- 커널 테이블의 크기를 줄인다. 이를 통해 시스템의 자원을 제약할 수 있다. 예를 들어 파일 개수, 프로세스 개수등이 해당한다. 운영체제에서 이와 관련된 설정을 높이면 그만큼 커널 테이블의 크기가 늘어나 메모리도 그만큼 더 사용하게 된다.
- 많은 메모리를 필요로 하는 프로그램은 밤에 돌리자.
- 많은 메모리를 필요로 하는 프로그램은 배치 큐를 이용해 작업하자. at, cron등 활용
- 자기만 사용하는 프로그램이라면 프로그램에서 메모리를 효율적으로 사용하는지 점검하자.
- 메모리 요구량을 줄이기 위해 공유 메모리를 사용하자. 공유 메모리는 다수의 프로세스 간에 데이터를 공유하고 전달하는 효과적인 방법을 제공한다. 또한 어떤 특정한 명령을 여러명이 사용하는 경우 가상 주소공간에 해당 프로그램의 여러 복사본을 갖는게 아니라 물리적 공간에 하나의 복사본을 만들고 모든 프로세스가 그것을 공유할 수 있다. 동적 라이브러리는 여러 프로세스가 실행 코드를 공유하는 대표적인 예이다. 그런데 공유 라이브러리를 사용하는 경우 메모리는 절약할 수 있겠지만 프로그램의 성능은 정적으로 컴파일하는 것이 더 빠르다. 예를 들어 Mysql의 경우는 -static을 사용하지 않고 동적으로 링크하면 대략 13%정도 속도가 느려진다고 한다. (**주6)
- sendmail은 메모리를 많이 사용하는 프로그램으로 sendmail을 실행하는데 사용되는 시간에 제한을 두자. 아니면 네트웍을 재구성해서 메일서버를 다른 시스템으로 옮길 수 있다. 위에서 설명을 했던대로 메일을 받는 경우에만 sendmail을 사용하면 된다.
- 이막스(Emacs)는 메모리를 많이 사용하는 프로그램으로 vi 등 다른 에디터를 사용하자.
- 이 모든게 안되면 메모리를 구입하자. 하드웨어의 가격이 예전에 비해 많이 저렴해졌으며 이제 1G 메모리도 그렇게 특별한 시스템은 아닌 상황이다. 대신 프로그램에서 요구하는 기본 메모리양도 커졌다.
6. 디스크 I/O 문제 파악하기
시스템에 과부하가 걸려있는데도 휴지기간(idle time)이 많다면 디스크 I/O 문제를 생각해 볼 수 있다. 보통 메모리 문제와 I/O문제는 서로 관련이 되어있다.
vmstat 5 를 실행한다. 그리고 이것을 정상적인 시스템 상황과 비교해본다. 정상적인 경우보다 디스크 연산이 더 높은가?
디스크 활동이 시스템 디스크에 골고루 분산되어있는가? iostat 등을 이용하여 모니터링하면 될 것이다.
그렇지 않다면 가장 활동적인 디스크가 가장 빠른 디스크인가?
디스크 활동이 디스크의 특정 영역에 집중되어있는가? 디스크에 적당히 분포되어있는가? 아니면 서로 다른 반대방향의 지점에 있는가?
NFS를 사용하고 있는가? 사용자들이 자신의 지역파일에 접근하는데 속도가 느리다고 보고를 하는가? 원격 파일시스템을 사용하는가? 만약 원격 파일시스템을 사용하면 네트웍 상황에 대해서 살펴보자. 이경우에는 지역 디스크 I/O문제는 아니다.
vmstat를 이용 메모리 상황을 살펴보자. 시스템에서 페이징이나 스와핑이 계속 일어나고 있다면, 메모리에 문제가 있으며 이경우 디스크 I/O에 심각한 문제를 초래할 수 있다. 먼저 메모리 문제를 살펴보아야한다.
이에 대한 해결책을 찾아보자.
파일시스템을 재구성하고 가능한한 I/O작업을 분산시킨다.
루트 파일시스템에 가장 빠른 디스크 드라이브와 컨트롤러를 사용한다. 루트 파일 시스템이 대부분 가장 많은 I/O작업을 한다. 특정한 파일의 성능이 중요하다면 성능이 중요한 파일을 하나의 파일시스템에 넣고 이 파일시스템에 가장 빠른 드라이브를 사용한다.
퍼포먼스가 중요한 파일을 블락 크기가 큰 파일시스템에 넣는다. 리눅스에서 블락 크기는 블락당 1024, 2048, 4096이다. 파일시스템을 생성할 때 지정을 해야 한다. 블락 크기를 높이면 성능이 향상될 수는 있어도 불필요하게 낭비되는 하드디스크 공간이 늘어난다.
버퍼 캐쉬의 크기를 늘린다. 그러면 대신 메모리에 문제가 생길 수 있다.
단편화를 제거하기 위해 주기적으로 파일시스템을 재구성한다.
자주 사용하는 파일을 파일시스템의 시작부분에 집중시키는 프로그램을 사용할수 있다.
운영체제 차원의 튜닝에서 가장 많은 성능향상을 얻을 수 있는 분야가 I/O 부분이다. I/O성능은 하드디스크의 속도뿐만 아니라 시스템 버스에 물려있는 여러 구성 요소와 함께 좌우가 된다. 그런데 리눅스를 주로 사용하는 인텔x86 계열의 하드웨어는 타상용 유닉스 시스템에 비하면 I/O와 관련되어 성능이 미약한 편이다. 또 비디오 카드등은 64비트를 넘어 128비트 체계로 간지 오래되었지만 마더보드의 PCI 슬롯은 32비트 체계를 가지고 있다. PC레벨에서는 32비트 CPU가 사요되고 있고 메모리를 부분만 64비트로 동작하고 있을 뿐이다. (**주 7) 그렇지만 PC서버가 일반화되면서 예전 상용 유닉스 장비에만 있었던 여러 가지 기능들이 속속 도입되고 있으며 앞으로도 발전이 기대된다. 여기에 몇가지 이야기를 덧붙이자면 디스크 I/O의 속도향상을 위해 RAID등을 사용할 수도 있고 소프트웨어 차원에서의 소프트웨어 레이드도 현재 리눅스에서 지원이 되고 있다. 저널링 파일 시스템이 최근부터 본격적으로 지원되기 시작하여 파일시스템의 안정성과 무결성을 높임과 더불어 속도도 꾸준한 향상이 되고 있다. 현재 리눅스에서 지원하는 저널링 파일 시스템으로는 reiserfs, SGI의 XFS 등이 있다. (**주8)
디스크 용량에 문제가 생길 수도 있다. 파일시스템에 여유공간이 부족한가? 그렇다면 몇가지 방법을 생각해보자.
ㅇ 필요없는 파일을 cron 등을 이용 정기적으로 삭제하자. 오래된 코어 덤프 파일, 에디터 백업파일, auto-save 파일 등등.
디스크 쿼터를 이용해 사용자의 디스크 용량 사용을 제한할 수 있다.
매우 작은 파일이 모여있는 파일시스템에는 작은 블럭 사이즈를 사용한다. (소스 코드, 작은 데이타 파일 등등)
ㅇ /tmp, /var/tmp 등에는 계속 임시파일이 생성되고 man 페이지를 위한 임시파일도 계속 생성이 된다. 이에 대한 처리는 레드햇 리눅스 계열에서/etc/cron.daily/tmpwatch를 이용하여 처리한다. 3장에서 다시 소개할 것이다.
7. 네트웍 문제 점검
네트웍 문제 점검
rlogin이나 NFS를 이용하여 파일에 접근하는 사용자가 성능이 느리다고 생각이 든다면 이는 네트웍 용량이나 데이터 정합성에 문제가 있을 수 있다.
netstat -i 를 실행하자. 충돌(collison)이 크면 네트웍에 오버헤드가 걸렸다고 생각할 수 있다. 충돌률은 ifconfig -a 등을 이용해서 나온 결과중 (collisons/TX packets) X 100을 하면 나온다. input이나 output 에러가 많다면 하드웨어 문제일 수 있다. 입력에러가 많다면 네트웍의 특정한 곳에 문제가 있을 가능성이 크며 출력에러가 많다면 시스템과 네트웍 인터페이스에 문제가 있을 가능성이 크다.
충돌이나 네트웍 하드웨어의 문제가 아니라면, 어떤 시스템이 가장 느린지를 찾아야한다. dropped 패킷이 크다면, 원격 시스템은 아마도 들어오는 자료에 대해 충분히 빠르게 대응하지 못할 것이다. 원격 시스템에 cpu, 메모리, 디스크 I/O문제가 있는지 확인하자. 그게 아니라면 그 시스템은 네트웍의 과부하에 견디지 못할 것이다. 네트웍을 다시 재구성하고 느린 시스템을 파일 서버로 사용하지 말자.
ㅇ 기본적인 연결 테스트에는 ping 명령을 사용하며 네트워크 접속에 대한 점검을 한다면 ifconfig, arp, netsta 등을 이용하고 네트워크 하드웨어 문제를 점검해 보아야 한다.
# ifconfig -i
eth0 Link encap:Ethernet HWaddr 00:01:02:26:BD:CE
inet addr:211.111.111.111 Bcast:211.50.6.255 Mask:255.255.255.192
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:346297 errors:0 dropped:0 overruns:0 frame:0
TX packets:346683 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:10 Base address:0xd000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:7745 errors:0 dropped:0 overruns:0 frame:0
TX packets:7745 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
# netstat -i
Kernel Interface table
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 349675 0 0 0 350447 0 0 0 BRU
lo 16436 0 7825 0 0 0 7825 0 0 0 LRU
네트웍 부하 줄이는 방법 (**주9)
사용자가 네트웍을 통해 I/O집약적인 프로그램을 실행하지 않도록 막자. grep 프로그램이 I/O 집약적인 프로그램중의 대표적인 예이다. 대신 네트웍을 통해 로그인해서 작업하자.
네트웍에 연결된 컴퓨터와 디스크를 재구성해서 가능한 많은 사용자가 지역 지역 시스템에서 작업을 하도론 만든다.
디스크없는 워크스테이션의 숫자를 줄인다. 가능하다면 이런 워크스테이션은 제거한다.
뛰어난 네트웍 성능을 가진 시스템을 파일서버로 사용한다.
ㅇ 충돌률을 줄이기 위해서는 네트워크 세그먼트 상의 트래픽양을 줄여야 하며 이 경우 이더넷을 분리할 수 있다.
데이터 정합성에 문제가 있다면 유일한 해결책은 문제가 있는 하드웨어를 찾아서 바꾸는 것이다. 네트웍 분석툴이 이러한 작업을 하는데 반드시 필요할 것이다.
8. 마치며
이번 강의에서는 시스템 최적화를 위한 준비 단계로 프로세스, 메모리, I/O 부분을 중심으로 어떻게 현재 시스템 상태를 모니터링하고 문제를 발견하여 해결을 할 수 있는지에 대하여 설명을 하였다. 중요한 것은 시스템을 모니터링하는 것과 더불어 나온 결과에 대하여 정확하게 이해를 해야 한다는 것이다. 이에 대해서는 free를 예로 들어 설명을 하였다. 가장 먼저 주기적으로 시스템을 모니터링하여 문제를 파악하고 있어야 하고 문제가 발생했을 경우 여러 가지 상황에 따라 CPU, 메모리, I/O부분을 점검해야 한다.
1. 시스템 모니터링 결과에 대해서 정확히 알고 있자
ㅇ 메모리가 왜 이리 모자라지? - free 에 대하여
밤에 잠을 자고 있는데 사무실에서 급하게 전화가 왔다. 웹서비스가 엄청 느려져서 도저히 웹사이트를 볼 수가 없다는 것이다. 잽싸게 일어나서 컴퓨터를 켰다. 원격으로 접속을 해서 서버를 관찰한다. 가장 먼저 무엇을 해야할까? 어디에서 시스템이 느려지고 있는지 찾아야한다. 그리고 평상시의 상태와 비교를 해야한다. 시스템 관리자라면 흔히 일어나는 경우이다. 시스템 관리의 첫 출발은 평상시에 계속 시스템의 상태를 파악하고 모니터링 결과를 비교하는 작업이다. 또한 나온 결과를 제대로 파악하고 있어야하는데 주기적으로 시스템을 모니터링해놓고도 그 결과를 엉뚱하게 해석한다면 전혀 다른 결과를 초래할 수 있다.
예를 한번 들어보자. 리눅스에서 메모리를 점검하기 위해 흔히 free를 사용한다. 그런데 free의 결과를 잘못 이해하는 경우가 상당히 많고 필자도 마찬가지였다. 아래 결과를 보자. 512M의 메모리를 가진 시스템이다.
$ free
total used free shared buffers cached
Mem: 513368 503180 10188 0 3772 332740
-/+ buffers/cache: 166668 346700
Swap: 1028152 84908 943244
이상하게 쓰는 것도 없는데 513M에서 현재 사용하는 것이 503M이다. 아무래도 시스템에 문제가 생겼나해서 재부팅을 했는데 조금 지나자 또 대부분의 메모리를 used에서 잡아먹는다. 에라 모르겠다 메모리를 512M 더 추가시키자. 농담이 아니라 실제로 충분히 발생할 수 있는 상황이다.
디스크를 읽는 일은 메모리에 비해서 아주 느리다. 수많은 사람들이 접속해서 ls 명령어를 모두 디스크에 읽어서 실행을 한다면 그 시스템의 속도가 아주 느려질 것이다. 물론 여기서는 ls라는 간단한 명령을 말했지만 시스템의 자원을 엄청 잡아먹는 프로그램이라면 문제가 또 달라질 것이다. 이런 경우 디스크에서 한번 읽어들인 정보를 메모리에 일정기간 보관하고 있다면 처음 읽을때만 속도가 느리지 이후에는 전반적으로 빨라질 것이다. 이것을 가르켜 디스크 버퍼링이라고 하며 이런 목적으로 사용되는 메모리가 위에서 나오는 버퍼 캐쉬이다.**주1 (실제로 버퍼 캐쉬는 파일을 버퍼링하는 것은 아니고 디스크 입출력의 가장 작은 단위인 블록을 버퍼링한다. 블록 디바이스 드라이버가 사용하는 데이터 버퍼를 가지고 있는 것이다) 만일 캐쉬의 크기가 고정되어 있다면 그 크기가 너무 커도 메모리 부족현상이 생길 수 있을 것이고 지나친 스와핑을 발생하게 해서 시스템이 느려질 가능성이 크다. 리눅스에서는 자동적으로 모든 램의 빈 공간을 버퍼 캐쉬로 사용하여 메모리를 효율성을 높이고 있으며 프로그램에서 많은 메모리를 필요로 하는 경우에는 자동으로 캐쉬의 크기를 줄인다. 그렇다면 위에서 실제로 사용가능한 메모리는 free+buffers+cached 이다. -/+ buffers/cache: 이 줄이 이러한 내용을 반영하고 있다. 일반적인 리눅스 시스템관리와 관련된 서적에는 이 부분에 대하여 지적을 한 곳이 거의 없으며 맨페이지에도 이런 설명은 아직 찾지 못했다. 운영체제와 커널의 원리에 대해서 모른다면 같은 결과를 놓고도 정말 엉뚱한 분석을 할 수 있는 것이다. 위의 내용을 아는 분이라면 모르겠지만 이 글을 보는 사람들중에 위의 내용을 몰랐던 사람들은 정말 모르고 있었구나 하는 생각이 들지 않을까?
2. 현재 시스템의 문제를 찾자
시스템의 성능은 현재의 시스템 자원을 여러 가지 프로그램들의 요청에 대하여 얼마나 효율적으로 적용을 하는가에 달려있다. 요즘처럼 인터넷이 보편화된 상황에서 네트워크도 중요한 부분이기는 하지만 일반적으로 성능에서 가장 중요한 시스템 자원은 CPU, 메모리, 디스크 입출력이다. 그래서 위의 부분들을 중심으로 성능에 문제가 생기기 전에 미리 시스템을 분석하는 것이 중요하다. 시스템에 문제가 생긴다면 다음을 먼저 점검해보자
CPU 문제 점검 - top, ps, uptime, vmstat, pstree 등
메모리 문제 점검 - free, vmstat 등
메모리에 문제가 없다면 디스크 I/O 점검 - df, du, 쿼타 등
디스크와 메모리에 문제가 없는데도 시스템에 문제가 생기면 CPU의 오버헤드에 문제가 있을 가능성이 크다
ㅇ 네트웍 문제 점검 - netstat, ping, traceroute, tcpdump 등
3. 사전 점검 사항
시스템이 정상적으로 작동하고 있을 때 정기적으로 모니터링을 해 두어야 시스템에 문제가 생겼을 때 대처를 할 수 있다. 아래를 참고로 하여 주기적으로 시스템 모니터링 결과를 모아두자.
주요 사용자들한테 성능이 괜찮다는 동의를 먼저 얻어야한다. 그리고 시스템 성능을 계속 유지할 수 있도록 정기적으로 점검한다.
시스템 accounting 프로그램을 이용한다. 시스템에서 CPU, I/O, 메모리 집약적인 프로그램들을 알고 있어야한다. (**주2)
$ sa
75563 169479.02re 510.44cp 0avio 506k
14056 450.37re 448.85cp 0avio 497k webalizer
361 91931.12re 37.86cp 0avio 1355k httpd*
275 7.50re 5.38cp 0avio 402k gawk
14056 455.55re 4.95cp 0avio 438k weblog
14226 588.92re 2.57cp 0avio 437k sh
11 18.88re 2.45cp 0avio 332k slocate
162 670.85re 1.46cp 0avio 666k in.telnetd
2298 45.83re 1.09cp 0avio 2858k mysqld*
325 0.86re 0.76cp 0avio 642k ps
358 1185.61re 0.66cp 0avio 454k bash
1419 0.48re 0.47cp 0avio 283k rmmod
accounting 결과 예제
vmstat 등의 프로그램을 이용 I/O연산이 얼마나 분산되어있는지, CPU가 작동하지 않고 노는 시간(idle)은 얼마인지, 정상적인 부하가 걸릴 경우 메모리를 얼마나 사용하고 있는지 확인한다.
주기적으로 시스템 상황을 자동으로 모니터링하는 방법에 대해서는 세 번째 강좌에서 설명을 할 예정이다.
4. 문제가 발생했을 경우의 대처 방법
시스템이 정상적으로 작동하고 있을때 제대로 모니터링을 하고 분석을 해 두었다면, 사용자가 불평하거나 문제가 터지기 않더라도 언제 시스템의 성능이 나빠질지 알 수 있다. 그러면 시스템에 문제가 발생하였을 경우에는 어떻게 대처를 해야 할까?
어떤 프로그램을 실행하고 있으며 어떻게 사용하고 있는가? 현재 시스템에서 주요하게 제공하는 서비스는 어떤 것인가? 예를 들어 NFS를 통해 파일에 접근을 한다면 네트웍 성능이 떨어지는게 문제의 한 부분이라는 것을 알 수 있다. 웹서비스를 한다면 시스템 자체의 부하가 아니라 네트웍 회선의 문제로 속도가 느려질 가능성도 있다.
uptime을 이용하여 시스템의 부하를 확인한다. 시스템의 부하가 어떤 추세로 움직이고 있고 어느 정도 수치로 작동하는지 확인을 한다. 웹서비스의 경우 보통 낮시간대에 접속이 폭주하므로 S자 형태로 시스템 부하가 변화될 것이다. 그런데 최대 접속할 시간이 아닌데도 시스템의 부하가 높아진다면 불필요한 프로그램이 계속 돌면서 시스템의 자원을 소비할 가능성도 있고 DOS 공격 등을 받고 있을 가능성도 크다.
$ uptime
9:23pm up 61 days, 5:23, 1 user, load average: 0.02, 0.05, 0.00
ps와 top를 활용한다.
- 디스크 액세스나 페이징을 기다리고 이는 프로세스가 있는가? 그렇다면 I/O와 메모리를 점검하자. 리눅스에서 프로세스 대기 상태는 인터럽트 허용과 인터럽트 금지의 두가지 형태가 있다. 세마포어를 기다리거나 파일을 읽을 수 있게 되길 기다리는 것처럼 자원을 기다리는 일반적인 대기상태는 대개 인터럽트로 처리가 가능하다. (인터럽트가 허용되는 sleep 상태는 ps,top 등에서 S로 나타난다.) 그렇지만 인터럽트가 금지되는 대기상태는 스왑파일에서 메모리로 페이지를 읽어들이는 것과 같이 임계지역에서 일이 끝마치기를 기다리고 있는 상태이다. 프로세스 상태에서 D 는 uninterruptible sleep로서 page fault 등을 의미하며 page fault 등을 통해 I/O중인 상태를 나타낸다. W는 has no resident pages를 의미하며 프로세스가 스왑아웃된 상태를 나타낸다. (W는 커널 프로세스에 대해서는 정확히 동작을 하지않는다.
- CPU와 메모리를 가장 많이 사용하는 프로세스를 찾으면 부하를 분산시키는데 도움이 될 것이다.
$ ps auxw
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 1120 68 ? S Jun17 0:06 init [3]
root 2 0.0 0.0 0 0 ? SW Jun17 0:00 [keventd]
root 3 0.0 0.0 0 0 ? SW Jun17 0:00 [kswapd]
root 4 0.0 0.0 0 0 ? SW Jun17 0:00 [kreclaimd]
root 5 0.0 0.0 0 0 ? SW Jun17 0:32 [bdflush]
root 6 0.0 0.0 0 0 ? SW Jun17 0:02 [kupdated]
root 351 0.0 0.0 1164 284 ? S Jun17 0:01 syslogd -m 0
root 360 0.0 0.0 1728 356 ? S Jun17 0:00 klogd
root 388 0.0 0.0 1156 220 ? S Jun17 0:00 inetd
root 402 0.0 0.2 3824 1452 ? S Jun17 3:09 /usr/sbin/snmpd
named 416 0.0 0.3 3376 1904 ? S Jun17 0:27 named -u named
$ top
7:34pm up 14:19, 3 users, load average: 1.20, 0.54, 0.20
57 processes: 53 sleeping, 4 running, 0 zombie, 0 stopped
CPU states: 94.6% user, 5.3% system, 0.0% nice, 0.0% idle
Mem: 513368K av, 321260K used, 192108K free, 0K shrd, 9208K buff
Swap: 1028152K av, 115000K used, 913152K free 270924K cached
PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND
12436 root 20 0 6428 6428 1564 R 0 13.1 1.2 0:00 cc1
3570 nobody 12 0 11148 6140 5016 R 0 2.5 1.1 0:09 httpd
12435 root 8 0 1528 1528 388 S 0 1.3 0.2 0:00 cpp
4185 root 9 0 512 328 312 S 0 0.3 0.0 0:01 sshd2
11364 taejun 10 0 876 876 680 R 0 0.3 0.1 0:00 top
1 root 8 0 120 68 68 S 0 0.0 0.0 0:04 init
2 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 keventd
3 root 9 0 0 0 0 SW 0 0.0 0.0 0:03 kswapd
4 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 kreclaimd
5 root 9 0 0 0 0 SW 0 0.0 0.0 0:01 bdflush
6 root 9 0 0 0 0 SW 0 0.0 0.0 0:00 kupdated
348 root 9 0 208 156 156 S 0 0.0 0.0 0:00 syslogd
357 root 9 0 608 4 4 S 0 0.0 0.0 0:00 klogd
371 root 8 0 180 124 120 S 0 0.0 0.0 0:00 crond
vmstat를 이용한다. (vmstat 5 5)
$ vmstat 5 5
procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
3 0 0 115000 189428 9220 272608 1 28 10 36 108 25 2 0 98
1 0 0 115000 189972 9220 272680 0 0 0 205 196 416 95 5 0
1 0 0 115000 187060 9220 272740 0 0 0 157 156 229 95 5 0
2 0 0 115000 194852 9220 272856 0 0 0 149 142 229 96 4 0
- vmstat에서 첫 번째 줄은 부팅 이후의 각 통계치에 대한 평균치를 보여주는데 이것은 무시해야 한다. 두 번째 줄부터 보면 된다.
- cpu에서 시스템에서 사용하는 cpu시간이 지나치게 높다면(50% 이상) 디스크 I/O에서 문제가 있을 가능성이 크다. 해당 프로그램의 소스코드를 구할 수 있다면 프로그램에서 얼마나 효율적으로 I/O를 사용하는지 확인해 보아야 한다. vmstat에서 sy 항목은 system time을 의미하며 커널모드로 넘어간 상태이다.
- 시스템 전체의 부하가 높은데도 cpu에서 휴지시간(idle time, id 항목)이 일반적으로 10%를 넘는다면 I/O나 메모리에 문제가 있을 가능성이 크다.
- 휴지시간이 항상 0이라면 CPU를 완전하게 100% 사용하고 있는 상태이다. CPU의 기능을 최대한 활용하는 것은 좋은 현상이다. 그런데 항상 100% 로 바쁜 상태라면 어떤 작업이 계속 축적되고 있다는 것이며 CPU의 과부하를 의미한다. CPU를 계속 사용하고 있는 프로세스를 찾아야한다.
- 디스크의 활동이 분산되지 않았다면, I/O 작업을 효율적으로 분산시켜야한다. 그런데 현재 리눅스용 vmstat에서는 이에 대한 정보는 나오지 않는다. 다른 유닉스의 경우에는 iostat나 sar을 이용하는데 인터넷에서 패키지를 받아서 설치할 수 있다. 이러한 프로그램이 sysstat 로 리눅스용 sar, iostat 패키지이다. 사이트 주소는 다음과 같다. (최근 레드햇 배포판 등에는 들어가고 있다)
http://perso.wanadoo.fr/sebastien.godard/
아래에서는 현재 두 개의 HDD가 장착되어 있는 시스템의 상태를 보여준다.
$ iostat
Linux 2.4.4 (tunelinux.pe.kr) 07/08/01
avg-cpu: %user %nice %sys %idle
5.55 0.00 1.20 93.26
Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn
dev8-0 6.06 9.49 102.23 50185324 540747898
dev8-1 1.99 1.51 25.05 7964700 132509976
위 사항에서 해당하는 것이 없고 메모리와 I/O 관련 튜닝을 할 필요가 없다고 분석이 되면 CPU쪽에서 과부하가 걸린 상태이다. CPU 과부하의 경우 대처할 수 있는 몇가지 방법은 있지만 CPU의 과부하는 메모리와 I/O 문제로 나누어지기 때문에 찾아내기 힘든 부분이다.
CPU의 과부하를 줄일 방법에 대해서 설명한다.
- 필요없는 데몬과 서비스를 줄인다. rwhod와 routed는 시스템의 성능을 저해하는 프로그램으로 이를 없애는 것만으로 많은 도움이 될 것이다. kudzu, portmap, nfslock, apmd, random, netfs, identd, atd, pcmcia, lpd, sendmail, gpm, xfs, linuxconf 등이 불필요하다면 사용하지 않아도 될 서비스들이다. cpu의 부하를 줄일 뿐만 아니라 보안 관점에서도 필요없으면 내리는 것이 낫다. 여기서 잘못 이해하기 쉬운 것이 sendmail 부분이다. pine등을 이용하여 메일을 발송할 때에는 센드메일 데몬을 이용하지 않는다. 센드메일을 백그라운드 작업으로 계속 작동시키는 목적은 외부로부터 메일을 받는데 있다. 그러므로 일반적인 메일서버의 기능을 하지 않고 단지 메일을 보내는 것이 목적이라면 sendmail을 가동시킬 필요가 없다. (**주3)
- at이나 cron 등을 이용 작업을 밤이나 시스템의 부하가 적을 때 실행하는 것도 좋은 방법이다. 보통 로그 로테이션, 백업, 로그분석 등은 새벽 시간을 이용하여 처리하는게 바람직하며 기본설정되어 있는 cron 작업은 대부분 새벽 4시에 가동이 된다.
- CPU 집약적인 작업은 nice를 이용 실행우선순위를 낮추면 편집작업과 갈은 상호대화적인 작업의 성능이 향상될 것이다.
- cpu 집약적인 작업의 실행우선순위를 높이면 작업 자체는 빨라지겠지만 상호대화적인 작업의 성능은 떨어질 것이다. 그런데 보통 일반적인 인터넷 서버로 운영을 한다면 CPU 집약적인 작업은 그렇게 많은 편은 아니며 꼭 서버에서 실행시켜도 되지 않는 작업이라면 다른 시스템을 이용하는 것이 좋다. 웹로그 분석도 이러한 경우에 속한다.
- nice를 이용하는것은 임시방편일 뿐이다. 부하가 계속 증가한다면 nice를 이용하는 것에도 한계가 있다. 시스템을 업그레이드하거나 부하를 분산할 시스템을 구입해야한다.
- 커널이나 프로그램의 컴파일을 하는 경우에도 nice를 이용하면 조금이나마 속도의 향상이 있다. 그렇지만 때로 nice를 잘못 사용하면 문제가 생길 수가 있으니 조심해야 한다. 예를 들어 오라클에서는 오라클 사용자 프로세스와 백그라운드 프로세스들을 같은 우선순위에 유지해야 한다. 설계가 그렇게 되어 있기 때문이다. 우선 순위를 변경할 경우 내용과 반응시간에 원치 않는 효과를 초래할 수도 있다. 예를 들어 log write process(LGWR)에 낮은 우선 순위를 부여할 경우, 이 프로세스는 충분한 횟수만큼 작동하지 못하고 LGWR은 병목현상을 일으키게 된다. 다른 한편, 만약 LGWR이 높은 우선 순위를 부여받게 되면, 사용자 프로세스는 느린 반응시간에 시달리게 될 것이다. 무엇이든 그냥 적용하는게 아니라 그 원리를 이해하고 조심스럽게 해야 한다. (**주4)
5. 메모리 문제 파악하기
시스템에 과부하가 걸려있는데도 휴지기간(idle time)이 많거나 ps에서 많은 양의 메모리를 필요로 하는 프로그램이 실행되고 있다면 메모리 문제를 생각해 볼 수 있다.
vmstat 5 를 실행해보자.
- swap-out이 지속적으로 항상 발생한다면 메모리가 부족한 것이다. 주기적으로 swap-outs이 발생하는건 정상적인 것이다. BSD 시스템에서는 비상호대화적인 작업을 스왑아웃한다. 현재 실행하고 있는 프로그램에서 스왑아웃이 계속 발생한다면 프로그램이 죽을 수도 있으며심각하게 메모리가 부족하다는것을 가리킨다. 스왑아웃필드(so)가 항상 0에 가까워야한다. 그렇지 않다면 프로세스들간에 가상 메모리에 대하여 경쟁하고 있으며 시스템은 페이징 상태에 있다. 페이징 활동은 또한 심각한 가용 메모리(free)의 부족과 직접적인 관련을 가지고 있으며 간접적으로는 시스템의 높은 CPU 사용시간 비율(sy)과 관련이 있다. 프로세스가 시작을 할 때 항상 이미지(text)와 데이터를 page-in 해야 하므로 page-in 열에서 높은 숫자가 항상 심각한 것은 아니라는 사실은 기억하고 있어야 한다.
- ps나 accounting 시스템에서 메모리 집약적인 작업이 있는지 확인을 한다. RSS필드나 storage integral이 큰 프로그램을 찾아보자. ps나 top에서 RSS는 프로세스가 사용중인 물리적 메모리 크기로 kbytes 단위로 보여준다. ELF 프로세스에서 사용된 라이브러리 페이지도 여기에 같이 계산이 된다. storage integral은 accounting 패키지에 들어있는 sa -K 옵션을 이용해 볼수있다.
메모리 문제를 해결할 몇가지 방법을 찾아보자.
- 시스템에서 버퍼 캐쉬가 있다면 크기를 줄인다. 대신 디스크 I/O성능에 영향을 줄 수있다. 리눅스는 /proc를 이용 전체 메모리에서 버퍼 캐쉬의 사용량을 조절할 수 있다. 이에 대해서는 마지막 장 에서 다루겠다.
- 네트워크 버퍼를 줄인다. 웹서버의 응답은 클라이언트에 직접 전달되는 것이 아니라 소켓 버퍼라는 네트워크 버퍼에 저장을 한다. OS에서는 적절한 수와 크기의 네트워크 버퍼를 가지고 있어야 메모리를 낭비하지도 않고 서버에서 필요한 버퍼를 기다리는 동안 서버의 작업이 중단되지도 않는 상태로 클라이언트의 접속을 처리할 수 있다. 갑작스럽게 접속이 중단되는 클라이언트에서 차지하고 있던 네트워크 버퍼는 웹 서버에서 메모리가 낭비되는 주요한 원인중의 하나이다. 아파치에는 SendBufferSize 지시자가 있어서 운영체제에서 지정되어 있는 TCP의 전송 버퍼를 늘릴 수 있다. 그런데 아직까지 필자도 리눅스쪽에서는 이 부분에 대하여 자세히 소개된 자료를 찾지 못했다. 아직 정확히 이해하지 못하고 있는 부분이지만 도움이 될까하여 고민 끝에 관련 내용을 포함한다. (**주5)
- 커널 테이블의 크기를 줄인다. 이를 통해 시스템의 자원을 제약할 수 있다. 예를 들어 파일 개수, 프로세스 개수등이 해당한다. 운영체제에서 이와 관련된 설정을 높이면 그만큼 커널 테이블의 크기가 늘어나 메모리도 그만큼 더 사용하게 된다.
- 많은 메모리를 필요로 하는 프로그램은 밤에 돌리자.
- 많은 메모리를 필요로 하는 프로그램은 배치 큐를 이용해 작업하자. at, cron등 활용
- 자기만 사용하는 프로그램이라면 프로그램에서 메모리를 효율적으로 사용하는지 점검하자.
- 메모리 요구량을 줄이기 위해 공유 메모리를 사용하자. 공유 메모리는 다수의 프로세스 간에 데이터를 공유하고 전달하는 효과적인 방법을 제공한다. 또한 어떤 특정한 명령을 여러명이 사용하는 경우 가상 주소공간에 해당 프로그램의 여러 복사본을 갖는게 아니라 물리적 공간에 하나의 복사본을 만들고 모든 프로세스가 그것을 공유할 수 있다. 동적 라이브러리는 여러 프로세스가 실행 코드를 공유하는 대표적인 예이다. 그런데 공유 라이브러리를 사용하는 경우 메모리는 절약할 수 있겠지만 프로그램의 성능은 정적으로 컴파일하는 것이 더 빠르다. 예를 들어 Mysql의 경우는 -static을 사용하지 않고 동적으로 링크하면 대략 13%정도 속도가 느려진다고 한다. (**주6)
- sendmail은 메모리를 많이 사용하는 프로그램으로 sendmail을 실행하는데 사용되는 시간에 제한을 두자. 아니면 네트웍을 재구성해서 메일서버를 다른 시스템으로 옮길 수 있다. 위에서 설명을 했던대로 메일을 받는 경우에만 sendmail을 사용하면 된다.
- 이막스(Emacs)는 메모리를 많이 사용하는 프로그램으로 vi 등 다른 에디터를 사용하자.
- 이 모든게 안되면 메모리를 구입하자. 하드웨어의 가격이 예전에 비해 많이 저렴해졌으며 이제 1G 메모리도 그렇게 특별한 시스템은 아닌 상황이다. 대신 프로그램에서 요구하는 기본 메모리양도 커졌다.
6. 디스크 I/O 문제 파악하기
시스템에 과부하가 걸려있는데도 휴지기간(idle time)이 많다면 디스크 I/O 문제를 생각해 볼 수 있다. 보통 메모리 문제와 I/O문제는 서로 관련이 되어있다.
vmstat 5 를 실행한다. 그리고 이것을 정상적인 시스템 상황과 비교해본다. 정상적인 경우보다 디스크 연산이 더 높은가?
디스크 활동이 시스템 디스크에 골고루 분산되어있는가? iostat 등을 이용하여 모니터링하면 될 것이다.
그렇지 않다면 가장 활동적인 디스크가 가장 빠른 디스크인가?
디스크 활동이 디스크의 특정 영역에 집중되어있는가? 디스크에 적당히 분포되어있는가? 아니면 서로 다른 반대방향의 지점에 있는가?
NFS를 사용하고 있는가? 사용자들이 자신의 지역파일에 접근하는데 속도가 느리다고 보고를 하는가? 원격 파일시스템을 사용하는가? 만약 원격 파일시스템을 사용하면 네트웍 상황에 대해서 살펴보자. 이경우에는 지역 디스크 I/O문제는 아니다.
vmstat를 이용 메모리 상황을 살펴보자. 시스템에서 페이징이나 스와핑이 계속 일어나고 있다면, 메모리에 문제가 있으며 이경우 디스크 I/O에 심각한 문제를 초래할 수 있다. 먼저 메모리 문제를 살펴보아야한다.
이에 대한 해결책을 찾아보자.
파일시스템을 재구성하고 가능한한 I/O작업을 분산시킨다.
루트 파일시스템에 가장 빠른 디스크 드라이브와 컨트롤러를 사용한다. 루트 파일 시스템이 대부분 가장 많은 I/O작업을 한다. 특정한 파일의 성능이 중요하다면 성능이 중요한 파일을 하나의 파일시스템에 넣고 이 파일시스템에 가장 빠른 드라이브를 사용한다.
퍼포먼스가 중요한 파일을 블락 크기가 큰 파일시스템에 넣는다. 리눅스에서 블락 크기는 블락당 1024, 2048, 4096이다. 파일시스템을 생성할 때 지정을 해야 한다. 블락 크기를 높이면 성능이 향상될 수는 있어도 불필요하게 낭비되는 하드디스크 공간이 늘어난다.
버퍼 캐쉬의 크기를 늘린다. 그러면 대신 메모리에 문제가 생길 수 있다.
단편화를 제거하기 위해 주기적으로 파일시스템을 재구성한다.
자주 사용하는 파일을 파일시스템의 시작부분에 집중시키는 프로그램을 사용할수 있다.
운영체제 차원의 튜닝에서 가장 많은 성능향상을 얻을 수 있는 분야가 I/O 부분이다. I/O성능은 하드디스크의 속도뿐만 아니라 시스템 버스에 물려있는 여러 구성 요소와 함께 좌우가 된다. 그런데 리눅스를 주로 사용하는 인텔x86 계열의 하드웨어는 타상용 유닉스 시스템에 비하면 I/O와 관련되어 성능이 미약한 편이다. 또 비디오 카드등은 64비트를 넘어 128비트 체계로 간지 오래되었지만 마더보드의 PCI 슬롯은 32비트 체계를 가지고 있다. PC레벨에서는 32비트 CPU가 사요되고 있고 메모리를 부분만 64비트로 동작하고 있을 뿐이다. (**주 7) 그렇지만 PC서버가 일반화되면서 예전 상용 유닉스 장비에만 있었던 여러 가지 기능들이 속속 도입되고 있으며 앞으로도 발전이 기대된다. 여기에 몇가지 이야기를 덧붙이자면 디스크 I/O의 속도향상을 위해 RAID등을 사용할 수도 있고 소프트웨어 차원에서의 소프트웨어 레이드도 현재 리눅스에서 지원이 되고 있다. 저널링 파일 시스템이 최근부터 본격적으로 지원되기 시작하여 파일시스템의 안정성과 무결성을 높임과 더불어 속도도 꾸준한 향상이 되고 있다. 현재 리눅스에서 지원하는 저널링 파일 시스템으로는 reiserfs, SGI의 XFS 등이 있다. (**주8)
디스크 용량에 문제가 생길 수도 있다. 파일시스템에 여유공간이 부족한가? 그렇다면 몇가지 방법을 생각해보자.
ㅇ 필요없는 파일을 cron 등을 이용 정기적으로 삭제하자. 오래된 코어 덤프 파일, 에디터 백업파일, auto-save 파일 등등.
디스크 쿼터를 이용해 사용자의 디스크 용량 사용을 제한할 수 있다.
매우 작은 파일이 모여있는 파일시스템에는 작은 블럭 사이즈를 사용한다. (소스 코드, 작은 데이타 파일 등등)
ㅇ /tmp, /var/tmp 등에는 계속 임시파일이 생성되고 man 페이지를 위한 임시파일도 계속 생성이 된다. 이에 대한 처리는 레드햇 리눅스 계열에서/etc/cron.daily/tmpwatch를 이용하여 처리한다. 3장에서 다시 소개할 것이다.
7. 네트웍 문제 점검
네트웍 문제 점검
rlogin이나 NFS를 이용하여 파일에 접근하는 사용자가 성능이 느리다고 생각이 든다면 이는 네트웍 용량이나 데이터 정합성에 문제가 있을 수 있다.
netstat -i 를 실행하자. 충돌(collison)이 크면 네트웍에 오버헤드가 걸렸다고 생각할 수 있다. 충돌률은 ifconfig -a 등을 이용해서 나온 결과중 (collisons/TX packets) X 100을 하면 나온다. input이나 output 에러가 많다면 하드웨어 문제일 수 있다. 입력에러가 많다면 네트웍의 특정한 곳에 문제가 있을 가능성이 크며 출력에러가 많다면 시스템과 네트웍 인터페이스에 문제가 있을 가능성이 크다.
충돌이나 네트웍 하드웨어의 문제가 아니라면, 어떤 시스템이 가장 느린지를 찾아야한다. dropped 패킷이 크다면, 원격 시스템은 아마도 들어오는 자료에 대해 충분히 빠르게 대응하지 못할 것이다. 원격 시스템에 cpu, 메모리, 디스크 I/O문제가 있는지 확인하자. 그게 아니라면 그 시스템은 네트웍의 과부하에 견디지 못할 것이다. 네트웍을 다시 재구성하고 느린 시스템을 파일 서버로 사용하지 말자.
ㅇ 기본적인 연결 테스트에는 ping 명령을 사용하며 네트워크 접속에 대한 점검을 한다면 ifconfig, arp, netsta 등을 이용하고 네트워크 하드웨어 문제를 점검해 보아야 한다.
# ifconfig -i
eth0 Link encap:Ethernet HWaddr 00:01:02:26:BD:CE
inet addr:211.111.111.111 Bcast:211.50.6.255 Mask:255.255.255.192
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:346297 errors:0 dropped:0 overruns:0 frame:0
TX packets:346683 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
Interrupt:10 Base address:0xd000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:7745 errors:0 dropped:0 overruns:0 frame:0
TX packets:7745 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
# netstat -i
Kernel Interface table
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 349675 0 0 0 350447 0 0 0 BRU
lo 16436 0 7825 0 0 0 7825 0 0 0 LRU
네트웍 부하 줄이는 방법 (**주9)
사용자가 네트웍을 통해 I/O집약적인 프로그램을 실행하지 않도록 막자. grep 프로그램이 I/O 집약적인 프로그램중의 대표적인 예이다. 대신 네트웍을 통해 로그인해서 작업하자.
네트웍에 연결된 컴퓨터와 디스크를 재구성해서 가능한 많은 사용자가 지역 지역 시스템에서 작업을 하도론 만든다.
디스크없는 워크스테이션의 숫자를 줄인다. 가능하다면 이런 워크스테이션은 제거한다.
뛰어난 네트웍 성능을 가진 시스템을 파일서버로 사용한다.
ㅇ 충돌률을 줄이기 위해서는 네트워크 세그먼트 상의 트래픽양을 줄여야 하며 이 경우 이더넷을 분리할 수 있다.
데이터 정합성에 문제가 있다면 유일한 해결책은 문제가 있는 하드웨어를 찾아서 바꾸는 것이다. 네트웍 분석툴이 이러한 작업을 하는데 반드시 필요할 것이다.
8. 마치며
이번 강의에서는 시스템 최적화를 위한 준비 단계로 프로세스, 메모리, I/O 부분을 중심으로 어떻게 현재 시스템 상태를 모니터링하고 문제를 발견하여 해결을 할 수 있는지에 대하여 설명을 하였다. 중요한 것은 시스템을 모니터링하는 것과 더불어 나온 결과에 대하여 정확하게 이해를 해야 한다는 것이다. 이에 대해서는 free를 예로 들어 설명을 하였다. 가장 먼저 주기적으로 시스템을 모니터링하여 문제를 파악하고 있어야 하고 문제가 발생했을 경우 여러 가지 상황에 따라 CPU, 메모리, I/O부분을 점검해야 한다.