Linux 커널 심화 시리즈 전체 목차 | 프로덕션 튜닝과 트러블슈팅
이 글의 핵심
Linux 커널 심화 시리즈 전체 목차: 파일시스템, 프로세스, 메모리, 디스크 관리 4개 고급 주제로 프로덕션 전문가 되기.
시리즈 소개
Linux 커널 심화 시리즈는 운영체제 안쪽을 파고드는 글 모음이다. 이 페이지는 교과서식 커리큘럼이 아니라, 나중에 다시 찾기 쉽도록 정리해 둔 개인용 안내에 가깝다. 주제는 파일시스템, 프로세스 스케줄링, 가상 메모리, 블록·디스크 I/O 네 가지다. 프로덕션에서 자주 마주치는 “디스크는 남는데 쓰기가 막힌다”, “CPU는 한가한데 응답이 느리다”, “갑자기 OOM으로 죽는다” 같은 상황을 커널 관점에서 해석하는 데 쓰면 된다.
한 번에 다 이해하려 하기보다 스토리지 → CPU 스케줄 → 메모리 → I/O 순서로 층을 쌓는 편이 낫다. 네트워크, 보안, 자동화는 그다음에 같은 사고 틀에 끼워 넣으면 된다.
SRE·DevOps나 백엔드·인프라 업무를 한다면 perf, bpftrace, sysctl, cgroup으로 가설을 좁혀 가는 연습이 본문 내용과 잘 맞물린다.
이 시리즈가 잘 맞는 경우
- 프로덕션 Linux의 장애와 성능이 곧바로 업무 성과로 이어지는 역할
- 애플리케이션은 다루지만 VFS나 메모리 회수 쪽 지식이 비어 있다고 느낄 때
- cgroup, NUMA, 페이지 폴트라는 용어는 알지만 그것들이 어떻게 연결되는지 설명하기 어려울 때
덜 맞는 경우
grep,ssh,systemctl이 아직 어색하다면 셸, 권한, 패키지 관리부터 손에 익히는 게 낫다.- LKM이나 드라이버 작성이 목표라면 이 시리즈는 동작 이해와 운영에 초점을 두고 있으니 개발 학습 경로를 따로 잡는 게 맞다.
처음 서버를 터뜨렸을 때
초보 시절 일이다. 테스트 서버였지만 “백업은 당연히 있겠지” 정도로만 생각하고 있었다. 디스크가 빠듯한 상태에서 find 결과를 rm으로 파이프해 한 번에 지워 버렸는데, 권한과 경로, 대상 디렉터리를 끝까지 확인하지 않은 채였다. 잠시 뒤 서비스가 조용해졌고, 그제야 journalctl이 아니라 텅 빈 디렉터리를 들여다보고 있었다. 복구는 다른 사람이 해 둔 백업 덕분에 조용히 끝났다. 실력이 아니라 운이었다.
그때 남은 것은 튜닝 팁이 아니라 습관이었다. 무언가를 바꾸기 전에 가정을 세우고, 한 번 더 읽어 보고, 되돌릴 수 있는지 확인한다. 대량 I/O, 대량 삭제, inode에 영향을 주는 작업은 가볍게 다루지 않는다. 그 뒤로 systemctl, cgroup, df -i 출력을 꼼꼼히 읽게 된 것도 멋을 내려는 게 아니라 그때 같은 실수를 반복하지 않으려는 쪽에 가깝다.
이 시리즈를 읽는 사람에게도 딱 맞는 도구 하나를 외우는 것보다 “왜 터지는지”를 커널·블록·메모리의 언어로 설명하는 연습이 더 오래 남는다고 본다.
systemd에 대한 입장
systemd 논쟁은 이제 그만 보고 싶다. “init 철학”을 두고 밤새 싸우기보다 systemctl, 유닛 파일, journalctl, Restart= 정책을 운영에서 끝까지 활용하는 편이 낫다. sysvinit이 그립다면 그런 환경에서 쓰면 되고, 실제로는 조직 정책상 systemd가 표준인 곳이 대부분이다. 이 인덱스는 진영 논리가 아니라 장애 때 로그, 타임스탬프, 의존성 정보가 실제로 도움이 되느냐를 기준으로 본다.
시리즈 본문 목차
파일시스템(고급)
#03 파일·inode 내부
본문 기준으로 30분 안팎이 걸리는 고급 편이다. ext4·XFS의 온디스크 inode, extent, VFS, 하드 링크, 블록 주소를 다룬다.
ext4와 XFS의 inode가 실제로 데이터 블록과 어떻게 연결되는지, extent가 예전의 직접·간접 블록 방식과 무엇이 다른지, df와 df -i로 용량 부족과 inode 부족을 구분하는 방법을 설명한다. “디스크는 남는데 파일이 안 만들어진다”는 현상을 inode, 디렉터리, extent로 설명할 수 있으면 이 편의 목적은 달성한 셈이다. 미리 POSIX 파일 모델, stat, ls -i, 하드 링크와 심볼릭 링크의 차이 정도를 알고 있으면 읽기 편하다.
프로세스(고급)
#05 프로세스·스케줄러
30분 안팎의 고급 편이다. task_struct, CFS, vruntime, 런큐, NUMA, cgroup CPU 제어를 다룬다.
커널이 프로세스와 스레드를 어떤 구조로 관리하는지, CFS의 vruntime이 공정성과 지연 사이에서 어떤 트레이드오프를 만드는지, NUMA와 CPU 친화성, cgroup으로 CPU 쿼터를 걸었을 때 throttling이 지표에 어떻게 나타나는지를 설명한다. top의 load average가 높을 때 그것이 I/O wait인지, CPU 병목인지, cgroup 제한 때문인지 구분해 말할 수 있으면 충분하다. ps, nice, chrt, taskset의 대략적인 쓰임과, Kubernetes의 requests/limits가 결국 cgroup 설정으로 내려간다는 점 정도만 알고 있어도 된다.
메모리(고급)
#06 메모리·가상 메모리
30분 안팎의 고급 편이다. MMU, 다단계 페이지 테이블, TLB, 페이지 폴트, ZONE, SLUB, kswapd, OOM, THP, swappiness를 다룬다.
MMU와 페이지 테이블, TLB가 성능과 격리 양쪽에 왜 필요한지, minor/major 페이지 폴트의 차이, COW가 fork와 컨테이너, 메모리 공유에서 갖는 의미, ZONE과 버디 할당자, SLUB, kswapd와 direct reclaim, OOM killer, 그리고 THP와 vm.swappiness 설정이 워크로드에 따라 득이 되기도 하고 해가 되기도 하는 이유를 설명한다. free -h와 /proc/meminfo로 페이지 캐시, anonymous 메모리, file-backed 메모리를 구분할 수 있으면 된다. 가상 주소와 물리 주소의 차이, mmap의 기본 개념, 컨테이너 메모리 제한이 어떻게 계산되는지 감을 잡고 있으면 도움이 된다.
디스크·블록(고급)
#09 디스크·블록 계층
30분 안팎의 고급 편이다. ext4/XFS 저널, blk-mq, I/O 스케줄러, iostat, blktrace를 다룬다.
정전 뒤 일관성을 보장하는 저널과 트랜잭션 복구, 블록 할당기와 단편화, blk-mq와 I/O 스케줄러(none, mq-deadline 등)가 지연과 처리량에 미치는 영향, iostat과 blktrace로 큐와 지연을 읽는 방법을 설명한다. iostat -x의 %util이나 await 값만 보고 “디스크가 나쁘다”고 단정할 수 없다는 점까지 이해하면 된다. 특히 %util은 요청을 병렬로 처리하는 SSD·NVMe에서는 100%에 가까워도 여유가 남아 있을 수 있다. lsblk의 ROTA 컬럼, NVMe와 SATA의 차이 정도를 알고 있으면 좋다.
주제별 색인
시리즈 본문은 파일·inode, 프로세스, 메모리, 디스크 네 편으로 정리되어 있다. 아래는 IPC, TCP, systemd, SELinux 같은 주제를 이 네 축 중 어디에 붙여 읽으면 좋은지 메모 삼아 분류한 것이다.
기초: 파일·프로세스
- VFS, inode, 경로 탐색 → #03과 OS 개론의 dentry 설명
- 스케줄과 스레드 → #05와 사용자 공간의
clone/pthread(라이브러리마다 다름) - 셸 스크립트와 자동화는 별도 축이다. 아래 도구 가이드를 참고한다.
시스템 프로그래밍: 메모리·IPC·시그널
- 가상 메모리와 COW → #06
- 파이프, 소켓, 공유 메모리 → 파일 디스크립터, 복사 비용, 블로킹 동작과 연결된다. 본문은 메모리 압박과
mmap쪽을 더 자세히 다룬다. - 시그널 → #05의 프로세스 상태 설명과 함께 읽는다.
네트워크
TCP는 블록 I/O와 지연이 발생하는 방식이 다르다. ss, tcpdump, conntrack, bpftrace를 주로 쓰게 된다. 프로세스가 언제 잠들고 깨어나는지는 #05, #06과 겹쳐 읽으면 이해가 쉽다.
성능
- CPU →
perf, flame graph, CFS와 throttling은 #05 - 메모리 →
vmstat, OOM, cgroup 메모리 제한, THP는 #06 - 디스크 →
iostat,pidstat -d는 #09 - eBPF → 고정 지표만으로 원인이 안 보일 때
bpftrace를 쓴다.
보안
- DAC, capabilities, namespace는 “프로세스가 무엇을 열 수 있는가”의 문제다.
- SELinux와 AppArmor는 어떤 라벨의 주체가 어떤 타입의 객체에 접근할 수 있는지를 정책으로 정한다. 거부 로그는
audit쪽에 남는다. - KASLR이나 SMEP 같은 보호 기법은 #06의 주소 공간 설명을 알고 있으면 왜 그 경계가 중요한지 이해하기 쉽다. 이 시리즈가 보안 전문 시리즈는 아니다.
운영
- 배포,
systemd, 컨테이너 이미지 레이어 문제는 결국 I/O, inode, cgroup으로 귀결된다. - 지연 문제는 먼저 CPU, 메모리, 디스크, 네트워크, 락 중 어디에서 오는지 나눈 뒤 해당 본문을 연다.
읽는 순서
초급·중급·고급을 따로 표로 나누지는 않는다. 첫 바퀴는 보통 #03 → #05 → #06 → #09 순서다. 저장 구조(#03)에서 시작해 실행과 스케줄(#05), 주소 공간과 메모리 회수(#06), 블록 I/O 경로(#09)로 넘어간다. 두 번째 바퀴는 장애 유형별로 섞어 읽는다. OOM이면 #06과 cgroup, I/O wait가 잦으면 #09, load는 높은데 CPU 사용률이 낮으면 I/O나 락, throttling(#05) 쪽을 본다.
시스템 프로그래밍으로 더 깊이 들어가고 싶다면 C의 open/mmap/epoll을 errno 처리와 부분 쓰기(partial write)까지 다뤄 보는 것이 좋다. Go나 Rust를 쓴다면 시스템 콜과 뮤텍스의 비용 이야기가 #05와 연결된다. strace로 시스템 콜을 관찰하면서 read가 언제 블로킹되는지 직접 확인해 보는 식으로 읽으면 된다.
같은 주제는 관련 시리즈의 C, Go, Rust 인덱스와 함께 봐도 좋다.
시리즈 전반의 관점
task_struct,mm_struct같은 커널 자료구조가/proc같은 인터페이스에 어떤 형태로 드러나는지 연결한다.- inode 부족,
%util해석, OOM, throttling처럼 장애 티켓에서 반복해서 나오는 질문에 맥락을 붙인다. sysctl, cgroup, THP, 스케줄러, I/O 큐 설정의 효과는 워크로드에 따라 다르다는 점을 반복해서 강조한다.- x86과 ARM, 컨테이너 오버헤드처럼 같은 설정도 하드웨어에 따라 다르게 보일 수 있다는 점을 전제로 한다.
증상별로 떠올리는 갈래
디스크 사용률은 30%인데 작은 파일이 안 만들어진다
inode와 dentry, 블록 할당기와 마운트 옵션, 쿼터를 의심한다. 컨테이너라면 overlay 파일시스템에서 df 결과가 호스트와 다르게 보일 수 있다는 점도 고려한다. df -h, df -i, 환경에 따라 tune2fs나 xfs_info를 확인하고, 파일 디스크립터 누수가 의심되면 lsof를 본다. #03에서 다룬다.
API 지연이 튀는데 CPU 사용률은 낮다
디스크 I/O(iostat, pidstat, #09), 메모리 압박(vmstat, dmesg, #06), cgroup CPU throttling(#05)을 차례로 확인한다. 락 경합이나 확장성 문제라면 사용자 공간 프로파일링과 perf의 off-CPU 분석이 필요하다.
빌드나 배치 작업 후 OOM이 난다
dmesg에서 Killed process 메시지와 OOM score, cgroup 메모리 제한, THP와 스왑 설정을 본다. drop_caches는 튜닝 수단이 아니라 잠깐 실험할 때나 쓰는 것이고, 운영 환경에서 상시로 쓰면 안 된다.
DB 디스크 지연이 기준을 넘는다
NVMe와 blk-mq 환경에서 none과 mq-deadline 같은 스케줄러 선택, 저널 모드에 따른 내구성과 성능의 트레이드오프, 가상화 환경의 I/O stall이나 IOPS 상한을 함께 본다. iostat 수치만으로 “디스크가 나쁘다”고 결론 내릴 수 없다.
편별로 자주 쓰는 명령
옵션은 배포판과 권한에 따라 다르다. 자세한 해석은 각 본문에서 다룬다.
#03 파일·inode
df -hT
df -i
stat /path/to/file
ls -li
# tune2fs -l /dev/sdXN
# xfs_info /mount/point
#05 프로세스·스케줄러
ps auxf
ps -L -o pid,tid,psr,comm
taskset -pc <pid>
mpstat -P ALL 1
# find /sys/fs/cgroup -maxdepth 2 -type f -name cpu.stat
#06 메모리
free -h
vmstat 1
dmesg -T | egrep -i "oom|oom-kill|out of memory|reclaim" || true
head -n 40 /proc/meminfo
sysctl vm.swappiness
#09 디스크·블록
lsblk -o NAME,ROTA,TYPE,SIZE,FSTYPE,MOUNTPOINT
iostat -xz 1
pidstat -d 1 -p <pid>
# blktrace — 테스트·정책 맞을 때만
도구 가이드(bash, vim, systemd, docker)
bash(또는 POSIX 셸)
파이프, 리다이렉트, set -euo pipefail을 제대로 이해해야 한다. 운영 사고의 상당수는 실패를 조용히 삼킨 스크립트에서 시작된다. find와 xargs로 대량 삭제를 자동화하기 전에 -print0/-0 조합과 공백·특수문자 처리부터 익혀야 한다. set -x와 PS4를 쓰면 스크립트 실행 과정을 재현 가능한 형태로 남길 수 있다.
vim(또는 표준 편집기)
서버에는 GUI가 없는 경우가 많다. 권한이 필요한 파일은 sudoedit로 편집하면 편집기 자체를 root로 실행하는 실수를 줄일 수 있다.
systemd
systemctl, journalctl, Restart=, LimitNOFILE처럼 유닛 단위로 파일 디스크립터와 리소스 제한이 걸린다는 점을 알아야 한다. 장애 때는 systemctl status의 Tasks 수, coredump, OOM 기록을 보고 유닛 설정과 커널 로그를 함께 확인한다. 앞의 systemd에 대한 입장에서 말했듯, 논쟁보다 로그가 실제로 도움이 되는지가 중요하다.
docker(OCI)
이미지 레이어, overlay2, 빌드 캐시는 inode와 용량 문제로 이어진다(#03, #09). memory/cpu limit도 결국 cgroup 설정이며, 값의 정확한 의미는 cgroup v1/v2와 컨테이너 런타임에 따라 달라진다.
역할별 관점
DevOps나 SRE라면 SLO를 깨는 지연이 CPU, 메모리, 디스크, 네트워크, 락 중 어디에서 오는지 찾는 것이 첫 번째 일이다. 릴리스로 시스템 콜 패턴이나 힙 사용량, 스레드 수가 바뀌면 같은 하드웨어에서도 병목 위치가 달라진다. 메트릭으로 범위를 좁히고, 필요하면 eBPF로 한 번 더 들여다본다.
시스템 관리자라면 RAID, LVM, 스냅샷, 백업이 #03과 #09 내용과 직접 맞닿는다. sudo, audit, SELinux로 인한 접근 거부는 애플리케이션 버그가 아니라 정책과 라벨 문제로 판명되는 경우가 많다. 커널 업데이트 채널, 재부팅 주기, livepatch 적용 여부는 조직 정책에 따라 정해진다.
학습 일정
주차별 과제를 표로 정해 두지는 않는다. 시간이 날 때 한 편을 읽고, df -i나 dmesg 같은 명령 하나라도 직접 손에 익히면 된다. 여유가 있다면 8주 정도로 늘려서 #03과 셸, #05와 C·Go, #06과 perf, #09와 bpftrace처럼 본문과 도구를 짝지어 한 번씩 실습해 본다. 목표는 전부 읽는 것이 아니라, 직접 재현해 본 병목 하나에 대해 가설과 완화 방법을 메모로 남기는 것이다.
FAQ
이 시리즈는 누구에게 맞나요?
SRE, DevOps, 백엔드·인프라, 시스템 분야에 관심 있는 사람에게 맞다. 프로덕션의 장애와 성능이 핵심 지표인 업무라면 더 쓸모가 있다.
선수 지식이 필요한가요?
C의 포인터와 구조체 개념, 기본 Linux 명령, OS 개론 정도를 알면 덜 헤맨다. 셸 사용과 /proc 읽는 법만 먼저 익혀도 체감 차이가 크다.
실무에 바로 쓸 수 있나요?
df -i, vmstat, iostat 같은 현장 도구를 sysctl, cgroup 설정의 맥락과 함께 다루므로 바로 쓸 수 있는 내용이 많다. 다만 한 번에 해결하는 튜닝 값은 워크로드에 따라 역효과를 내기 쉬우니, 적용 전에 측정하고 비교하는 습관을 들이는 것이 좋다.
커널 소스를 봐야 하나요?
필수는 아니다. 본문에서 구조체나 함수를 짚는 것은 이해를 돕기 위해서다. 직접 패치를 하려면 빌드와 테스트 과정을 따로 익혀야 한다.
네트워크, Kubernetes, 보안은 다루나요?
직접 깊이 다루는 축은 커널의 스토리지, 스케줄, 메모리다. Kubernetes는 cgroup, namespace, 네트워크, CSI를 통해 이 내용과 연결된다. 네트워크는 블록 I/O와 지연 특성이 달라서 위 주제별 색인의 네트워크 항목을 보조 자료로 쓰면 된다.
ARM(Graviton 같은) 서버에서도 똑같나요?
MMU, TLB, 스케줄러, blk-mq 같은 큰 틀은 비슷하다. 하지만 perf 이벤트, 캐시 구조, 드라이버는 다르므로 해당 머신에서 perf list와 문서로 확인해야 한다.
습관 하나만 고르라면?
튜닝, 삭제, 대량 I/O 작업 전에는 가정을 세우고, 다시 검토하고, 가능하면 롤백 방법을 준비한다. 기록 없이 시도한 변경이 사고의 원인이 되는 경우가 많다.
관련 시리즈
참고 자료
책
- 리눅스 커널 내부구조 — 국내서, 개론에서 중급 수준
- Understanding the Linux Kernel — 영어, 오래된 커널 버전 기준이지만 개념 지도를 잡는 데 쓸 만하다
온라인
- Linux Kernel Documentation — 공식 문서
- Brendan Gregg’s Blog — 성능 분석과 관측
도구
파일·inode (#03)에서 메타데이터와 저장 구조를 먼저 잡고, #05, #06, #09로 넘어가며 깊이를 더하면 된다.
부록: 자주 쓰는 짧은 명령
- 파일시스템:
df -hT,df -i,du --max-depth=1, 환경에 따라tune2fs,xfs_info - CPU·프로세스:
uptime,mpstat,pidstat,ps -L - 메모리:
free -h,vmstat 1,dmesg -T - 디스크:
iostat -xz 1,pidstat -d, 고급 분석은blktrace - 시스템 콜·프로파일링:
strace -f -c -p <pid>, 권한이 있으면perf
이 목록만으로도 장애 초반에 어느 축부터 볼지 정하는 데는 충분하다. 원인과 근거, 완화 방법은 위 본문과 증상별 갈래를 차례로 참고한다.