icon

안동민 개발노트

14장 : 실무에서 만나는 OS 개념

성능 튜닝과 OS 면접 주제


OS 지식은 면접장에서 단골 질문이며, 서버 성능을 한 단계 끌어올리는 무기이기도 합니다. 이 절에서는 실무에 바로 적용할 수 있는 커널 파라미터 튜닝과, 자주 출제되는 면접 질문을 정리합니다.


커널 파라미터 튜닝

파일 디스크립터 제한

ulimit 설정
# 프로세스당 최대 열 수 있는 파일 수
ulimit -n          # 현재 값 확인 (기본 1024)
ulimit -n 65535    # 일시적 변경

# 영구 설정: /etc/security/limits.conf
# *  soft  nofile  65535
# *  hard  nofile  65535

# 시스템 전체 제한
cat /proc/sys/fs/file-max
sysctl -w fs.file-max=2097152

웹 서버가 동시에 수천 개의 연결을 처리하려면 파일 디스크립터 제한을 높여야 합니다. 소켓도 파일 디스크립터를 사용하기 때문입니다. 1024는 고트래픽 서비스에 턱없이 부족합니다.

TCP 튜닝

tcp_tuning.sh
# 현재 값 확인
sysctl -a | grep somaxconn

# listen 백로그 크기 (동시 연결 요청 대기열)
sysctl -w net.core.somaxconn=65535

# SYN 큐 크기 (3-way handshake 중인 연결)
sysctl -w net.ipv4.tcp_max_syn_backlog=65535

# TIME_WAIT 소켓 재사용 (빠른 포트 회전)
sysctl -w net.ipv4.tcp_tw_reuse=1

# TCP keepalive (유휴 연결 감지)
sysctl -w net.ipv4.tcp_keepalive_time=300    # 300초 후 첫 probe
sysctl -w net.ipv4.tcp_keepalive_intvl=30    # 30초 간격
sysctl -w net.ipv4.tcp_keepalive_probes=5    # 5번 실패 시 연결 종료

# 사용 가능한 로컬 포트 범위 확장
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

# SYN flood 방지
sysctl -w net.ipv4.tcp_syncookies=1
파라미터기본값권장값효과
somaxconn12865535연결 폭주 시 거부 방지
tcp_max_syn_backlog12865535SYN flood 대응력
tcp_tw_reuse01TIME_WAIT 포트 재활용
tcp_fin_timeout6015FIN_WAIT 빠른 정리
ip_local_port_range32768-609991024-65535아웃바운드 연결 확대

메모리 튜닝

memory_tuning.sh
# 스왑 사용 빈도 (0~100, 낮을수록 RAM 선호)
sysctl -w vm.swappiness=10
# DB 서버: 1~10 (스왑 최소화)
# 웹 서버: 10~30

# overcommit 정책
sysctl -w vm.overcommit_memory=0    # 0: 보수적 (거부 가능)
                                     # 1: 항상 허용 (위험)
                                     # 2: swap + ratio% RAM만 허용

# dirty page 플러시 주기
sysctl -w vm.dirty_ratio=20                # 전체 메모리의 20%까지 dirty 허용
sysctl -w vm.dirty_background_ratio=5      # 5% 초과 시 백그라운드 플러시 시작
sysctl -w vm.dirty_expire_centisecs=3000   # 30초 이상 된 dirty page 플러시

# 영구 설정
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p  # 적용

swappiness를 낮추면 OS가 가능한 한 RAM을 사용하고, 필요할 때만 스왑합니다. 데이터베이스 서버에서는 0~10이 권장됩니다. Redis처럼 메모리 기반 저장소는 0으로 설정합니다.

I/O 스케줄러

io_scheduler.sh
# 현재 I/O 스케줄러 확인
cat /sys/block/sda/queue/scheduler
# [mq-deadline] kyber bfq none

# 변경 (즉시 적용)
echo "none" > /sys/block/nvme0n1/queue/scheduler   # NVMe SSD
echo "mq-deadline" > /sys/block/sda/queue/scheduler # HDD/SATA SSD
스케줄러적합한 디스크특징
none (noop)NVMe SSD스케줄링 불필요, 최소 오버헤드
mq-deadlineHDD, SATA SSD요청 만료 보장, DB에 적합
bfq데스크톱, 저성능공평한 대역폭 할당
kyber고성능 SSD지연 시간 목표 기반

자주 출제되는 OS 면접 질문

프로세스와 스레드

프로세스와 스레드의 차이는?

프로세스는 독립된 메모리 공간(코드, 데이터, 힙, 스택)을 가집니다. 스레드는 같은 프로세스 내에서 코드, 데이터, 힙을 공유하고, 각자의 스택만 가집니다. 프로세스 간 통신은 IPC가 필요하지만, 같은 프로세스의 스레드는 공유 메모리로 바로 통신합니다. 프로세스 생성은 무겁고(주소 공간 복사), 스레드 생성은 가볍습니다(스택만 할당).

컨텍스트 스위칭이란?

CPU가 현재 프로세스/스레드의 실행을 중단하고 다른 것을 실행하는 과정입니다. 현재의 레지스터 상태, PC, 스택 포인터 등을 PCB에 저장하고, 새 프로세스의 상태를 복원합니다. 비용이 발생하며, 특히 캐시와 TLB가 무효화되는 것이 큰 오버헤드입니다. 같은 프로세스 내의 스레드 전환은 주소 공간이 같으므로 TLB 플러시가 필요 없어 더 빠릅니다.

fork()와 exec()는?

fork()는 부모의 메모리를 복사한 자식 프로세스를 생성합니다. COW(Copy-on-Write)로 실제 물리 메모리는 수정 시에만 복사됩니다. exec()는 현재 프로세스의 주소 공간을 새 프로그램으로 교체합니다. 셸이 명령을 실행할 때 fork() + exec() 조합을 사용합니다.

메모리

가상 메모리란?

프로세스에게 물리 메모리보다 큰 연속된 주소 공간을 제공하는 기법입니다. 실제로 사용하는 페이지만 물리 메모리에 올리고, 나머지는 디스크에 둡니다. 페이지 테이블로 가상 주소를 물리 주소로 변환하며, TLB가 이 변환을 캐시합니다.

페이지 폴트란?

프로세스가 접근하려는 페이지가 물리 메모리에 없을 때 발생합니다. OS가 디스크에서 해당 페이지를 읽어 빈 프레임에 적재하고 페이지 테이블을 갱신합니다. 디스크 I/O가 필요하므로 수 밀리초가 걸립니다. 빈 프레임이 없으면 페이지 교체 알고리즘(LRU 등)으로 교체할 프레임을 결정합니다.

내부 단편화 vs 외부 단편화?

내부 단편화: 할당된 블록 내부의 사용되지 않는 공간 (페이징에서 발생). 외부 단편화: 할당된 블록 사이의 남는 공간 (세그멘테이션에서 발생). 페이징은 고정 크기 프레임으로 외부 단편화를 제거하고, 컴팩션은 외부 단편화를 해결하지만 비용이 큽니다.

동기화

데드락의 4가지 조건은?

상호 배제, 점유와 대기, 비선점, 순환 대기입니다. 네 조건이 동시에 충족되어야 데드락이 발생합니다. 하나라도 깨뜨리면 예방됩니다. 실무에서는 락 순서 규칙타임아웃이 가장 많이 사용됩니다.

뮤텍스와 세마포어의 차이는?

뮤텍스는 이진(0 또는 1)으로, 소유권이 있어 잠근 스레드만 풀 수 있습니다. 세마포어는 카운터로 N개까지 동시 접근을 허용합니다. 소유권 개념이 없어 다른 스레드가 signal할 수 있습니다. 뮤텍스는 락, 세마포어는 신호라고 기억하면 됩니다.

스핀락은 언제 쓰나?

임계 영역이 매우 짧아 컨텍스트 스위칭보다 바쁜 대기가 더 빠른 경우에 씁니다. 멀티코어에서만 의미가 있고, 싱글코어에서는 CPU만 낭비합니다. 커널 인터럽트 핸들러에서 주로 사용됩니다.

시스템

사용자 모드와 커널 모드의 차이는?

사용자 모드에서는 제한된 명령어만 실행 가능합니다. 하드웨어 접근, 인터럽트 비활성화 등은 불가능합니다. 시스템 콜을 통해 커널 모드로 전환되며, 이때 모든 명령어와 하드웨어에 접근할 수 있습니다. 이 전환에는 수백 나노초의 오버헤드가 있습니다.

동기와 비동기, 블로킹과 논블로킹의 차이는?
블로킹논블로킹
동기read() — 데이터 올 때까지 대기read()가 즉시 반환, 반복 확인
비동기거의 없음aio_read() — 완료 시 통보

동기(Synchronous)는 작업 완료를 호출자가 직접 확인합니다. 비동기(Asynchronous)는 완료 시 콜백이나 이벤트로 통보받습니다. 블로킹은 작업 완료까지 호출자가 대기합니다. 논블로킹은 즉시 반환하고 나중에 결과를 확인합니다.


심화 면접 주제

캐시 친화(Cache-friendly) 코드란?

CPU가 메모리에 접근할 때 캐시 라인(보통 64바이트) 단위로 가져옵니다. 연속된 메모리에 순서대로 접근하면 캐시 적중률이 높아집니다. 연결 리스트보다 배열이, 열 우선 탐색보다 행 우선 탐색이 캐시 친화적입니다.

cache_friendly.c
/* 캐시 친화적: 행 우선 순회 (연속 메모리 접근) */
for (int i = 0; i < N; i++)
    for (int j = 0; j < N; j++)
        sum += matrix[i][j];  /* 캐시 적중 */

/* 캐시 비친화적: 열 우선 순회 (점프 접근) */
for (int j = 0; j < N; j++)
    for (int i = 0; i < N; i++)
        sum += matrix[i][j];  /* 캐시 미스 빈발 */

N이 큰 행렬에서 행 우선 순회가 수배 빠를 수 있습니다.

Zero-Copy란?

전통적인 파일 전송은 커널 버퍼 → 사용자 버퍼 → 소켓 버퍼 → NIC로 4번의 복사가 발생합니다. sendfile() 시스템 콜은 커널 버퍼에서 NIC로 직접 전달하여 복사를 줄입니다. Nginx, Kafka 등 고성능 서버가 활용합니다.

epoll vs select?

select는 감시할 fd 목록을 매번 커널에 전달합니다. O(n). epoll은 커널에 fd를 등록해두고, 이벤트가 발생한 fd만 반환합니다. O(1). 동시 연결 수가 수만 개를 넘으면 epoll이 필수입니다. Windows에서는 IOCP, macOS에서는 kqueue가 대응됩니다.


정리

운영체제는 컴퓨터 과학의 기초이자, 실무 개발의 근간입니다. 프로세스와 스레드를 이해하면 동시성 버그를 잡을 수 있고, 가상 메모리를 이해하면 메모리 문제를 진단할 수 있습니다. 파일 시스템을 알면 데이터를 안전하게 관리하고, 보안 원리를 알면 견고한 시스템을 설계할 수 있습니다.

이 교재에서 다룬 개념들은 특정 기술이 아니라 원리입니다. 언어와 프레임워크는 바뀌어도, OS의 원리는 수십 년 동안 유효했고 앞으로도 유효할 것입니다.

목차