
커널(Kernel): 운영체제의 심장
운영체제라는게 사실 프로그램들의 집합이라면, 그 중에서도 가장 핵심이 되는 녀석은 누구일까요? 항상 메모리에 상주하는 커널의 정체.

운영체제라는게 사실 프로그램들의 집합이라면, 그 중에서도 가장 핵심이 되는 녀석은 누구일까요? 항상 메모리에 상주하는 커널의 정체.
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

매번 3-Way Handshake 하느라 지쳤나요? 한 번 맺은 인연(TCP 연결)을 소중히 유지하는 법. HTTP 최적화의 기본.

저도 처음엔 같은 말인 줄 알았습니다. 리눅스 서버를 처음 만졌을 때, "리눅스 커널 업데이트"라는 말이 따로 있더군요. 그럼 리눅스 OS 업데이트랑은 뭐가 다른 걸까요? 둘 다 리눅스인데?
이게 와닿지 않아서 하루 종일 삽질하다가, 문득 이렇게 이해했습니다.
비유하자면,
에어컨(유틸리티 프로그램)이 고장 나도 차는 굴러가지만, 엔진(커널)이 멈추면 차는 그냥 고철입니다. 컴퓨터가 켜져 있는 동안, 단 한순간도 쉬지 않고 메모리에 상주하는 핵심 프로그램, 그게 바로 커널입니다.
결국, 리눅스에서 "OS 업데이트"는 쉘, 파일 매니저, GUI 같은 주변 도구를 업데이트하는 것이고, "커널 업데이트"는 엔진 자체를 새 모델로 바꾸는 것이라고 받아들였습니다.
처음 서버 접속했을 때 "커널 버전이 뭐냐?"고 물어보는 사람이 있었습니다. 저는 당연히 몰랐죠. 어디서 확인하는 건데?
그냥 터미널에서 이렇게 하면 됩니다.
uname -r
# 출력 예시: 5.15.0-56-generic
이 숫자가 커널의 버전 번호입니다.
5: 메이저 버전15: 마이너 버전0-56-generic: 패치 레벨 + 배포판별 추가 정보macOS에서 해보니까 Darwin Kernel Version 23.3.0이라고 나오더군요.
macOS도 결국 Unix 기반이라 커널이 따로 있는 겁니다.
이걸 알고 나서는 서버 문서에 "Kernel Version: ..." 항목을 넣는 게 왜 필요한지 이해했습니다.
커널의 가장 중요한 임무는 "하드웨어 보호"입니다. 아무 프로그램이나 하드디스크에 막 접근해서 중요 문서를 지워버리면 안 되니까요.
받아들인 바로는, 커널은 이런 3가지 일을 합니다.
만약 이게 없다면? 프로그램끼리 메모리 싸움이 벌어지고, CPU는 하나의 프로그램이 독점하고, 하드웨어는 무질서하게 접근당할 겁니다. 커널은 경찰관 겸 중재자입니다.
처음 듣는 용어가 또 나왔습니다. "커널 공간(Kernel Space)"과 "유저 공간(User Space)".
이건 CPU가 메모리를 나누는 방식입니다.
예를 들어, 크롬 브라우저(Ring 3)가 파일을 읽고 싶으면, 커널(Ring 0)에게 부탁해야 합니다. 이 부탁하는 방법이 시스템 콜(System Call)입니다.
비유하자면,
이걸 이해하고 나니, "왜 프로그램이 직접 하드웨어를 못 건드리냐?"라는 질문의 답이 선명해졌습니다. CPU가 애초에 권한을 나눠놓은 겁니다.
예를 들어, Python에서 파일을 열 때 이렇게 씁니다.
file = open("data.txt", "r")
이 한 줄 뒤에서는 대략 이런 일이 벌어집니다.
open() 함수를 호출.fopen() 호출.fopen()은 다시 시스템 콜 open()을 호출. (Ring 3 → Ring 0으로 전환)시스템 콜은 유저 공간과 커널 공간을 이어주는 유일한 다리입니다.
리눅스에는 약 300개 이상의 시스템 콜이 있습니다: read(), write(), fork(), exec(), socket() 등등.
이게 결국 "프로그램은 커널 없이 아무것도 못한다"는 말의 의미였습니다.
커널을 어떻게 설계하느냐에 따라 크게 두 파벌로 나뉩니다.
철학: "다 귀찮다, 한 방에 넣자."
핵심 기능뿐만 아니라 디바이스 드라이버, 파일 시스템, 네트워크 스택까지 싹 다 커널 안에 집어넣음.
장점:
단점:
대표주자: 리눅스 (Linux), 전통적인 Unix.
처음엔 "왜 이렇게 불안정한 구조를 쓸까?"라고 생각했는데, 서버 환경에서는 속도가 생명이더군요. 그래서 모놀리식 구조가 압도적입니다.
철학: "핵심만 남기고 다 밖으로 빼!"
메모리 관리, 스케줄링, IPC(프로세스 간 통신) 같은 진짜 필수 기능만 커널에 남기고, 나머지(드라이버, 파일 시스템)는 일반 프로그램(유저 공간의 서버 프로세스)처럼 돌림.
장점:
단점:
대표주자: Mach (macOS의 기반), Minix, QNX.
저는 macOS를 쓰는데, "왜 macOS는 리눅스보다 안정적인 느낌이지?"라는 의문이 있었습니다. 마이크로 커널 기반(정확히는 하이브리드)이라는 걸 알고 나서 이해했습니다.
현대의 OS들은 순수 모놀리식도, 순수 마이크로도 아닙니다.
결국 "성능 vs 안정성"의 타협점을 찾은 겁니다.
리눅스를 만든 Linus Torvalds와 Minix(마이크로 커널)를 만든 Andrew Tanenbaum이 1992년에 Usenet에서 개싸움(?)을 벌였습니다.
Tanenbaum: "모놀리식 커널은 시대착오적이다. 마이크로 커널이 미래다." Torvalds: "마이크로 커널은 느리다. 실용성이 답이다."
결과는?
하지만 아이러니하게도, Tanenbaum의 아이디어는 macOS, QNX(자동차), Fuchsia(구글) 같은 곳에서 살아남았습니다. 결국 이거였습니다: 둘 다 맞다. 용도에 따라 다르다.
모놀리식 커널의 문제는 "덩치가 너무 크다"였습니다. 하지만 리눅스는 Loadable Kernel Module (LKM)이라는 기법으로 이걸 해결했습니다.
USB 드라이버, 그래픽 카드 드라이버 같은 건 필요할 때만 커널에 동적으로 끼워넣습니다.
lsmod # 현재 로드된 커널 모듈 목록 보기
출력 예시:
Module Size Used by
nvidia_drm 102400 5
nvidia_modeset 1245184 12 nvidia_drm
nvidia 56385536 573 nvidia_modeset
NVIDIA 그래픽 카드를 쓰면, nvidia 모듈이 자동으로 로드됩니다.
필요 없으면 언로드할 수도 있습니다.
sudo rmmod nvidia # 모듈 제거
sudo insmod nvidia.ko # 모듈 추가
처음엔 "커널 모듈을 잘못 건드리면 시스템이 뻗는다"는 말이 무서웠는데, 직접 해보니 정말 뻗더군요. 그 후로는 함부로 건드리지 않습니다.
리눅스에는 신기한 디렉토리가 하나 있습니다. /proc.
cat /proc/cpuinfo # CPU 정보
cat /proc/meminfo # 메모리 정보
cat /proc/version # 커널 버전
이 디렉토리는 실제 디스크에 존재하지 않습니다. 커널이 실시간으로 생성하는 가상 파일 시스템입니다.
예를 들어, CPU 정보를 보려면:
cat /proc/cpuinfo
출력:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 142
model name : Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
이걸 알고 나서는 서버 모니터링 스크립트에서 /proc/meminfo를 파싱해서 메모리 사용량을 체크하는 이유를 이해했습니다.
커널이 죽으면 컴퓨터가 멈춥니다. 왜냐하면 커널은 모든 걸 관리하니까요.
처음 서버에서 Kernel Panic을 봤을 때, 로그에 이런 게 찍혀 있었습니다.
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
대략 이런 의미였습니다: "루트 파일 시스템을 못 찾았어. 나 죽는다."
이 경험 이후로, "커널은 신"이라는 말을 받아들였습니다. 커널이 죽으면 그냥 끝입니다.
커널은 부팅할 때, 그리고 하드웨어가 연결될 때마다 뭔가를 로그로 남깁니다.
이걸 보는 명령어가 dmesg입니다.
dmesg | tail -20 # 최근 20줄 보기
출력 예시:
[ 1.234567] usb 1-1: New USB device found, idVendor=046d, idProduct=c52b
[ 1.234568] input: Logitech USB Receiver as /devices/pci0000:00/usb1/1-1/input0
[ 10.567890] EXT4-fs (sda1): mounted filesystem with ordered data mode
USB 마우스를 꽂으면 dmesg에 바로 뜹니다.
처음엔 이게 왜 필요한지 몰랐는데, 하드웨어 문제를 디버깅할 때 정말 유용하더군요.
Docker를 처음 쓸 때, "가상머신이랑 뭐가 다른가?"라는 질문이 있었습니다.
핵심 차이는 커널입니다.예를 들어, macOS에서 Linux Docker 컨테이너를 돌리면?
이게 와닿았던 순간이, "왜 Docker에서 uname -r을 치면 호스트 커널 버전이 나오지?"라는 의문을 풀었을 때였습니다.
# 호스트에서
uname -r
# 5.15.0-56-generic
# Docker 컨테이너 안에서
docker run -it ubuntu bash
uname -r
# 5.15.0-56-generic (똑같음!)
컨테이너는 커널을 공유하기 때문에 가볍고 빠릅니다. 하지만 보안 측면에서는 VM보다 약합니다. (커널을 뚫으면 호스트도 뚫림)
최근에 알게 된 신기술이 eBPF (extended Berkeley Packet Filter)입니다.
전통적으로 커널을 확장하려면 커널 모듈을 작성해야 했습니다. 하지만 커널 모듈은 위험합니다. 버그가 있으면 시스템 전체가 뻗으니까요.
eBPF는 커널 안에 안전한 샌드박스 프로그램을 삽입할 수 있게 해줍니다.
예를 들어:
# eBPF로 시스템 콜 추적하기 (bpftrace 사용)
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s opened %s\n", comm, str(args->filename)); }'
이걸 실행하면, 모든 프로그램이 어떤 파일을 여는지 실시간으로 볼 수 있습니다.
eBPF는 Kubernetes 네트워킹 (Cilium), 보안 도구 (Falco), 모니터링 (Pixie)에서 쓰입니다. "커널을 커널 모듈 없이 확장한다"는 발상이 너무 신박해서 깊게 파보고 싶습니다.
리눅스는 모놀리식 커널입니다. 서버는 다음과 같은 특징이 있습니다.
그래서 좀 무겁고 관리하기 힘들더라도, 퍼포먼스가 깡패인 모놀리식 구조의 리눅스가 서버 시장을 장악한 것입니다.
AWS, Google Cloud, Azure의 99% 이상이 리눅스 커널 위에서 돌아갑니다.
처음엔 "OS랑 커널이랑 뭐가 다르냐?"는 질문에서 시작했습니다. 지금은 이렇게 정리해봅니다.
결국 이거였습니다: 커널은 컴퓨터의 엔진이다. 엔진이 멈추면 차는 고철이다.