initng과 upstart
난이도 : 중급
M. Tim Jones, Consultant Engineer, Emulex
2007 년 4 월 03 일
개발자들이 리눅스®에 대해 갖는 가장 큰 불만은 리눅스 부팅 속도입니다. 기본적으로, 리눅스는 클라이언트 데스크탑 또는 서버용으로 사용될 수 있는 범용 OS입니다. 리눅스의 유연성 덕택에, 광범위하게 사용되지만, 특정 구성에 맞춰 최적화 되지는 않습니다. 이 글에서는 리눅스 부팅 속도를 높일 수 있는 옵션들을 소개하고, 아울러 초기화 프로세스를 병렬화 하는 두 가지 옵션들도 소개합니다. 또한, 부팅 프로세스의 성능을 그래픽으로 나타내는 방법도 설명합니다.
(무엇보다도 커널 디버거가 부족한) GNU /리눅스에 대해 갖는 공통적인 불만은 OS 시작에 시간이 많이 걸린다는 것이다. 이 프로세스를 부팅(booting)으로 간주할 수 있지만, 사실 여러 가지 독립적인 태스크들이 개입되어 콜드(cold) 시스템에서 쉘 또는 윈도우 매니저를 통해 인터랙팅 할 수 있는 시스템으로 변해간다. 리눅스 부팅과 초기화 프로세스에 대해 알아보자.
리눅스 부팅에는 많은 단계들이 있지만, 이 프로세스를 세 가지 기본적인 단계로 나눌 수 있다. 그림 1에서 묘사한 것처럼 BIOS, 커널 부트(kernel boot), 시스템 초기화(system initialization,)로 나뉠 수 있다.
그림 1. 리눅스 부팅 프로세스
여러분이 처음 컴퓨터를 켜거나 리셋 할 때, 컴퓨터 프로세서는 basic input/output system(BIOS)에서 실행을 시작한다. BIOS는 시스템의 마더보드에 있는 플래시 메모리 장치에 저장되어 있으며, 이는 기본 컴포넌트들(시스템 메모리)의 초기 테스팅, OS를 부팅하는 방법 결정 등 많은 작업(job)을 갖고 있다. PC 기반 컴퓨터들이 매우 유연해지면서, 부팅 장치는 하드 디스크, CD-ROM 또는 네트워크 인터페이스 같은 기타 장치들을 포함하여 마더보드에 부착된 많은 개별 장치들 중 하나가 될 수 있다.
여러분이 일반적으로 부팅 할 곳(주로 하드 디스크)에서 장치를 선택함으로써, 부팅 장치를 결정하는 프로세스를 최적화 할 수 있다. 하지만, 지금까지, BIOS 단계 중에서 가장 시간을 많이 소비하는 측면은 메모리 테스트이다. 이 테스트의 특정 측면들(예를 들어, 전체 메모리 테스트 같은)을 실행하지 않으면 속도 향상에는 도움이 될 수 있지만 부팅 시 시스템 무결성 테스트라는 대가를 치러야 한다.
부팅 장치가 발견되면 리눅스 커널 부팅 프로세스가 시작된다. 이 프로세스는 (대략) 두 단계(제 1 단계 부팅(first-stage boot)과 제 2 단계 부팅(second-stage boot.))로 발생한다. 제 1 단계는 간단한 부트 로더(부팅 장치의 마스터 부트 레코드(MBR)에 있음)로 구성되고, 하는 일은 제 2 단계 부트 로더를 로딩한다. 제 1 단계 부트 로더는 파티션 테이블을 사용하여 제 2 단계 부트 로더를 찾는다. 제 1 단계 부트 로더는 테이블을 검사하면서, 활성 파티션을 찾는다. 로더가 파티션을 배치하면, 제 2 단계 부트 로더를 RAM에 로딩하고 이를 실행한다.
제 2 단계 부트 로더가 RAM에 로딩되면, 리눅스 커널 이미지와 초기 RAM 디스크 이미지(initrd)가 RAM에 로딩된다. 커널이 실행될 때, 하이 메모리로 압축을 풀고 initrd를 나중에 사용할 수 있도록 복사한다.
|
커널 부트 프로세스는 매우 복잡하지만 매우 빠르다. 대부분의 코드가 해당 시스템의 기계어로 작성되기 때문이다. 커널 부트 순서의 말미에, init 프로세스가 시작되며, init은 리눅스 시스템에서 생성된 첫 번째 프로세스 이므로, 이것은 다른 모든 프로세스들의 엄마(mother)인 셈이다. (모든 프로세스들은 init의 자손(child)이라고 할 수 있다.)
본 글의 주제인 init 프로세스는 커널 부트 시퀀스가 완료되면서 생성된 첫 번째 프로세스이다. 리눅스는 init 프로세스를 사용하여 서비스와 애플리케이션을 초기화 하는데, 이것이 리눅스를 더욱 유용하게 만든다.
init 프로세스가 시작될 때, /etc/inittab.이라고 하는 파일을 연다. 이 파일은 init용 설정 파일이고, 시스템을 초기화 하는 방법을 정의하고 있다. 이 파일에는 전원 오류가 발생할 때 무엇을 해야 하는지에 대한 정보와, Ctrl-Alt-Delete 키 시퀀스를 탐지할 때 반응하는 방법 등을 수록하고 있다. Listing 1은 이 파일의 일부이다.
inittab 설정 파일은 공통 포맷인 id:runlevels:action:process.로 여러 엔트리들을 정의하고 있다. id는 엔트리를 구분하는 문자 시퀀스이다. runlevels는 액션이 취해질 runlevel을 정의한다. action은 특별한 액션을 지정한다. 마지막으로 process는 실행될 프로세스를 정의한다.
Listing 1. inittab 파일 발췌
# The default runlevelid:2:initdefault# Boot-time system configuration/initialization scriptsi::sysinit:/etc/init.d/rcS# Runlevelsl0:0:wait:/etc/init.d/rc 0l1:1:wait:/etc/init.d/rc 1l2:2:wait:/etc/init.d/rc 2l3:3:wait:/etc/init.d/rc 3l4:4:wait:/etc/init.d/rc 4l5:5:wait:/etc/init.d/rc 5l6:6:wait:/etc/init.d/rc 6z6:6:respawn:/sbin/sulogin# How to react to ctrl-alt-delca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now |
|
init이 /etc/inittab을 로딩하면, 시스템은 initdefault 액션이 정의한 runlevel로 간다. Listing 1에서 보듯, 이것은 runlevel 2가 된다. runlevel을 시스템의 상태로 간주하라. 예를 들어, runlevel 0은 시스템 중지 상태이고, runlevel 1은 싱글 유저 모드이다. runlevel 2에서 5까지는 멀티 유저 상태이고, runlevel 6은 재부팅을 나타낸다. (일부 배포판에서는 runlevel을 다르게 표시할 수 있다.) 또는, 실행될 프로세스(시스템의 상태를 정의하는 프로세스)를 정의하는 방식으로 runlevel을 간주할 수 있다.
주: 시스템의 현재 runlevel을 보려면, runlevel 명령어를 사용한다.
Listing 1에서 정의된 것처럼, initdefault는 기본 init 레벨을 2(멀티 유저 모드)로 정한다. 초기 runlevel이 정의된 후에, 인자 2(runlevel)를 가진 rc 스크립트가 실행되어 시스템을 불러온다. 이 스크립트는 다양한 서비스와 애플리케이션 스크립트를 실행하여 특정 엘리먼트를 시작 또는 중지한다. 이 경우, 파일들은 /etc/rc2.d/에 정의된다. 예를 들어, MySQL 애플리케이션이 시작되었다면(시스템 시작처럼) /etc/rc2.d/S20mysql start로서 실행되었을 것이다. 시스템이 중지될 때, 같은 스크립트가 stop 인자와 함께 실행된다.
|
결국, 많은 스크립트들이 순차적으로(serially) 실행되어 필요한 다양한 서비스들을 시작한다. (여러분은 리눅스에서 부팅 스크린의 일부로 보게 될 것이다.) 서비스들이 서로 관련이 없다 하더라도, 하나가 시작된 후에 다른 것이 시작된다. 그래서 결국 이 프로세스에 시간이 드는 것이다. (특히, 많은 서비스들을 갖고 있는 큰 시스템이 더욱 그러하다.)
이러한 문제에 대한 확실한 솔루션은 init 명령의 순차성을 없애고 보다 병렬적으로(parallel) 실행하도록 하는 것이다. 많은 곳에서 멀티 프로세싱 시스템을 사용하고 있는 것을 보면 이해가 될 것이다. 예를 들어, 소켓 스크립팅(socket striping,) 또는 두 개 이상의 소켓을 사용하여 데이터를 병렬로 이동하는 것은 이러한 개념에 입각한 솔루션이다. Redundant array of independent disks (RAID) 시스템 역시 디스크 주위를 (병렬 방식으로) 스트리핑 하여 디스크 I/O 성능을 높이고 있다.
|
|
전통적인 init 프로세스(sysvinit)는 순차 프로세스이므로, 이러한 시스템 부분은 최적화 하기에 알맞다. 사실, init 프로세스를 최적화 할 때 여러 가지 방식들을 사용할 수 있다. 이러한 방식 몇 가지를 살펴보고, 문제를 해결하는 방법을 알아보자. 첫 번째 두 방식은 종속 관계(dependency) 기반(종속 관계를 사용하여 병렬화를 이룩한다.)이고, 세 번째는 이벤트 기반 시스템(프로세스가 이벤트에 의존하여 시작과 중지할 때를 지시한다.)이다.



덧글