리눅스 아키텍처 파헤치기: 4개 계층으로 이해하는 시스템 동작 원리

|MSA & Architecture|14분 읽기

명령어 하나 뒤에 숨은 여행

터미널에 ls라고 칩니다. 파일 목록이 나옵니다. 너무 당연해서 아무도 신경 쓰지 않죠. 그런데 이 한 줄이 실행되기까지 시스템 안에서는 꽤 긴 여행이 일어납니다. 사용자 공간에서 출발한 명령이 커널을 거쳐 하드웨어까지 내려갔다가 다시 올라오는 경로.

저는 운영과 아키텍처 자리에 앉고 나서야 이 경로를 제대로 들여다보게 됐습니다. 개발할 때는 ls가 그냥 ls였거든요. 그런데 장애를 추적하거나 성능 병목을 잡다 보면, 결국 "이 요청이 지금 어느 층에서 막혀 있는가"를 따지게 됩니다. 그때부터 이 계층 구조가 단순한 교과서 그림이 아니라, 문제를 분해하는 좌표계로 보이기 시작했어요.

오늘은 이 여행 경로, 즉 리눅스 아키텍처를 정리해보려 합니다. 복잡해 보이지만 의외로 선이 명확한 구조입니다.

4개 층으로 나누어 보는 리눅스

리눅스는 모듈식 계층형 아키텍처를 따릅니다. 아파트처럼 각 층이 명확히 나뉘어 있고, 정해진 통로로만 위아래가 대화합니다.

계층 역할 주요 구성요소
4. 사용자 공간 사용자와의 직접적인 상호작용 Shell, 애플리케이션, 명령어
3. 시스템 라이브러리 커널과 애플리케이션 간 중계 glibc, 시스템 호출
2. 커널 시스템 자원 관리 프로세스, 메모리, 파일시스템 관리
1. 하드웨어 물리적 처리 수행 CPU, RAM, 디스크, I/O 장치

핵심은 각 계층이 바로 아래 계층하고만 대화한다는 점입니다. 애플리케이션이 하드웨어를 직접 건드릴 수 없는 이유가 여기 있죠. 이게 답답해 보일 수도 있지만, 마이크로서비스에서 서비스 간 통신을 게이트웨이로 강제하는 것과 같은 발상입니다. 직접 호출을 막아야 격리가 유지되고, 격리가 유지돼야 한 층의 사고가 전체로 번지지 않거든요.

1층: 하드웨어 - 모든 것의 기초

가장 아래에는 물리적인 하드웨어가 있습니다. CPU, 메모리, 스토리지, 네트워크 카드처럼 실제로 연산하고 저장하는 부품들이죠.

여기서 중요한 건 리눅스가 하드웨어와 직접 대화하지 않는다는 점입니다. 대신 장치 드라이버라는 번역가를 거칩니다. 이 덕분에 같은 커널이 서로 다른 NIC, 서로 다른 디스크 컨트롤러 위에서 동일하게 동작할 수 있어요. 위층 입장에서는 하드웨어가 무엇이든 인터페이스가 같으니까요.

클라우드 환경으로 넘어오면 이 추상화가 한 겹 더 늘어납니다. 가상화 계층이 끼면서 "진짜 하드웨어"와 "OS가 보는 하드웨어"가 분리되죠. 운영하다 보면 이 경계를 헷갈려서 엉뚱한 데서 병목을 찾는 경우가 의외로 많습니다.

2층: 커널 - 리눅스의 심장

커널은 리눅스의 핵심입니다. 소프트웨어와 하드웨어 사이에서 모든 자원을 조율하는 지휘자죠.

커널이 맡는 일은 크게 네 가지입니다.

  1. 프로세스 관리: 프로그램 실행, 스케줄링, 종료 처리
  2. 메모리 관리: RAM 할당, 가상 메모리, 스왑
  3. 장치 관리: 하드웨어와의 소통 창구
  4. 파일시스템 관리: 데이터 저장, 읽기, 권한

커널은 커널 공간이라는 보호된 메모리 영역에서 동작합니다. 사용자 프로그램이 함부로 건드릴 수 없게 격리돼 있죠. 이 경계가 왜 중요한지는 장애를 한 번 겪어보면 체감됩니다. 사용자 프로세스가 죽어도 커널은 멀쩡해야 시스템이 살아남으니까요. 권한 경계는 보안 장치이기 이전에, 사고의 폭발 반경(blast radius)을 줄이는 설계입니다.

3층: 시스템 라이브러리 - 번역사의 역할

애플리케이션이 커널과 직접 말을 섞기엔 절차가 너무 복잡합니다. 그래서 중간에 시스템 라이브러리가 있어요. 대표 격이 **GNU C 라이브러리(glibc)**입니다.

애플리케이션이 "파일을 읽고 싶어"라고 하면, 시스템 라이브러리가 이를 시스템 호출(syscall) 형태로 변환해 커널에 전달합니다.

대표적인 시스템 호출들:

read()    // 파일 읽기
write()   // 파일 쓰기
open()    // 파일 열기
fork()    // 프로세스 복제
exec()    // 새 프로그램 실행

시스템 라이브러리 덕분에 개발자는 커널 수준 코드를 직접 만질 필요가 없습니다. 역할로 보면 일종의 SDK 같은 존재죠. 내부 구현이 어떻게 바뀌든 위층은 동일한 인터페이스만 알면 됩니다. 이 안정적인 계약이 깨지지 않기 때문에 수십 년 된 바이너리가 지금도 돌아가는 거고요.

4층: 사용자 공간 - 우리가 만나는 리눅스

사용자 공간은 우리가 실제로 작업하는 영역입니다.

  • 셸(Shell): 명령어를 입력받아 시스템에 전달하는 인터페이스 (bash, zsh 등)
  • 유틸리티: ls, cp, grep 같은 기본 명령어들
  • 애플리케이션: 브라우저, 에디터, 서버 프로그램 등

터미널에 명령어를 입력하면 셸이 이를 해석하고, 필요하면 시스템 호출을 통해 커널에 요청을 넘깁니다. 그 결과가 다시 화면으로 올라오는 거죠. 우리가 평소 만지는 건 사실상 이 한 층뿐인데, 아래 세 층이 묵묵히 받쳐주고 있는 셈입니다.

명령어 하나의 여행 경로

cat /etc/passwd를 입력했을 때의 흐름을 따라가 봅니다.

  1. 사용자 공간: 셸이 명령어 파싱
  2. 시스템 라이브러리: open(), read() 시스템 호출 생성
  3. 커널: 파일시스템을 통해 파일 위치 확인
  4. 하드웨어: 디스크에서 실제 데이터 읽기
  5. 역순으로 복귀: 데이터가 터미널에 출력

이 왕복이 밀리초 단위로 일어납니다. 그런데 운영 관점에서 흥미로운 건, 장애가 났을 때도 이 똑같은 경로를 거꾸로 짚는다는 점입니다. 출력이 느리다? 그럼 어느 구간에서 시간이 새는지를 봅니다. 시스템 호출에서 막혔는지, 커널이 I/O를 기다리는지, 아니면 디스크 자체가 느린지. strace로 syscall을 들여다보거나 I/O 지표를 보는 작업이 결국 이 5단계 중 한 칸을 특정하는 일이거든요. 구조를 알면 추측이 줄고, 추측이 줄면 장애 시간이 줄어듭니다.

모듈성이 가져다주는 유연함

이 아키텍처의 가장 큰 장점은 모듈성입니다. 각 구성요소를 독립적으로 추가, 제거, 업데이트할 수 있어요.

예를 들어 새 파일시스템을 추가하거나 드라이버를 갈아끼울 때 시스템을 통째로 재부팅할 필요가 없습니다.

# 모듈 동적 로드
sudo modprobe ext4

# 모듈 제거
sudo rmmod old_driver

이게 별것 아닌 것 같지만, 운영하는 입장에선 재부팅을 피한다는 게 곧 다운타임을 피한다는 뜻입니다. 핵심을 멈추지 않고 주변부만 교체하는 구조. 무중단 배포를 고민해 본 사람이라면 이 발상이 낯설지 않을 겁니다. 커널은 이미 수십 년 전부터 같은 문제를 풀고 있었던 거죠. 덕분에 같은 리눅스가 스마트폰부터 슈퍼컴퓨터까지 굴러갑니다.

아키텍처를 이해해야 하는 이유

이 구조가 머릿속에 잡히면 평소 헷갈리던 것들이 정리됩니다.

  • 권한 시스템: 왜 root가 필요한지, 사용자 분리가 어떻게 이뤄지는지
  • 성능 튜닝: 병목이 어느 계층에서 생기는지
  • 문제 해결: 로그를 보고 어느 층의 문제인지 추론
  • 보안 강화: 계층별로 어디를 막아야 하는지

특히 시스템 관리나 DevOps를 한다면 이 기본기가 의외로 멀리까지 따라옵니다. 자동화 스크립트를 짤 때도, 인프라를 설계할 때도 결국 "이 작업이 어느 층에서 일어나는가"를 알고 있느냐가 판단의 속도를 가릅니다. 도구는 계속 바뀌지만, 계층이라는 좌표계는 잘 안 바뀌거든요.

단순하지만 강력한 설계

리눅스의 계층형 아키텍처는 30년 넘게 살아남은 설계입니다. 명확한 역할 분담과 표준화된 인터페이스. 이 두 가지로 안정성과 확장성을 동시에 잡았죠.

돌아보면 우리가 요즘 좋은 아키텍처라고 부르는 원칙들, 즉 관심사 분리, 인터페이스 고정, 격리, 모듈 교체 같은 것들은 이미 이 안에 다 들어 있습니다. 새로운 패러다임이 등장할 때마다 우리는 사실 같은 원칙을 다른 이름으로 다시 발견하는 게 아닐까 싶기도 하고요. 터미널에 명령어를 칠 때마다 이 정교한 시스템이 묵묵히 돌고 있다는 걸 알고 나면, ls 한 줄도 조금 다르게 보입니다.

#리눅스#시스템아키텍처#커널#운영체제#시스템관리