라즈베리파이로 뜯어보는 운영체제: htop 하나로 시작해서 epoll까지
컴퓨터구조랑 운영체제를 책으로만 보다가 도저히 흥미가 안 붙어서, 그냥 집에 있는 라즈베리파이를 직접 뒤적거리면서 공부해보기로 했다. `htop` 하나 띄워놓고 시작한 질문이 결국 가상 메모리, 스레드, 커널/유저 스페이스, 소켓, epoll까지 이어졌다.
학습 주제
- 주제: 라즈베리파이 실습을 통한 운영체제/컴퓨터구조 개념 정리 (프로세스, 메모리, 스케줄링, 소켓, I/O)
- 날짜: 2026-07-20
탐구 과정
시작은 단순했다. htop을 띄워놓고 "이 숫자들이 다 뭔가"부터 물고 늘어졌다. VIRT, RES, SHR, PRI, NI, 프로세스 상태(S, R)... 하나씩 뜻을 알아가다 보니 계속 "근데 왜?"가 튀어나왔다.
특히 걸렸던 부분은 이거였다.
"코드만 일부 올리는 거면 VIRT도 그만큼 낮게 책정해야 하지 않나?"
이게 결국 가상 메모리와 페이지 테이블 개념으로 이어졌고, 여기서 "영토를 미리 뻥튀기해서 약속해두고, 실제로 필요할 때만 물리 메모리를 배정한다"는 비유로 이해가 됐다. 그 다음엔 자연스럽게 "그럼 코어 수랑 프로세스 수는 무슨 관계인가", "왜 프로세스가 여러 개 떠 있나(MSA랑 뭐가 다른가)", "레이스 컨디션은 SHR 때문에 안 터지나" 같은 질문들이 줄줄이 나왔다.
중간에 살짝 딴 길로 새서 "AI가 포인터 조작이나 러스트 소유권 같은 걸 얼마나 잘하는지"도 궁금해서 짚어봤다. 결론은 메모리 안전성 검증은 확률 기반 모델이 다루기엔 너무 엄격한 논리적 정합성을 요구한다는 것.
그러다 lsof, ss, iostat 같은 명령어로 실제 파이 내부를 들여다보기 시작했는데, 여기서 진짜 재밌는 사건이 하나 터졌다. strace로 nginx를 직접 실행시켰더니:
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
에러가 났다. 처음엔 당황했는데, lsof -i :80으로 확인해보니 이미 PID 2519번 nginx가 80번 포트를 정상적으로 쓰고 있었다. 포트 중복 문제였다는 걸 직접 로그로 확인한 게 꽤 유익했다. 이론으로만 보던 "포트는 하나의 프로세스만 점유 가능"을 실제 에러로 마주친 셈이다.
마지막엔 "epoll이 되려면 코어가 여러 개 있어야 하는 거 아닌가?"라는 질문에서 시작해 I/O 멀티플렉싱까지 파고들었다.
핵심 학습 내용
프로세스와 htop 읽는 법
VIRT: 프로세스가 예약해둔 가상 메모리 크기 (실제로 다 쓰는 게 아님)RES: 실제 물리 RAM에 올라온 크기SHR: 다른 프로세스와 공유하는 메모리(보통 read-only 라이브러리)PRI/NI:NI는 사용자가 조정하는 친절도,PRI는 그걸 반영해 OS가 최종 계산한 실제 우선순위S상태(Sleeping)가 많은 건 정상. 대부분의 프로세스는 입력/이벤트를 기다리며 쉬고 있을 뿐이다.
가상 메모리와 페이지 폴트
OS는 프로세스에게 "너는 이만큼의 주소 공간을 다 쓸 수 있어"라고 먼저 크게 약속(가상 주소)해두고, 실제로 그 주소에 접근하는 순간에만 물리 메모리를 배정한다(Demand Paging). 이때 실제 RAM에 해당 데이터가 없으면 페이지 폴트가 발생하는데, 이건 에러가 아니라 "지금 이 부분 실제로 필요하니까 디스크에서 가져와줘"라는 요청 신호다. MMU(하드웨어)가 이 감지를 담당하고, 커널이 개입해서 처리한다.
RAM마저 부족해지면 다음 순서로 대응한다:
- 스와핑(Page Out/In) - 안 쓰는 프로세스 메모리를 디스크로 밀어냄
- OOM Killer - 그마저 안 되면 리소스를 가장 많이 먹는 프로세스를 강제 종료
커널 스페이스 vs 유저 스페이스
둘 다 물리적으로는 같은 RAM 위에 있다. 다만 OS가 "여기부터 여기까지는 커널 영역"이라고 선을 그어두고, CPU의 특권 레벨(Privilege Level)을 이용해 유저 프로세스가 커널 영역에 접근하지 못하게 막는다. 시스템 콜(openat, read 등)을 호출하면 CPU가 유저 모드에서 커널 모드로 전환(트랩)되고, 커널 코드가 대신 하드웨어를 조작한 뒤 다시 유저 모드로 돌아온다.
파일을 읽는 흐름은 이렇게 정리된다.
디스크(Raw Data) → 커널 페이지 캐시(Kernel Memory) → 복사 → 프로세스 버퍼(User Memory)
이 복사 과정이 곧 I/O 오버헤드이고, 이를 줄이기 위한 기법이 mmap(파일을 프로세스 주소 공간에 직접 매핑해서 복사 생략), Zero-copy, GPU의 Unified Memory 같은 것들이다.
파일 기술자(FD)의 정체
openat("/var/log/nginx/access.log", ...) = 4 같은 로그에서 나오는 그 숫자는 실제 어딘가에 물리적으로 "꽂히는" 게 아니라, 프로세스가 가진 **FD 테이블(배열)**의 특정 인덱스에 커널이 만든 '파일 객체'의 주소를 기록해두는 것이다. 프로세스는 파일의 실제 위치를 몰라도 되고, 그냥 숫자 하나만 기억하면 커널이 알아서 매핑을 찾아준다.
스레드 vs 프로세스
// 개념적으로 이렇게 나뉜다
프로세스: 완전히 독립된 메모리 영역, 통신 비용 비쌈, 안정적
스레드: 프로세스 내부에서 메모리(코드/데이터/힙)를 공유, 빠르지만 하나가 오염되면 전체가 죽음
크롬 브라우저가 탭마다 프로세스를 분리하면서 내부 연산은 스레드로 처리하는 것도 이 트레이드오프를 설계한 결과다.
소켓과 I/O 멀티플렉싱
소켓은 커널이 관리하는 통신용 버퍼를 가리키는 통로다. write()를 호출하면 데이터가 곧장 나가는 게 아니라 커널의 송신 버퍼에 복사되고, 버퍼가 꽉 차면 프로세스는 블로킹된다.
가장 흥미로웠던 부분은 epoll이 코어 개수와 무관하다는 점이었다. 처음엔 "동시 처리가 되려면 코어가 여러 개여야 하는 거 아닌가" 생각했는데, epoll은 "계산을 동시에 하는 기술"이 아니라 "누가 나를 불렀는지 확인하는 기술"이다. 대부분의 접속자는 아무 데이터도 안 보내고 있다는 통계적 전제 위에서, 커널이 데이터 들어온 소켓만 콕 집어 알려주기 때문에 코어 하나로도 수만 개 연결을 감당할 수 있다.
| 방식 | 특징 |
|---|---|
| select | 매번 소켓 리스트 전체를 검사, 개수 제한 있음 |
| poll | 개수 제한은 없지만 여전히 전체 검사 |
| epoll | 이벤트 기반, 변화 있는 소켓만 골라줌 (현재 표준) |
이해한 내용
- VIRT와 RES의 차이는 "가상화라는 이름의 뻥튀기 + 필요할 때만 실제 배정"이라는 OS의 기본 전략이다.
- 프로세스가 여러 개 떠 있는 건 로드밸런싱, 장애 격리를 위한 설계이고, 이게 사실 클라우드의 MSA가 하는 일을 단일 노드 안에서 OS가 이미 오래전부터 해오던 방식이라는 걸 알게 됐다.
- 컨텍스트 스위칭은 공짜가 아니다. 코어 수보다 압도적으로 많은 프로세스/스레드가 돌면 스위칭 비용 때문에 오히려 성능이 깎이는 쓰레싱이 발생할 수 있다.
- 커널 메모리와 유저 메모리는 물리적으로 같은 RAM 안에 있지만, 하드웨어 특권 레벨로 강제 격리된다는 걸 명확히 잡았다.
- I/O 멀티플렉싱은 "대부분의 연결은 놀고 있다"는 현실적 관찰을 기술로 구현한 것이라는 게 인상 깊었다.
실전 적용
- 서버를 직접 운영하게 되면
lsof,ss -tnp,iostat -x조합으로 병목을 먼저 진단하는 습관을 들일 수 있을 것 같다. - 지금 k3s/Docker 환경을 이미 파이에 굴리고 있으니, 다음엔 컨테이너가 어떻게 네임스페이스로 프로세스를 격리하는지
nsfs나 cgroup을 통해 더 들여다보고 싶다. - Nginx의 워커 프로세스 구조(epoll + 멀티프로세스)를 실제 웹 서버 튜닝(worker_processes, worker_connections 설정)에 적용해볼 계획.
추가 학습 계획
- 이번에 다루지 못한 파일 시스템 내부(inode, dentry, 저널링)와 네트워크 패킷의 계층별 흐름(3-way handshake, TCP 흐름 제어)을 다음 주제로 이어갈 예정
strace로 다른 데몬(redis, k3s-agent)들의 시스템 콜도 뜯어보고 싶다tcpdump로 실제 패킷 캡처해서 소켓 버퍼가 채워지고 비워지는 과정을 직접 눈으로 확인해보기- Formal Verification과 AI 코드 생성의 한계에 대한 자료도 따로 찾아볼 예정 (러스트 소유권 관련 논의가 계속 궁금함)