커널 파라미터와 자원 제한
Oracle용 커널 파라미터의 일시 및 영구 적용, ulimit과 실행 중인 DB 프로세스의 자원 한도 점검
#핵심 요약
Oracle은 기동할 때 SGA용 큰 공유 메모리를 잡고 많은 프로세스가 세마포어, 파일을 함께 쓰므로, 커널 기본값으로는 인스턴스가 뜨지 않거나 ORA-27102, ORA-27125 같은 오류가 날 수 있음
sysctl -w는 지금 커널에만(재부팅하면 사라짐), /etc/sysctl.d/*.conf, /etc/sysctl.conf는 영구 설정이며, 파일을 고친 뒤에는 sysctl -p 파일 또는 sysctl --system으로 적용하고 다시 조회함
fs.file-max는 시스템 전체 파일 수, ulimit -n(nofile)은 프로세스 하나의 파일 수라 둘 다 충분해야 함
limits 파일은 새 로그인 세션부터 적용되므로 su - oracle로 다시 들어가 확인하고, 실행 중인 DB는 /proc/<PMON PID>/limits로 봄
#개념과 동작 원리
| 커널 파라미터 | Oracle 쪽 자원 | 관련 초기화 파라미터 |
|---|---|---|
kernel.shmmax |
공유 메모리 세그먼트 하나의 최대 크기(바이트), SGA보다 커야 함 | SGA_MAX_SIZE, MEMORY_MAX_TARGET |
kernel.shmall |
시스템 전체 공유 메모리 총량(페이지 단위) | SGA 합계 |
kernel.shmmni |
공유 메모리 세그먼트 최대 개수 | |
kernel.sem |
프로세스 동기화용 세마포어 네 값 | PROCESSES, SESSIONS |
fs.file-max |
시스템 전체 파일 핸들 수 | DB_FILES, PROCESSES |
fs.aio-max-nr |
동시 비동기 I/O 요청 수 | DISK_ASYNCH_IO |
net.ipv4.ip_local_port_range |
아웃바운드 연결에 쓰는 로컬 포트 범위(시작, 끝) | |
net.core.rmem_*, wmem_* |
소켓 수신, 송신 버퍼, SQL*Net, RAC 인터커넥트, Data Guard 전송 |
kernel.sem 자리 |
의미 |
|---|---|
| SEMMSL (1번째) | 세마포어 집합 하나당 최대 세마포어 수 |
| SEMMNS (2번째) | 시스템 전체 세마포어 총수 |
| SEMOPM (3번째) | semop() 한 번에 처리하는 작업 수 |
| SEMMNI (4번째) | 시스템 전체 세마포어 집합 수 |
sysctl의 파라미터 이름은 /proc/sys 아래 가상 파일과 1:1로 대응하며 점(.)이 슬래시(/)로 바뀜(net.core.rmem_max → /proc/sys/net/core/rmem_max)/proc/sys는 디스크 파일이 아니라 커널이 메모리에서 보여 주는 값이라 여기에 쓰면 즉시 반영됨
#필수 명령어 또는 SQL
#커널 파라미터 조회
sysctl kernel.shmmax
cat /proc/sys/kernel/shmmax
sysctl kernel.shmall
getconf PAGE_SIZE
sysctl kernel.sem
cat /proc/sys/kernel/sem
sysctl fs.file-max
sysctl fs.aio-max-nr
sysctl net.ipv4.ip_local_port_range
sysctl net.core.rmem_max
sysctl -a | grep -E 'kernel.shm|kernel.sem|fs.file-max|fs.aio-max-nr'결과 해석:
kernel.shmall은 페이지 단위라 바이트로는 페이지 크기를 곱함
실습 값 1073741824 페이지 × 4096바이트는 약 4TB이고, shmall 2097152 × 4096은 8GB임
kernel.shmmax = 4398046511104(4TB)는 preinstall 권장값이며, 설정 전에는 커널 기본값으로 매우 큰 수가 보이기도 함
kernel.sem의 네 값은 탭으로 구분돼 나오며, 리눅스 기본값은 세 번째(SEMOPM)가 32라 19c 권장값 100보다 낮음
#일시 변경과 영구 변경
sysctl -w kernel.sem="250 32000 200 128"
sysctl kernel.sem
cp -p /etc/sysctl.conf /etc/sysctl.conf.bak_$(date +%Y%m%d)
vi /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
sysctl kernel.sem
diff /etc/sysctl.conf.bak_$(date +%Y%m%d) /etc/sysctl.conf결과 해석:
실습 기록: -w로 SEMOPM을 100에서 200으로 바로 바꾸고, /etc/sysctl.conf에도 같은 값을 적어 sysctl -p로 적용한 뒤 diff에 kernel.sem 한 줄만 바뀐 것을 확인함
kernel.sem은 네 값이 한 항목이라 하나만 바꿀 때도 네 값을 모두 적음
-w만 하면 재부팅 뒤 사라지고(파일 누락), 파일만 고치면 아직 적용되지 않은 상태(적용 누락)가 됨
먼저 -w로 효과를 본 뒤 같은 값을 파일에 기록하는 순서를 씀
수정 전 백업은 cp -p로 권한, 소유자, 시각을 보존하고 날짜를 붙여, 여러 번 고칠 때 되돌릴 시점을 고를 수 있게 함
#설정 파일, 적용 순서, 검증
ls -l /etc/sysctl.d/
cat /etc/sysctl.d/<oracle 설정 파일>.conf
sysctl -p /etc/sysctl.d/<oracle 설정 파일>.conf
sysctl --system
grep -R "kernel.sem" /etc/sysctl.conf /etc/sysctl.d 2>/dev/null
sysctl fs.file-max결과 해석:
Oracle 값은 운영 설정과 섞이지 않게 /etc/sysctl.d/ 아래 별도 파일로 두면, 실습이 끝났을 때 그 파일만 정리하면 됨
sysctl -p만 쓰면 /etc/sysctl.conf만 적용하므로 sysctl.d 아래 파일은 경로를 붙여 적용함
sysctl --system은 /usr/lib/sysctl.d, /etc/sysctl.d, /etc/sysctl.conf를 부팅 때와 같은 순서로 전부 다시 적용하고, 적용 순서를 출력함
같은 파라미터가 여러 파일에 있으면 나중에 적용된 값이 남음
실습 서버의 /etc/sysctl.d/99-sysctl.conf는 ../sysctl.conf를 가리키는 심볼릭 링크였고, preinstall이 만든 파일은 99-oracle-database-preinstall-19c-sysctl.conf였음
파일 이름은 OS, 패키지 버전마다 다르므로 ls와 grep -R로 실제 위치를 찾음
파일에 적은 값과 sysctl 조회 값이 다르면 미적용, 더 나중 파일의 덮어쓰기, 이름 오타 중 하나임
#이름 오타 찾기
echo 'kernel.shm_max_typo = 4398046511104' > /tmp/broken.conf
sysctl -p /tmp/broken.conf결과 해석:
실습 기록: cannot stat /proc/sys/kernel/shm_max_typo: No such file or directory
오류에 나온 /proc/sys 경로를 점 이름으로 되돌리면 어느 줄이 틀렸는지 알 수 있음(정상 이름은 kernel.shmmax)
같은 방식으로 tcp_syncookie 오류는 끝의 s가 빠진 net.ipv4.tcp_syncookies의 오타임
#세마포어 부족 증상
| 부족한 값 | 실패하는 호출 | alert 로그 |
|---|---|---|
| SEMMNS, SEMMNI | semget |
ORA-27154, ORA-27300 ... status: 28, ORA-27301 No space left on device |
| SEMOPM | semop |
ORA-27300 ... status: 7, ORA-27301 Argument list too long |
| SEMMSL | semget |
ORA-27300 ... status: 22, ORA-27301 Invalid argument |
No space left on device는 디스크가 아니라 세마포어 자리가 없다는 뜻이라 df로 디스크를 보는 것은 헛걸음임
인스턴스는 대략 PROCESSES + 10개의 세마포어를 쓰고, 한 집합에 SEMMSL개까지 들어가므로 필요한 집합 수는 PROCESSES ÷ SEMMSL을 올림한 값임
SEMMSL 250이 "프로세스 250개까지만"이라는 뜻은 아님
실습은 alter system set processes=500 scope=spfile 뒤 재기동해 프로세스 수를 늘리는 과제도 함께 함
#ulimit 조회와 현재 세션 변경
ulimit -a
ulimit -Sn
ulimit -Hn
ulimit -Su
ulimit -Hu
ulimit -Ss
ls /proc/$$/fd | wc -l
cat /proc/$$/limits | grep -i 'open files'
ps -u oracle --no-headers | wc -lulimit -n 4096
ulimit -u 16384
ulimit -u 1666666결과 해석:
ulimit -a의 open files (-n)이 nofile, max user processes (-u)가 nproc, stack size (-s)가 스택이며 기본으로 soft 값을 보여 줌
soft는 지금 적용 중인 값, hard는 soft를 올릴 수 있는 상한이며, 일반 사용자는 hard를 넘겨 올릴 수 없음
실습 기록: hard 16384를 넘겨 ulimit -u 1666666을 하자 cannot modify limit: 명령을 허용하지 않음
nofile이 부족하면 Too many open files, nproc이 부족하면 fork: Resource temporarily unavailable이 나며, 소켓, 파이프도 파일 디스크립터로 셈
$$는 현재 셸의 PID이고, ps -u oracle | wc -l에는 머리글 한 줄이 섞이므로 --no-headers를 붙임
ulimit으로 바꾼 값은 현재 셸과 그 자식에만 적용되고 다시 로그인하면 돌아감
#limits 파일과 새 세션, DB 프로세스 확인
oracle soft nofile 1024
oracle hard nofile 65536
oracle soft nproc 16384
oracle hard nproc 16384
oracle soft stack 10240
oracle hard stack 32768
oracle hard memlock 134217728
oracle soft memlock 134217728ls -l /etc/security/limits.d/
cat /etc/security/limits.d/20-nproc.conf
su - oracle -c 'ulimit -Hn; ulimit -Su; ulimit -Ss'pgrep -f ora_pmon
cat /proc/<PMON_PID>/limits | egrep 'open files|Max processes|stack'결과 해석:
형식은 대상 soft/hard 항목 값이며 PAM의 pam_limits.so가 로그인 때 읽음
OL 7 기본 20-nproc.conf의 * soft nproc 4096은 모든 사용자에 적용되므로, oracle을 따로 적지 않으면 nproc이 4096에 묶임
limits.d는 이름순으로 읽혀 마지막 파일이 이김
실습은 zz-oracle-lab.conf를 만들어 preinstall 파일보다 나중에 읽히게 했으며, 여러 파일이 있으면 새 세션의 ulimit으로 최종값을 확인함
반드시 su - oracle처럼 하이픈을 붙인 새 로그인 세션에서 확인함
실습 기록: 셸은 nofile soft 1024, hard 65536인데 PMON의 limits는 Max open files 65536 65536, Max processes 16384, Max stack size 33554432
셸과 DB 프로세스의 값은 따로 보며, limits를 바꾼 뒤에는 DB를 다시 기동해야 프로세스에 반영됨
#사용 조건과 주의사항
커널 파라미터와 limits 변경은 서버 전체와 이후 세션에 영향을 주므로 변경 전 백업과 원복 방법을 정함
권장값은 Oracle 버전, OS, 메모리 크기에 따라 다르므로 설치 문서와 preinstall이 넣은 값을 기준으로 검증함
설치 실패나 접속 오류가 나면 오류 메시지와 해당 프로세스의 실제 한도를 함께 확인함