[출처] http://maso.zdnet.co.kr/maso/2000/08/09/014004,965778277,178.html


[Admin] 리눅스 서버 최적화 테크닉 키우기 2

커널 설정시 선택 사항과 애플리케이션 최적화
리눅스 커널에 여러 기능을 추가하면 나타날 성능저하 문제를 피하기 위한 방법으로
주요 기능을 커널에서 떼어내 모듈로 제공하는 방법이 있다. 기타 기능을 모듈로
처리해 커널을 최소화하면 시스템 성능을 높일 수 있으며, 모듈로 제공된 기능은
시스템 환경에 따라 선택할 수 있어 편리하다. 커널 설정시 주의해야 할 사항과
애플리케이션 최적화에 대해 살펴보자.

이상호 성균관대학교 산업용 네트워크 연구실


--------------------------------------------------------------------------------

리눅스 서버 최적화 차원에서 지난호에 컴파일을 위한 gcc 옵션 설정까지 알아봤다.
이번호에는 컴파일과 관련된 옵션을 정리하고 모듈과 커널 설정에 대해 알아본다.

지난호에서는 주로 펜티엄 프로 이상의 CPU를 대상으로 옵션을 설명했다. 아직 펜티엄
기반의 시스템이 많이 있으므로 펜티엄 CPU에서의 커널 컴파일을 위한 옵션을
알아보면 다음과 같다.

CFLAGS= -Wall -Wstrict-prototypes -O3 -march=pentium -mcpu=pentium -ffast-math
-funroll-loops -fomit-frame-pointer -fforce-mem -fforce-addr -malign-double
-fno-exceptions

물론 HOSTFLAGS도 같은 값을 갖는다.

지금까지 소개한 gcc 옵션은 -O, -f, -m으로 시작했다. -O는 전반적인 최적화 정도를,
-f는 실제 소스 코드 중심의 최적화 기능을, -m은 CPU에 따라 사용할 명령어를 각각
정할 수 있는 옵션이다. 즉 CPU마다 다른 선택사항을 갖게 되는데, -m으로 시작되는
옵션을 사용해 만들어진 실행 코드는 다른 CPU를 사용하는 시스템에서 실행될 경우
문제를 일으킬 수 있다.

지금까지 사용한 옵션을 정리하면 <표 1>과 같다.

gcc의 사용 방법과 옵션에 대해 더 자세히 알고 싶은 독자는 gcc 매뉴얼을 참고하기
바란다.

이제 펜티엄 사용자들도 커널 컴파일까지 진행해 보았을 것이다. 지금부터 모듈에
관해 간단히 알아보자.

모듈의 용도와 컴파일

모듈은 사용자들이 커널에 필요한 기능을 쉽게 포함시키기 위해 만들어졌다.
지난호에서 살펴본 Monolithic 커널 구조에서는 기능을 확대하고 새로운 디바이스
드라이버를 추가하면 커널의 크기가 늘어나게 된다. 그리고 개발자는 커널의 부분적인
수정에도 불구하고 전체 커널을 여러 번 부팅해 테스트해야 하는 불편함이 따른다.
이를 개선하기 위해 만들어진 것이 모듈이다.

모듈을 사용하는 경우 대부분의 시스템에서 사용되는 기본적인 기능이 최소의 커널인
코어 커널로 구성되며, 나머지는 시스템 환경에 따라 선택하면 된다. 부트 과정에서
먼저 기본적인 코어 커널이 메모리에 로드된 다음, 모듈이 로드돼 커널에 동적으로
링크된다.

모듈의 실행, 즉 동적 링크와 삭제는 kmod라는 별도의 데몬이 관리하게 된다. Make
config 과정에서 모듈을 사용하는 경우 “Enable Loadable module support?”의 문항
이후에 kmod를 사용할 것인지를 묻는데 이때 사용 선택을 해준다.

상위 레벨(사용자 애플리케이션)로부터 호출된 시스템 콜은 코어 커널로
받아들여지며, 필요한 기능이 모듈에 포함되는 경우 코어 커널은 시스템 콜과 관련된
작업을 모듈을 통해 처리한다.

이로써 커널 리컴파일 과정에서 코어 커널까지 컴파일했다고 볼 수 있다. 남은 것은
모듈 컴파일이다. 모듈 컴파일을 위해 다시 /usr/src/linux 디렉토리로 이동하자.

이제 사용할 모듈을 컴파일해 사용하려면 다음과 같이 입력하면 된다. 물론 make
config 과정에서 Enable Loadable Module Support를 ‘Y’로 했어야 한다.

> make modules
> make modules_install

이제 모듈을 포함해 전체 커널의 컴파일 과정을 마쳤다. 이제 새로 생성된 커널을
사용해 보자.

새로운 커널의 설치

새로 생성된 코어 커널은 /usr/src/linux/arc/i386/bzImage에 위치한다. 보통 리눅스
커널은 /boot 디렉토리에 있지만 시스템마다 다를 수 있다. 이를 확인하려면 먼저
/etc/lilo.conf를 살펴본다.

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
default=linux

image=/boot/vmlinuz-version
    label=linux
   initrd=/boot/initrd-version.img
   read-only
   root=/dev/hda1

image 섹션에 리눅스 부트를 위한 정보가 나타난다. 도스 또는 윈도우와 함께
사용하는 시스템에서는 others 섹션이 표시돼 있을 것이다.

Image 섹션의 첫 부분에 /boot/vmliuz-version이 적혀있는데 리눅스로 부트하는 경우,
/boot/vmlinuz-version을 커널 이미지로 사용한다는 의미다. Vmlinuz-version에서
version은 커널의 버전을 나타낸 것이다. 만약 버전이 2.2.12라고 하면
vmlinux-2.2.12 등으로 표시돼 있을 것이다. root는 /boot/vmliuz-version이 위치한
드라이브를 가리킨다. label은 linux라고 돼 있는데, 이는 lilo: 프롬프트에서
linux를 입력하면 해당 이미지를 부트시킨다는 의미이다.

이제 새로운 커널 이미지를 사용해 보자. 만약을 위해 이전의 이미지는 백업해 두는
것이 좋다. 몇몇 시스템은 /boot 디렉토리가 10MB 크기 내외의 별도 파티션으로
구성돼 있는 경우가 있는데 이때를 고려해 다른 곳에 별도의 디렉토리를 만들어
복사하기로 한다. 먼저 커널 이미지 백업용 디렉토리를 생성하자.

> mkdir /boot_back
> cp /boot/* /boot_back/

다음은 새로운 커널 이미지를 /boot 디렉토리에 복사한다.

> cp /usr/src/linux/arch/i386/bzImage /boot/vmlinuz-version.number

이제 System.map 파일을 /boot 디렉토리에 복사한다.

> cp /usr/src/linux/System.map-version-number /boot/

복사된 커널 이미지와 System.map 파일의 이름을 단순화하기 위해 일상적으로
사용되는 이름으로 링크해 바꾼다.

>cd /boot
>ln ?fs vmlinux-version.number vmlinux
>ln ?fs System.map-version.number System.map

이제 남은 일은 lilo.conf 파일을 수정해 lilo에 의해 새로운 커널이 부트되도록
설정해주는 것이다. /boot 디렉토리와 백업용으로 생성한 /boot_back 디렉토리가 하드
디스크의 같은 파티션인 /dev/hda1에 존재한다고 가정하면 다음과 같이 수정할 수
있다.

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
default=linux

image=/boot/vmlinuz
   label=linux
   initrd=/boot/initrd-version.img
   read-only
   root=/dev/hda1

image=/boot_backup/vmlinuz-version
   label=old
   initrd=/boot_backup/initrd-version.img
   read-only
   root=/dev/hda1

위의 lilo.conf를 살펴보면 새로운 이미지와 예전 이미지 두 개를 함께 사용하는
것으로 돼 있다. 컴퓨터의 전원을 켜면 ‘lilo:’라는 프롬프트가 나오는데 이때
linux를 입력하면 새로운 이미지가 사용될 것이고, old를 압력하면 이전의 커널
이미지가 사용될 것이다. 이는 새로운 커널에 문제가 발생할 경우를 대비한 것이다.
만약 새로운 커널에 심각한 문제가 발생해 부트되지 않으면 예전의 커널을 사용해
복구하기 위한 배려이다.

이제 lilo의 설정을 다음과 같이 업데이트한다.

>/sbin/lilo -v

이제 다시 부트해 새로운 커널이 올바르게 동작하는지 살펴보자. 지금까지 전반적인
커널 최적화 과정을 살펴보았다. 다음은 실제 커널의 기능을 설정하는 과정에서
주의할 선택 사항을 정리해 보자.

커널 설정시 주의사항

커널에 포함될 기능을 선택할 때 주의해야 할 사항은 리눅스가 현재 어떤 용도로
사용되느냐에 따라 달라진다. 보통 전체적인 성능 향상이 요구되는 서버, 일반적인
사용자용 클라이언트 시스템으로 사용될 때와 라우터 등의 네트워크 서버로 사용될
때의 커널 설정은 크게 달라진다.

서버: 서버로 사용되는 시스템은 보통 설정이 크게 바뀌지 않으며, 고정적이면서도
대용량의 데이터를 처리한다. 이때 모듈 사용이 권장되지 않으며 개발자를 위한
설정은 선택하지 않는 게 좋다.
워크스테이션: 워크스테이션으로의 사용은 최종 사용자의 편의성을 중시해야 한다.
사운드 카드와 같은 장치들은 바뀔 수도 있으며, 기능 또한 선택적으로 바꿔가며
사용할 수 있다. 이때는 모듈을 사용하는 것이 더 편하다.
네트워크 장비: 시스코 라우터 같은 별도 라우터를 도입하는 대신 리눅스 서버를
라우터로 사용할 경우, 별도의 디바이스 드라이버나 커널 레벨의 프로그래밍을 해야
하는 경우가 많다. 커널 레벨에서의 프로그래밍은 모듈 프로그래밍이 더 편하다.
우선은 서버와 워크스테이션의 공통적인 부분만 설명하며, 네트워크 장비로의 활용에
대해선 다음호에서 살펴보자.

각각의 설정 방법에서 큰 차이가 있지만, 대부분의 커널 기능은 make config 과정에서
선택하게 된다. 가장 먼저 생각할 점은 사용하는 호스트에서 어떤 기능이 필요한가를
선택하는 것이다. 될 수 있으면 make config에서 별로 사용하지 않는 기능은
‘N’으로 체크해 두는 것이 좋다. 다음은 모듈을 사용할 것인지, 모듈을 사용할 경우
어떤 기능을 모듈로 사용하고, 어떤 기능을 코어 커널에 포함시킬 것인지에 대한
문제다.

먼저 모듈을 사용하면 시스템 성능 차원에서 효율이 떨어진다. 실제 모듈은 코어
커널에 붙어 동작하는 것처럼 보이지만 사실은 커널의 일부가 쓰레딩돼 사용되는
것으로 볼 수 있다. 즉, 실제 모듈의 동작은 커널과 분리돼 동작한다. 이 때문에
약간의 비효율성이 따를 수 있는데 이를 방지하기 위해 자주 쓰이는 부분과 그렇지
않는 부분을 분리하는 방법이 있다. 서버로 사용할 경우 가급적 모듈의 사용은 권하지
않는다. 보통 서버에서는 마너리식 커널을 선호한다. 모듈을 사용하는 경우 먼저 make
config 과정에서 ‘Loadable module support’란의 문항을 모두 선택해야 한다. 특히
kmod는 일정 시간마다 시스템 환경을 감시해 필요한 모듈을 실행시키거나 불필요한
모듈을 제거하는 일도 함께 하므로 꼭 포함하도록 한다. 몇몇 버전에서는 이를 묻지
않는다.

모듈을 사용하더라도 자주 쓰이는 부분은 코어 커널에 꼭 포함하도록 한다. 그리고
몇몇 디바이스 드라이버와 자주 사용하지 않는 기능들은 모듈로 처리한다.

필자의 경우 리눅스를 주로 사용하므로 기본 파일 시스템인 ext2를 코어 커널로
처리하고 기끔 사용하는 도스를 모듈로 선택했다.

make config 다음에 소개할 몇몇 공통적으로 적용되는 선택 항목은 성능에 큰 영향을
미친다. 이를 각 항목별로 살펴보자.

Code maturity level options
Prompt for development and/or incomplete code/drivers[N/y/?]
: 개발자를 위한 항목이니 선택하지 않는다.

Processor types and features
Math emulation [N/y/?]
: 부동소수점 연산장치가 없는 경우에만 선택. 펜티엄 이상에서는 선택하지 않는다.
MTRR support [Y/n/?]
: 펜티엄Ⅱ 이상에선 선택한다.

Symetric multi-processing support [N/y/?]
: 여러 개의 CPU를 사용하는 경우에만 선택해야 한다.

Genneral setup
PCI access mode[Any]
: PCI 접근을 BIOS를 통해 할 것인지 아니면 커널에서 직접 접근할 것인지를 선택하는
것으로, 어떤 경로에서나 접근할 수 있도록 Any를 선택하자.
PCI quirks [N/y/?]
Backward-compatible /proc/pci [N/y/?]
: 가급적 위의 두 기능은 선택하지 않는다.

Block devices
CMD640 chipset bugfix/support [N/y/?]
RZ1000 chipset bugfix/support [N/y/?]
: 위의 두 선택은 해당 chipset을 사용하는 경우에 한한다. 대부분 현재 생산되는
보드에서는 사용되지 않는 것 같다.

이것으로 일반적인 커널 최적화를 위한 설정에 대해 살펴보았다. 기본적인 설정에
대해서만 알아본 것 같아 아쉽지만 애플리케이션 최적화로 넘어가자.

애플리케이션 프로그램의 최적화

리눅스 애플리케이션은 소스 코드 형태와 바이너리 형태로 배포되고 있다. 이미
실행파일이 만들어진 바이너리 배포판의 경우 다시 최적화하기 어렵기 때문에 커널의
경우와 마찬가지로 소스 코드 형태의 배포판을 알맞게 컴파일해 사용하는 방법을
살펴보자.

보통 리눅스를 처음 설치할 때 애플리케이션 프로그램 또한 미리 컴파일된 바이너리가
설치되므로 이들을 제거하고 소스 코드를 새로 컴파일해야 한다. 다른 방식으로
최적화된 프로그램도 있는데 몇몇 데몬의 경우 일부 기능이 커널에 포함되는 경우가
있다. 이는 빠른 응답을 위해 몇몇 기능을 커널에서 처리하도록 한 것인데, httpd를
모듈로 바꾼 형태도 등장했다. Khttpd라고 불리는 웹 서버인데
http://www.fenrus.demon.nl/에서 자세한 정보를 만날 수 있다.
보통 프로그램을
모듈로 바꾼다는 것은 쉽게 할 수 있는 일이 아니므로 소스 코드를 응용하는 방법을
설명한다.

보통 GNU 배포 형식을 따르는 프로그램의 소스 코드는 tar.gz 형태로 압축돼 있다.
보통 이런 형식으로 배포되는 프로그램은 다음과 같은 간단한 과정으로 컴파일을
마치게 된다.

>./configure
>make

configure 명령을 수행하면 해당 호스트 환경을 파악해 Makefile이 생성되며, 이때
make는 생성된 Makefile을 바탕으로 컴파일을 진행한다.

지난호에 설명했던 /etc/profile 설정은 위와 같은 소스 코드 배포본을 컴파일하는
경우를 위해서이다. /etc/profile에 CFLAGS를 정의하고 익스포트(export)해 make를
통해 컴파일하는 경우 gcc 옵션이 공통적으로 적용되게 했다.

현재 레드햇의 경우 rpm 형식으로 소스 코드를 배포하고 있는데 소스 코드를 패키징한
rpm의 경우 다음과 같은 형식으로 돼 있다.

프로그램이름-버전.src.rpm

다음과 같이 입력하면 소스 코드를 바탕으로 새로운 바이너리를 만들어낸다.

>rpm --rebuild 프로그램 이름-버전.src.rpm

rpm 패키지 형태로 압축된 소스 코드는 컴파일시 /etc/profile에 설정한 CFLAGS 값이
적용되지 않는다. rpm을 통해 컴파일 옵션이 적용되기 위해서는 /usr/lib/rpm
디렉토리의 rpmrc 설정값을 바꿔줘야 한다. /usr/lib/rpm/rpmrc를 살펴보면,
optflags라는 필드가 있는데 각 플랫폼에 따라 옵션을 지정할 수 있다. 인텔 계열의
경우 optflags: i386으로 시작되는 부분에 지정돼 있다. 이 부분을 /etc/profile의
CFLAGS 값과 마찬가지로 바꿔준다. 펜티엄 프로, 펜티엄 Ⅱ, 펜티엄 Ⅲ인 경우 다음과
같이 고쳐준다.

optflags: i386 -O9 -funroll-loops -ffast-math -malign-double -mcpu=pentiumpro
-march=pentiumpro -fomit-frame-pointer -fno-exceptions

펜티엄의 경우 다음과 같이 설정하면 된다.

optflags: i386 -O3 -march=pentium -mcpu=pentium -ffast-math -funroll-loops
-fomit-frame-pointer -fforce-mem -fforce-addr -malign-double -fno-exceptions

이제까지 컴파일을 통한 최적화를 살펴보았다. 다음호에선 리눅스 호스트를 서버 또는
라우터로 이용할 때 고려해야 할 사항을 살펴보겠다.

필자 연락처 : turtle@ece.skku.ac.kr
정리 : 박세영 andrea@sbmedia.co.kr

Created by KAN and MISO Return to Original Intention.. / chtla.com ( Site Version 1.0 )
 




Copyright(c) 2001, 수퍼유저코리아 All Rights Reserved.
서버구축(운용)상담 : e-mail : webmaster@superuser.co.kr