본문으로 건너뛰기

안동민 개발노트

본문 시작

성능 튜닝과 OS 면접 주제

파일·TCP·메모리·I/O 커널 파라미터를 측정 근거로 조정하고 운영체제 핵심 질문을 병목 진단 관점에서 정리합니다.

이 절에서는 운영체제 면접에서 자주 다루는 주제와 서버 운영에서 확인하는 커널 파라미터를 함께 정리합니다.

튜닝 항목은 병목 유형, 측정 지표, 변경 전후 검증 기준을 중심으로 봅니다.

OS 원리와 성능 질문

이 절은 파일 디스크립터, TCP, 메모리, I/O 스케줄러처럼 바로 바꿀 수 있는 커널 설정과 프로세스, 가상 메모리, 동기화, 시스템 콜 면접 주제를 한 흐름으로 정리한다.

  1. 연결 수
    소켓도 파일 디스크립터를 쓴다

    연결 수 고트래픽 웹 서버에서는 `ulimit -n`과 `fs.file-max`가 낮으면 동시에 열 수 있는 연결 자체가 먼저 막힌다. 65535 somaxconn

  2. 메모리
    지연 시간 요인: RAM, 스왑, dirty page

    메모리 `swappiness`, `overcommit_memory`, dirty page 비율은 메모리 기반 저장소와 DB 서버의 안정성 판단에 직접 연결된다. swappiness=10 dirty_ratio

  3. 면접 원리
    OS 성능 비용 요소

    면접 원리 프로세스와 스레드, `fork()`와 `exec()`, 가상 메모리 질문은 결국 주소 공간과 캐시 무효화 비용을 이해했는지 확인한다. COW TLB


커널 파라미터 튜닝

파일 디스크립터 제한

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으로 설정합니다.

아래 다이어그램은 증상별로 먼저 볼 지표와 조정할 커널 파라미터를 연결한 튜닝 우선순위 표입니다.

커널 튜닝 절차

튜닝은 값을 크게 올리는 일이 아니라 병목 가설을 세우고 측정값으로 확인한 뒤 되돌릴 수 있는 단위로 변경하는 과정입니다.

  1. 1
    accept 대기열과 SYN 큐를 분리해서 본다

    연결 폭주 거부가 늘면 애플리케이션 처리량과 커널 큐 한계를 함께 확인합니다. 지표 ss -s 조정 somaxconn

  2. 2
    TIME_WAIT와 포트 범위

    포트 고갈 짧은 아웃바운드 연결이 많으면 재사용 정책과 포트 범위가 병목이 됩니다. 지표 ss -tan 조정 ip_local_port_range

  3. 3
    swap과 reclaim 점검

    메모리 압박 DB와 캐시 서버는 swap 진입 자체가 지연 시간 급등으로 이어질 수 있습니다. 지표 vmstat 1 조정 swappiness

  4. 4
    dirty page 밀림

    쓰기 지연 flush가 몰리면 평균은 좋아 보여도 p99 지연 시간이 튀기 쉽습니다. 지표 /proc/meminfo 조정 dirty_ratio

  5. 5
    한 번에 하나만 변경

    여러 값을 동시에 바꾸면 어떤 설정이 효과를 냈는지 알 수 없습니다.

  6. 6
    기본값과 되돌림 기록

    장애 시 원복할 수 있도록 현재 값, 변경 값, 적용 시간을 남깁니다.

  7. 7
    p95와 p99 확인

    평균 처리량보다 꼬리 지연 시간이 튜닝 부작용을 더 빨리 드러냅니다.

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지연 시간 목표 기반
커널 튜닝 손잡이

본문 예제의 `ulimit`, TCP 백로그, swappiness, dirty page, I/O 스케줄러는 모두 병목 위치가 다를 때 선택하는 설정이다.

  1. 동시 접속이 늘 때 연결이 거부된다

    소켓 수와 listen 대기열을 먼저 의심한다. ulimit -n, somaxconn

  2. DB나 Redis가 스왑으로 느려진다

    RAM을 우선 쓰도록 swappiness를 낮추고 overcommit 정책을 본다. vm.swappiness=10

  3. 쓰기 지연이 한꺼번에 튄다

    dirty page가 어느 시점에 백그라운드 플러시되는지 조정한다. dirty_ratio, dirty_background_ratio

  4. 본문 표의 값을 읽는 방식

    항목 대표 값 줄이려는 위험 TCP 백로그 65535 연결 폭주와 SYN 큐 부족으로 새 요청이 밀리는 상황 로컬 포트 범위 1024-65535 아웃바운드 연결이 많을 때 임시 포트가 빠르게 고갈되는 상황 I/O 스케줄러 none, mq-deadline NVMe에는 불필요한 스케줄링 오버헤드, HDD에는 요청 지연 운영 적용: 예제처럼 `sysctl -w`로 즉시 바꾼 값은 재부팅 후 사라질 수 있으므로, 검증된 값만 `/etc/sysctl.conf`에 영구 반영한다.


자주 출제되는 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)는 완료 시 콜백이나 이벤트로 통보받습니다.

블로킹은 작업 완료까지 호출자가 대기합니다.

논블로킹은 즉시 반환하고 나중에 결과를 확인합니다.

블로킹과 동기

면접에서는 두 축을 섞어 말하기 쉽습니다. 호출자가 멈추는지와 완료를 누가 전달하는지를 분리하면 네 칸으로 정리됩니다.

  1. Sync + Blocking
    가장 흔한 read/write

    Sync + Blocking 가장 흔한 read/write 데이터가 올 때까지 호출 스레드가 멈춥니다. read()

  2. Sync + Nonblock
    직접 다시 확인

    Sync + Nonblock 직접 다시 확인 즉시 반환하고 호출자가 반복 확인합니다. EAGAIN

  3. Async + Blocking
    실무에서는 드문 조합

    Async + Blocking 실무에서는 드문 조합 완료 통지는 비동기지만 기다리면 장점이 줄어듭니다. rare

  4. Async + Nonblock
    제출 후 완료 통지

    Async + Nonblock 제출 후 완료 통지 요청을 맡기고 다른 일을 하다가 완료 큐나 콜백을 받습니다. io_uring

  5. Interview Answer
    먼저 축을 정의하고, 예시를 한 칸씩 붙이면 답변이 흔들리지 않습니다

    Interview Answer 먼저 축을 정의하고, 예시를 한 칸씩 붙이면 답변이 흔들리지 않습니다 블로킹과 논블로킹은 호출 직후 스레드의 상태, 동기와 비동기는 완료 확인의 주체를 기준으로 설명합니다.


심화 면접 주제

캐시 친화(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가 대응됩니다.

운영체제 면접 답변 축

본문의 프로세스와 스레드, 가상 메모리, 동기화, 시스템 질문은 서로 다른 단원이 아니라 실행 단위와 자원 접근 비용을 묻는 연결된 질문이다.

  1. process
    실행 단위와 주소 공간

    process 프로세스는 독립된 메모리 공간을 가진다 IPC가 필요하고 생성 비용이 크지만 실패가 다른 프로세스로 번지지 않게 격리한다. thread 스레드는 코드, 데이터, 힙을 공유한다 스택만 따로 두므로 가볍지만 공유 메모리 버그를 조심한다. fork+exec `fork()`는 COW로 복사하고 `exec()`는 프로그램을 바꾼다 셸 명령 실행 흐름을 설명할 때 함께 묶어서 답한다.

  2. TLB
    메모리 접근과 기다림의 비용

    TLB 컨텍스트 스위칭은 레지스터 저장보다 캐시 무효화가 아프다 같은 주소 공간의 스레드 전환이 더 빠른 이유로 연결된다. page fault 없는 페이지에 접근하면 디스크에서 프레임으로 읽어 온다 빈 프레임이 없으면 LRU 같은 페이지 교체가 뒤따른다. lock 데드락은 네 조건이 동시에 맞을 때 생긴다 실무 답변은 락 순서 규칙과 타임아웃으로 마무리한다.


정리

운영체제는 컴퓨터 과학의 기초이자, 실무 개발의 근간입니다.

프로세스와 스레드를 이해하면 동시성 버그를 잡을 수 있고, 가상 메모리를 이해하면 메모리 문제를 진단할 수 있습니다.

파일 시스템을 알면 데이터를 안전하게 관리하고, 보안 원리를 알면 견고한 시스템을 설계할 수 있습니다.

이 교재에서 다룬 개념들은 특정 기술이 아니라 원리입니다.

언어와 프레임워크는 바뀌어도, OS의 원리는 수십 년 동안 유효했고 앞으로도 유효할 것입니다.

OS 면접 답변 기준

운영체제 질문은 용어 정의보다 어떤 상태가 어떤 이벤트로 바뀌며, 그 선택이 성능·공정성·안정성 중 무엇을 얻고 잃는지 설명해야 밀도가 생긴다.

  1. 핵심 한 문장

    개념의 목적과 해결하는 문제를 먼저 짧게 말한다. definition

  2. 상태 전이

    프로세스, 페이지, 락, 파일 같은 대상의 상태가 어떻게 바뀌는지 설명한다. mechanism

  3. 실패 조건

    deadlock, page fault, starvation, race처럼 깨지는 경우를 붙인다. edge case

  4. 트레이드오프

    속도, 메모리, 공정성, 복잡도 중 무엇을 선택했는지 말한다. judgment