2009년 10월 7일 수요일

[Linux] 시스템 최적화 - 동시사용자 늘리기위한 커널 조정

글쓴날 : 2000년 2월 24일(목)
글쓴이 : 문태준
(http://www.taejun.pe.kr, taejun@taejun.pe.kr, taejun@hitel.net)


참고자료
하이텔 리눅스동호회 Tip&경험담 lt 동시로 검색
20만통의 전자메일과 sendmail(마소 99. 05) 중 내용
기타 리눅스 및 유닉스 시스템 관리 관련 서적
운영체제론 서적

** 이글은 실제로 제가 대형서버를 운영하고 있는 상황에서 나온
글은 절대 아니며 그냥 여기저기서 주워들은 이야기들과 자료들을
토대로 해서 작성한 것입니다. 동시접속이 몇백명에서 몇천명되는
서비스를 하려면 단순하게 커널 컴파일한번 하고 끝나는 것이 아니라
여러가지 조정을 해주어야할 것이 많습니다. 또한 하드웨어와 OS
제한이 있으므로 로드밸런싱(부하분산), 트래픽분산등을 하는
스위칭 장비, 클러스터링 시스템 구성이 필요할 수 있습니다.
그만큼 설계를 잘 해야합니다. 여기에 언급한것은 단지 쉽게
할 수 있는 맛보기정도이지요. 이로인해서 생기는 손해에 대해서는
본인이 절대 책임을 지지 않습니다. 또한 내용중 틀린 부분도
많이 있을 것입니다.


0. 들어가며

대규모 서비스를 준비하는 경우 운영체제의 제한사항을 먼저 확인해야한다.
동시에 열수 있는 총파일수, 한 프로세스가 열수 있는 파일수 등등.

예를 들어 대형 웹서버를 아파치로 서비스하는 경우를 생각해보자.
아파치는 기본적으로 프로세스 방식으로 서비스를 처리한다. 이건
사용자의 요구가 올때마다 하나의 프로세스를 띄우므로 만약 동시에
10명의 사용자가 접속을 하면 10개의 프로세스가 떠야한다는 것이다.
최근의 아파치 서버는 MaxClients 150 이라고 설정되어있다. 이건
동시에 150개의 프로세스를 띄울수 있으며 결국 동시에 150명을 받아
들일 수 있다는 것이다.(실제로 이정도만 하더라도 절대로 작은 규모는
아니다) 그런데 만약 nobody가 만들어낼 수 있는 최대 프로세스 개수가
그 이하라면? 당연히 문제가 생길 것이다. 물론 최근 레드햇 6.0 이상
버전은 그 이상으로 맞추어져 있어서 문제가 생기지는 않겠지만.

문제는 프로세스가 많이 뜨면 프로세스뿐만이 아니라 열 수 있는 파일
수에서도 문제가 된다.

그러면 먼저 프로세스의 자원 한도에 대해서 알아보자.


1. 프로세스의 자원한도
프로세스의 자원한도를 리눅스에서는 ulimit 를 통해서 알 수 있다.
(Redhat 6.0, PowerLinux 등)

# ulimit -a (또는 ulimit -Sa) --> soft 한도
core file size (blocks) 0
data seg size (kbytes) unlimited
file size (blocks) unlimited
max memory size (kbytes) unlimited
stack size (kbytes) 8192
cpu time (seconds) unlimited
max user processes 2048
pipe size (512 bytes) 8
open files 1024
virtual memory (kbytes) 2105343



# ulimit -Ha ------>> hard 한도
core file size (blocks) unlimited
data seg size (kbytes) unlimited
file size (blocks) unlimited
max memory size (kbytes) unlimited
stack size (kbytes) unlimited
cpu time (seconds) unlimited
max user processes 2048
pipe size (512 bytes) 8
open files 1024
virtual memory (kbytes) 4194302


소프트한도는 새로은 프로세스가 만들어졌을때 디폴트로 적용되는
자원의 한도입니다. 이것을 하드한도까지 증가시킬 수 있습니다.
그렇지만 이 한도를 넘어서 확장하는것은 슈퍼유저만이 가능합니다.
하드한도는 절대적인 선이지요.
그렇다면 하드한도는 슈퍼유저라고 무한대로 늘릴수 있는가?
절대 아니지요. 이건 커널차원에서 지정을 해야합니다.
이에 대해서는 뒤에서 설명합니다.

위에서 각 항목을 볼까요?

코어파일의 최대크기
프로세스의 데이타 세그먼트 최대크기
쉘에서 생성되는 파일ㅢ 최대크기
resident set size의 최대크기(메모리 최대크기)
프로세스의 스택 최대크기
총 누적된 CPU시간(초)
단일 유저가 사용가능한 프로세스의 최대갯수
512-바이트 블락의 파이프 크기
open file descriptors의 최대 숫자(열수있는 최대파일수)
쉘에서 사용가능한 가상 메모리의 최대용량


각 설정을 수정할 수 있는데 학교에서 실습용 워크스테이션으로
쓰는게 아니라면 보통 이런작업을 할 일은 없을듯.
여기서 각 항목에 대해서 잘 모른다면 프로그래밍, OS 관련책을
보셔야할듯. (실은 저도 다 까먹었음)
위에서 하나의 프로세스가 열 수 있는 파일의 최대값은 ulimit
명령을 이용해서는 수정이 되지 않습니다. 단지 보여주기만
할 뿐이죠. 이건 커널소스를 뜯어고치든지 /proc 에서
직접 수정하든지 해야합니다.

최근의 리눅스배포판에서는 유저당 총 2048개의 프로세스를
띄울 수 있고 하나의 프로세스가 총 1024개의 파일을 열 수
있습니다. 실제로 이건 커널 2.0대에서 2.2대로 올라가면서
가장 크게 변한 부분중의 하나입니다. 실제로 이정도만해도
일반적인 서비스에서는 충분하고 이걸 바꾸어야 할 경우는
거의 없을 것입니다. 따른 말로 해서 "떡을 칩니당"
그런데 우리의 목표는 대규모 서비스를 하는 것이잖아요?




2. 파일, 프로세스 갯수 조정

주요하게 살펴야할 것듯.

리눅스에서 동시에 열 수 있는 파일수 : NR_FILE , 4096
한 프로세스가 열 수 있는 파일수 : NR_OPEN, 1024


# vi /usr/src/linux/include/linux/fs.h

#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */

#define NR_FILE 4096 /* this can well be larger on a larger system */


여기서 한 프로세스가 열수 있는 파일수를 수정하려면
/usr/src/linux/include/linux/limits.h 에서

#define NR_OPEN 1024

이부분도 수정을 해주어야합니다.

수정을 하였으면 컴파일을 해서 테스팅을 해야겠지요.
여기서 주의할 것은 메모리가 적은 시스템의 경우라면 부팅이 되지
않을 수도 있습니다.


그런데 굳이 컴파일을 하지 않아도 /proc 를 이용 변경할 수 있습니다.

# cat /proc/sys/fs/file-max
4096

# echo 8192 > /proc/sys/fs/file-max
# cat /proc/sys/fs/file-max
8192


# cat /proc/sys/fs/file-nr
591 184 8192

여기서 591는 현재 할당된 파일핸들, 184는 그중사용된 파일핸들,
8192는 파일핸들의 최대숫자입니다. 할당된 파일핸들이 최대치로
가더라도 실제 사용된 파일핸들의 숫자가 여유가 있다면 걱정할
필요는 없습니다.
(만약 시스템에서 "running out of file handles" 라는 메시지가
나온다면 열수 있는 파일에 문제가 있다는 것입니다)


그런데 안타깝게도 한 프로세스당 열수 있는 파일수(NR_OPEN)은
쉽게 바꿀 수가 없습니다. 기본 1024인데 이건 위에서 말을 하대로
컴파일을 하세요. 그다음 시스템이 뻗을지 계속 유지될지는...


여기서 좀만 더 살펴보지요.
(다시 NR_FILE 이 4096이라 하구요)

# cat /proc/sys/fs/inode-max
8319

# cat /proc/sys/fs/inode-nr
8340 1006


파일 핸들에 따라 커널에서 동적으로 inde structures를 할당합니다.
inode-max는 inode 핸들러의 최대값입니다.
여기서 inode-max 값은 3-4배이상으로 하라고 추천합니다.

/usr/src/linux/Documentation/proc.txt 에 /proc 에 대한
상세한 설명이 나와있는데 이에 대해서 살펴보지요.


This value should be 3 to 4 times larger than the value
in file-max, since stdin, stdout, and network sockets also need an
inode struct to handle them.

그러니깐 stdin(표준입력), stdout(표준출력), 네트웍 소켓에서
파일을 다루기 위해 inode struct 가 필요하다고 하네요.


메일서버가 200개 이상 실행되거나 웹서버가 동시에 400개 이상
실행되는 대형 사이트에는 최대값을 크게 만드는 것이 좋다고
하네요. 그런데 중요한건 무조건 늘린다고 좋은것은 아니겠지요?
최대값이 늘어날 수록 더 많은 메모리가 필요하고 자원할당도
더 많이 필요하기요.

그래서 가능하면 어떤 프로그램에서 쓸데없는 파일은 열지 않도록
하면 파일핸들을 할당하지 않기때메 열린 파일수가 줄어들겠지요.
하나의 열린 파일수를 줄이면 268개의 파일을 닫는 효과가
있다고 하는데 제가 이부분은 아직 정확히 이해가 가지 않습니다.


이번엔 시스템의 최대 프로세스수를 생각해볼까요?
예를 들어 텔넷으로 접근하는 경우 최소한 로그인프로그램과
쉘프로그램 두개의 프로세스가 생성되겠지요? 256명이 접근하면
최소 512. 그렇다면 시스템의 최대 프로세스 갯수를 설정하는
것도 위와 비슷합니다.

/usr/src/linux/include/linux/tasks.h

여기서보면

#define NR_TASKS 2560 /* On x86 Max 4092, or 4090 w/APM configured. */

#define MAX_TASKS_PER_USER 2048

x86 시스템에서는 최대 4092까지 가능하다고 되어있고
유저당 최대 프로세스수는 2048입니다. 이건 ulimit에서
보았지요?


자 이제 마지막으로 프로세스에서 열어놓은 파일을 어떻게
확인할 것인가?

lsof 프로그램을 이용하면 됩니다.

man 페이지만 하더라도 프린트하면 한 30여페이지가 되는것
같네요. 한번 연구해볼 가치가 있을듯.

오픈파일은 정규파일, 디렉토리, 블락 및 캐릭터파일(device),
라이브러리, executing text reference, 스트림 또는
네트웍파일(인터넷 소켓, NFS file 또는 유닉스 도메인 소켓)
등이 있습니다.

댓글 없음:

댓글 쓰기