On-premise에서 Cloud를 운영하는 SE로서 실무에서 발생한 문제를 해결하기 위해 전전긍긍하던 중 아주 유용한 책을 발견하여 공부하고 정리하기 위해 포스팅을 하게 되었습니다. 좋은 책을 써주신 저자님께 감사드립니다. :)
http://www.yes24.com/Product/Goods/44376723
DevOps와 SE를 위한 리눅스 커널 이야기 - YES24
커널은 오랜 세월 기능이 추가되고 개선되어 오면서 완벽하게 이해하기 힘들 정도로 방대해졌다. 하지만 변하지 않는 기본 기능들이 있다. 이런 근간이 되는 기능에 대한 이해를 바탕으로 시스
www.yes24.com
- top 명령어와 프로세스
top 명령어를 통해 시스템의 전반적인 통계 뿐만아니라 각 프로세스의 상태와 스케줄링 우선순위, 메모리와 CPU 등의 시 스템 자원 사용 현황을 알 수 있습니다.
# top -b -n1
top - 15:26:42 up 224 days, 3:21, 43 users, load average: 25.42, 22.36, 21.03
Tasks: 1504 total, 2 running, 1501 sleeping, 1 stopped, 0 zombie
%Cpu(s): 15.3 us, 3.9 sy, 0.0 ni, 79.5 id, 1.1 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem : 386610.1+total, 256523.7+free, 14854.89+used, 115231.4+buff/cache
MiB Swap: 0.000 total, 0.000 free, 0.000 used. 369960.1+avail Mem
### Priority ↰ ↱ PR을 얼마나 조절할 것인가
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
### ↳ 프로세스 상태
67489 admin 20 0 830296 97648 29356 S 505.3 0.025 0:01.58 kubectl
68495 admin 20 0 758228 48408 29868 S 84.21 0.012 0:00.16 kubectl
68500 admin 20 0 757716 47328 29228 S 84.21 0.012 0:00.16 kubectl
47956 root 15 -5 3155896 1.900g 79612 S 57.89 0.503 86984:03 kube-apiserver
60665 root 15 -5 10.103g 628336 392120 S 21.05 0.159 33872:09 etcd
68196 root 20 0 44632 5716 3476 R 15.79 0.001 0:00.05 top
3293 root 20 0 4700552 24012 5052 S 10.53 0.006 14394:15 haproxy
3028 openvsw+ 10 -10 5560676 198672 15764 S 5.263 0.050 8884:47 ovs-vswitchd
5277 root 20 0 910656 181164 37740 S 5.263 0.046 1821:42 kube-scheduler
...
- PR (Priority)
: 프로세스의 CPU 스케쥴링 우선순위입니다. 기본적으로 모든 프로세스는 20의 PR을 가집니다.
- NR (Nice Value)
: 'nice' 명령어로 PR에 가중치를 줄 수 있다. 값이 음수이면 프로세스의 우선순위를 높이고, 반대로 양수이면 우선순위를 낮춥니다. PR이 20이고 NI가 -10이라면, PR은 10이되어 더 자주 실행됩니다.
ex) 'nice -n 10 <command>'와 같은 명령어로 실행시킬 프로세스의 NI 값을 조정할 수 있습니다.
* 프로세스 스케줄링와 우선순위
![](https://blog.kakaocdn.net/dn/SQtjJ/btr93kt16jB/zOHesNoRuYKtRIQbxHgVo1/img.png)
CPU는 한 번에 하나의 Task를 처리할 수 있습니다. 시스템에서 어떤 어플리케이션이 구동되기 위해서 다양한 프로세스들이 동작하는데, 각 프로세스들은 연산 처리를 위해 CPU를 두고 우선순위에 따라 서로 경합합니다.
CPU 마다 존재하는 Run Queue가 우선순위에 따라 적합한 Task를 연결하여 큐에 저장합니다. 그리고 스케줄러가 큐에서 우선순위가 가장 높은 프로세스를 디스패처로 넘겨줍니다. 마지막으로 디스패처는 현재 실행중인 프로세스의 정보(Context)를 메모리에 저장하고, 넘겨 받은 프로세스를 CPU에 연산하도록 요청합니다.
* RT(Real Time) Scheduler
프로세스 중에 PR이 숫자가 아니라 'rt'인 프로세스가 있습니다. 커널 데몬과 같이 특정 시간 안에 종료되어야 하는 프로세스로 가상의 CPU 사용 시간을 기준으로 프로세스의 우선순위를 정하는 CFS(Completely Fair Scheduling) 보다 먼저 실행됩니다.
- 프로세스 상태
![](https://blog.kakaocdn.net/dn/J5zfn/btsaETCBkG7/JfaduTnDTJTddHYB6AV4qK/img.png)
- D = Uninterruptible Sleep
디스크나 네트워크 I/O의 대기 상태로, 디스크 읽기와 같은 동기적 요청에 대한 응답이 해당 프로세스 도착하기 전까지 다른 프로세스에게 CPU의 사용권한을 양도합니다.
D 상태의 프로세스가 많다는 것은 요청이 끝나길 기다리는 프로세스가 많다는 의미로 시스템의 부하 계산에 포함됩니다.
- R = Running
CPU 자원을 소모하여 실행되고 있는 프로세스를 의마합니다.
- S = Sleeping
sleep() 함수와 같이 타이머가 작동하거나 콘솔 입력을 대기하는 상태합니다. (Interrubtible Sleep)
- T = Traced or stopped
strace 등으로 프로세스의 시스템 콜을 추적하고 있는 상태입니다.
![](https://blog.kakaocdn.net/dn/bbMxoc/btsaERLxZn4/h9iBAVwECaf2xUPSrbjKk0/img.png)
- Z = Zombie
부모 프로세스가 종료되었음에도 종료되지 않은 자식 프로세스로 메모리나 CPU를 소모하지 않지만 PID를 점유합니다. 시스템에서 생성할 수 있는 PID의 개수는 커널 변수에 정의되어 있으며, 좀비 프로세스가 아주 많이 늘어나게 된다면 PID가 고갈될 수 있습니다.
# 생성 가능한 최대 PID 개수
# sysctl -a | grep pid_max
kernel.pid_max = 81920
프로세스가 사용하고 있는 메모리와 관련된 값은 VIRT, RES, SHR 3가지가 있습니다.
- VIRT (Virtual Memory Size)
: Task가 사용하고 있는 가상 메모리의 총량으로 프로세스가 커널로부터 사용을 예약받은 메모리를 의미합니다. (KiB)
VIRT 영역의 상한은 'vm.overcommit_memory'라는 커널 파라미터에 의해 결정됩니다.
# sysctl -a | grep 'vm.overcommit_memory'
vm.overcommit_memory = 0
### 0 : Page Cache + Swap + Slab Reclaimable의 값이 요청받은 메모리 수보다 클 경우 Commit (default)
### 1 : 항상 commit
### 2 : vm.overcommit_ratio와 swap 크기를 기준으로 제한적인 commit
![](https://blog.kakaocdn.net/dn/dXxl38/btr9QU4WQl4/f3kWRlGwjDc8TCzu6bROxk/img.png)
* Memory Commit
![](https://blog.kakaocdn.net/dn/ZogVk/btsar6Q1amp/3jyeYCMfkdDHZ8tTD9IlpK/img.png)
프로세스가 커널로 메모리 할당을 요청할 때, 물리 메모리를 바로 할당하는 것이 아니라 가상 메모리의 주소만 전달해 준 뒤 해당 메모리 영역을 어떤 프로세스에게 주었다는 정보만 저장하는 과정입니다.
프로세스는 메모리가 필요할 때 malloc() 같은 시스템 콜로 메모리 할당을 요청합니다. 가용 메모리가 있다면 커널은 가상 메모리 주소를 넘겨줍니다. 그 후 프로세스가 할당받은 메모리 영역에 실제 쓰기 작업을 시작해서 Page Fault가 발생하면, 커널은 전역 변수로 관리되는 Page Table에 물리 메모리와 가상 메모리를 매핑합니다.
아래의 sar 통계를 확인해보면 프로세스들은 할당받은 가상 메모리의 10~11% 정도만 물리 메모리와 매핑해서 사용하고 있습니다.
# sar -r
### vvv
00:00:01 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
00:10:01 262381860 378624416 14605364 3.69 1060416 104654736 43700760 11.04 56514860 61447644 3580
00:20:01 262140564 378451400 14777140 3.73 1060416 104723104 43941116 11.10 56677476 61515980 5220
00:30:01 262355760 378630544 14601156 3.69 1060416 104687060 43499252 10.99 56505024 61479368 3784
...
top 명령어의 결과에서도 ovs 프로세스의 RES가 약 200 MB인 반면 VIRT는 약 5.5GB 정도로 RES보다 훨씬 많은 VIRT 를 할당받고 있습니다.
# top -b -n 1
### VIRT RES
3028 openvsw+ 10 -10 5560676 198672 15764 S 5.263 0.050 8884:47 ovs-vswitchd
이렇게 물리 메모리보다 가상 메모리를 크게 할당받아 overcommit 상태로 관리하는 이유는 순간적으로 많은 양을 필요로 하는 작업이 있을 수 있기 때문입니다. 대표적인 경우로 fork()와 같이 새로운 프로세스 생성이 있습니다. fork()를 사용하면 현재 실행 중인 프로세스와 똑같은 자식 프로세스를 만들게 됩니다. 이 때 자식 프로세스는 부모 프로세스의 주소 공간을 그대로 복사해오며, 그 과정에서 아래 그림처럼 메모리 overcommit이 발생하게 됩니다.
![](https://blog.kakaocdn.net/dn/RA9yU/btsaTeT3Xaw/LmbrhMhCJcKmOANxSIiZCk/img.png)
그러나 대부분 fork() → exec() 콜을 통해 새로운 작업으로 넘어가는 경우가 많기때문에 복사해 온 공간을 그대로 사용하는 경우는 매우 드물게 발생합니다. 그리고 부모 프로세스와 복제된 자식 프로세스가 메모리의 같은 페이지를 참조하다가 부모나 자식 어느쪽이든 쓰기 작업이 발생했을 때 메모리를 복제하여 실제 할당을 하게 됩니다.
Reference
https://brunch.co.kr/@alden/16
vm.overcommit에 대한 짧은 이야기
Linux Kernel Internal | 이번 글에서는 vm.overcommit에 대해서 다뤄볼까 합니다. 막연하게 메모리를 많이 쓸 수 있게 해주는 거 아니야?라고 생각 해왔었는데요, 살펴보니 조금 다른 의미였습니다. 그
brunch.co.kr
https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html
Operating Systems: Virtual Memory
Figure 9.13 - Page-fault curve for FIFO replacement on a reference string. There are a number of page-buffering algorithms that can be used in conjunction with the afore-mentioned algorithms, to improve overall performance and sometimes make up for inheren
www.cs.uic.edu
https://nesoy.github.io/articles/2018-11/Context-Switching
Context Switching이란?
nesoy.github.io
'System Engineering > Linux' 카테고리의 다른 글
[커널이야기] 리눅스 메모리 1 - 메모리를 확인하는 방법과 slab/swap 메모리 (2) | 2023.06.15 |
---|---|
[커널이야기] Load Average로 시스템 콜 추적하기 (0) | 2023.06.09 |
폐쇄망 환경에서 휴대폰 테더링으로 yum/apt 사용하기 (0) | 2023.04.20 |
[커널이야기] Linux 시스템의 구성 정보 확인하기 - BIOS / CPU / NUMA / NIC / DISK (0) | 2023.04.11 |
Rhel7.7/KVM에 PCI-Passthrough/SR-IOV 설정하기 (0) | 2021.02.19 |