본문 바로가기

디스크 스케줄링과 I/O 최적화

FCFS·SSTF·SCAN 계열의 헤드 이동을 비교하고 SSD와 Linux I/O 스케줄러에서 달라지는 최적화 기준을 이해합니다.

하드 디스크는 기계 장치입니다.

헤드가 물리적으로 이동해야 데이터를 읽을 수 있습니다.

여러 프로세스가 동시에 디스크 I/O를 요청하면, 요청을 어떤 순서로 처리하느냐에 따라 성능이 크게 달라집니다.


디스크의 물리적 구조

하드 디스크(HDD)는 회전하는 플래터(Platter) 위에서 헤드(Head)가 데이터를 읽고 씁니다.

  • 트랙(Track): 플래터 위의 동심원. 단순한 CHS 도식에서는 바깥쪽을 0번으로 둡니다. 현대 장치의 LBA 주소와 실제 물리 배치는 컨트롤러가 추상화합니다.
  • 섹터(Sector): 트랙을 나눈 최소 단위 (전통 512바이트, 현대 4KB/Advanced Format)
  • 실린더(Cylinder): 같은 반지름의 트랙들을 수직으로 모은 것. 헤드 이동 없이 접근 가능합니다.

디스크 접근 시간은 세 요소로 구성됩니다.

구성 요소의미일반적인 시간
탐색 시간(Seek Time)헤드를 원하는 트랙으로 이동3~15ms
회전 지연(Rotational Latency)원하는 섹터가 헤드 아래로 회전2~6ms (7200RPM 약 4.2ms)
전송 시간(Transfer Time)데이터를 실제로 읽기0.01~0.1ms

표의 시간은 대략적인 규모 예시이며 요청 크기·장치에 따라 달라집니다. HDD 스케줄링은 헤드 이동 비용뿐 아니라 대기 시간과 공정성도 고려합니다.


디스크 스케줄링 알고리즘

요청 큐: 트랙 [98, 183, 37, 122, 14, 124, 65, 67], 현재 헤드 위치: 53.

FCFS (First-Come, First-Served)

요청이 도착한 순서대로 처리합니다.

53→98→183→37→122→14→124→65→67.

헤드 이동 거리: 45+85+146+85+108+110+59+2 = 640 트랙.

헤드가 디스크 전체를 왔다 갔다 합니다.

SSTF (Shortest Seek Time First)

현재 헤드 위치에서 가장 가까운 요청을 먼저 처리합니다.

53→65→67→37→14→98→122→124→183.

헤드 이동: 12+2+30+23+84+24+2+59 = 236 트랙.

FCFS보다 크게 개선됩니다.

단점: 멀리 있는 요청이 계속 뒤로 밀려 기아(Starvation)가 발생할 수 있습니다.

SJF 스케줄링과 같은 문제입니다.

SCAN (엘리베이터 알고리즘)

헤드가 한쪽 끝에서 다른 쪽 끝으로 이동하면서 경로상의 모든 요청을 처리하고, 끝에 도달하면 방향을 바꿉니다.

53으로 시작, 왼쪽으로 진행: 53→37→14→0(끝)→65→67→98→122→124→183.

요청 유입과 서비스 시간을 제한한 일반적인 SCAN 모형에서는 한 방향의 스캔으로 요청을 계속 방문하여 SSTF의 기아 위험을 줄입니다.

하지만 끝에서 방향을 바꾸면 바로 지나온 영역은 요청이 비어 있으므로 비효율적일 수 있습니다.

C-SCAN (Circular SCAN)

한 방향으로만 요청을 처리하고, 끝에 도달하면 반대쪽 끝으로 돌아오는 동안 요청을 처리하지 않습니다. 물리적인 복귀 이동에도 시간과 거리가 듭니다.

반복 스캔에서 위치에 따른 대기 편차를 줄이려는 방식이며, 모든 요청의 대기 시간이 정확히 같다는 보장은 아닙니다.

53 오른쪽으로: 53→65→67→98→122→124→183→(끝)→0(점프)→14→37.

LOOK / C-LOOK

SCAN/C-SCAN의 실용적 변형입니다.

LOOK은 진행 방향의 마지막 요청에서 반전하고, C-LOOK은 반대편 첫 요청으로 복귀한 뒤 같은 방향으로 서비스합니다. 본문 시뮬레이션은 복귀 거리도 합산합니다.

불필요한 이동을 줄입니다.

disk_scheduling.py
def sstf(requests, head):
    """SSTF 스케줄링 시뮬레이션"""
    pending = list(requests)
    order = []
    total_movement = 0
    current = head

    while pending:
        # 가장 가까운 요청 찾기
        closest = min(pending, key=lambda x: abs(x - current))
        total_movement += abs(closest - current)
        current = closest
        order.append(closest)
        pending.remove(closest)

    return order, total_movement

def c_look(requests, head):
    """C-LOOK 스케줄링 시뮬레이션"""
    left = sorted([r for r in requests if r < head])
    right = sorted([r for r in requests if r >= head])
    order = right + left  # 오른쪽 끝까지 → 왼쪽 처음으로 점프
    total = 0
    current = head
    for r in order:
        total += abs(r - current)
        current = r
    return order, total

requests = [98, 183, 37, 122, 14, 124, 65, 67]
head = 53

for name, func in [("SSTF", sstf), ("C-LOOK", c_look)]:
    order, movement = func(requests, head)
    print(f"{name}: 이동={movement}, 순서={order}")

원 SSTF의 선택 과정을 손으로 확인하기

시작 53에서 남은 요청까지의 거리 중 최소는 65까지의 12입니다. 다음 65에서는 67까지의 2가 최소입니다. 두 요청을 제거하고 67에서 다시 비교하면 37까지 30이 98까지 31보다 작아 37을 고릅니다. 이렇게 매번 현재 위치를 갱신해야 그림의 53→65→67→37 순서를 얻습니다. 처음 위치 53에서 한 번 정렬한 목록을 끝까지 쓰는 알고리즘이 아닙니다.

독립 확인: 새 큐는 [40,60], 시작은 50입니다. 원 SSTF 함수와 오른쪽부터 처리하는 원 C-LOOK 함수의 방문 순서·총 이동을 구하세요. 큐를 [60,40]으로 바꾸면 SSTF는 어떻게 달라지나요? 트랙 범위 0~99에서 오른쪽 SCAN이 끝 99까지 간 뒤 마지막 요청 40에서 멈춘다는 별도 조건의 이동 거리도 비교하세요.

직접 계산한 뒤 풀이 확인

원 SSTF의 동률 선택은 min에 전달한 pending의 앞 원소여서 [40,60]은 50→40→60, [60,40]은 50→60→40입니다. 둘 다 10+20=30입니다. 오른쪽 먼저 C-LOOK은 입력 순서와 무관하게 50→60→40이며 복귀 20도 합쳐 30입니다. 선언한 SCAN은 50→60→99→40이라 10+39+59=108입니다. LOOK과 SCAN을 비교하려면 끝 트랙까지의 이동과 종료 조건을 명시해야 합니다. 새 유입이 없는 이 큐의 거리만으로 실제 디스크 응답 시간을 정하지 않습니다.

알고리즘 비교

알고리즘예제와 정책의 해석
FCFS이 요청열은 640 트랙. 도착 순서를 지키지만 항상 최장 이동은 아님
SSTF이 요청열은 236 트랙. 매 순간 가까운 요청을 고르며 전체 최적해를 보장하지 않음
SCAN시작 방향·끝 트랙·종료 기준을 정해야 거리를 비교할 수 있음
C-SCAN복귀 중에는 서비스하지 않음. 복귀 이동 비용도 포함
LOOK / C-LOOK물리 끝 대신 남은 요청의 끝을 방문. 새 요청 유입 정책도 공정성에 영향

코드의 출력은 실행 기록으로 제시하지 않습니다. 현재 요청열과 거리 합산 규칙을 고정한 시뮬레이션입니다.

같은 요청 큐라도 서비스 순서가 달라지면 헤드 이동 거리가 달라집니다

세 정책의 입력을 동일하게 둔다. C-LOOK의 복귀에도 실제 거리를 더한다. 각 단계의 값과 전환 이유를 비교합니다.

디스크 스케줄링 · 같은 입력

같은 요청 큐라도 서비스 순서가 달라지면 헤드 이동 거리가 달라집니다

시작 헤드 53, 요청 [98, 183, 37, 122, 14, 124, 65, 67]을 고정합니다. FCFS·SSTF·오른쪽 먼저 C-LOOK의 방문 순서와 이동 거리를 함께 비교합니다.

FCFS · 총 640 트랙

입력된 도착 순서를 그대로 서비스합니다.

FCFS의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 98, 183, 37, 122, 14, 124, 65, 67. 총 이동 거리 640 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작981183237312241451246657678

SSTF · 총 236 트랙

매 순간 현재 헤드에서 가장 가까운 남은 요청을 고릅니다.

SSTF의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 65, 67, 37, 14, 98, 122, 124, 183. 총 이동 거리 236 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작651672373144985122612471838

C-LOOK · 오른쪽 먼저 · 총 322 트랙

오른쪽 요청 끝 183에서 왼쪽 첫 요청 14로 복귀합니다. 그 구간에서는 요청을 서비스하지 않습니다.

C-LOOK · 오른쪽 먼저의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 65, 67, 98, 122, 124, 183, 14, 37. 총 이동 거리 322 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작651672983122412451836147378

FCFS · 총 640 트랙

입력된 도착 순서를 그대로 서비스합니다.

FCFS의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 98, 183, 37, 122, 14, 124, 65, 67. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 640트랙.트랙 번호위치0100200시작53198218333741225146124765867위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67

이동 거리: 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = 640

SSTF · 총 236 트랙

매 순간 현재 헤드에서 가장 가까운 남은 요청을 고릅니다.

SSTF의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 65, 67, 37, 14, 98, 122, 124, 183. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 236트랙.트랙 번호위치0100200시작53165267337414598612271248183위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183

이동 거리: 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59 = 236

C-LOOK · 오른쪽 먼저 · 총 322 트랙

오른쪽 요청 끝 183에서 왼쪽 첫 요청 14로 복귀합니다. 그 구간에서는 요청을 서비스하지 않습니다.

C-LOOK의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 65, 67, 98, 122, 124, 183, 14, 37. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 322트랙. 183에서 14로 돌아가는 점선은 중간 요청을 서비스하지 않는 복귀이고 그 거리 169도 합산한다.트랙 번호위치0100200시작53165267398412251246183714837위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 65 → 67 → 98 → 122 → 124 → 183 → 14 → 37

이동 거리: 12 + 2 + 31 + 24 + 2 + 59 + 169 + 23 = 322

요청은 처음부터 모두 대기하며 새 유입이 없는 예입니다. 총 거리는 연속 방문 위치 차이의 절댓값을 모두 더합니다. 넓은 화면의 가로 축은 시작+서비스 순서, 세로 축은 트랙 번호입니다. C-LOOK 점선 복귀 183 → 14의 거리 169도 합산합니다. 거리는 응답 시간이나 모든 요청열의 성능 순위를 뜻하지 않습니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 시작부터 마지막 서비스까지 진행합니다.
관계도의 보충 설명
전체 도표의 표기·관계·조건
구분전체 도표의 내용
관계 설명시작과 서비스 위치는 53, 98, 183, 37, 122, 14, 124, 65, 67. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 640 트랙.
관계 설명시작과 서비스 위치는 53, 65, 67, 37, 14, 98, 122, 124, 183. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 236 트랙.
관계 설명시작과 서비스 위치는 53, 65, 67, 98, 122, 124, 183, 14, 37. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 322 트랙. 183에서 14로 돌아가는 점선은 중간 요청을 서비스하지 않는 복귀이고 그 거리 169도 합산한다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
시작

세 정책의 입력을 동일하게 둔다.

  • 헤드·누적 거리 1: head 53
  • 헤드·누적 거리 2: 요청 [98,183,37,122,14,124,65,67]
  • 모든 요청 대기
처음 두 서비스

정책별 선두 선택이 갈린다.

  • 헤드·누적 거리 1: FCFS 53→98→183, 누적 130
  • 헤드·누적 거리 2: SSTF/CLOOK 53→65→67, 누적 14
  • 두 요청 처리
여섯 서비스 뒤

같은 정책을 계속 적용한 누적 상태다.

  • 헤드·누적 거리 1: FCFS 끝 124, 누적 579
  • 헤드·누적 거리 2: SSTF 끝 122, 누적 175
  • 헤드·누적 거리 3: CLOOK 끝 183, 누적 130
  • 각 정책에서 여섯 요청 처리; 두 요청은 아직 대기
마지막 서비스

C-LOOK의 복귀에도 실제 거리를 더한다.

  • 헤드·누적 거리 1: FCFS 끝 67 총 640
  • 헤드·누적 거리 2: SSTF 끝 183 총 236
  • 헤드·누적 거리 3: CLOOK 183→14→37 총 322
  • 모든 요청 소진; 거리≠응답시간

같은 요청 큐라도 서비스 순서가 달라지면 헤드 이동 거리가 달라집니다

세 정책의 입력을 동일하게 둔다. C-LOOK의 복귀에도 실제 거리를 더한다. 각 단계의 값과 전환 이유를 비교합니다.

디스크 스케줄링 · 같은 입력

같은 요청 큐라도 서비스 순서가 달라지면 헤드 이동 거리가 달라집니다

시작 헤드 53, 요청 [98, 183, 37, 122, 14, 124, 65, 67]을 고정합니다. FCFS·SSTF·오른쪽 먼저 C-LOOK의 방문 순서와 이동 거리를 함께 비교합니다.

FCFS · 총 640 트랙

입력된 도착 순서를 그대로 서비스합니다.

FCFS의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 98, 183, 37, 122, 14, 124, 65, 67. 총 이동 거리 640 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작981183237312241451246657678

SSTF · 총 236 트랙

매 순간 현재 헤드에서 가장 가까운 남은 요청을 고릅니다.

SSTF의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 65, 67, 37, 14, 98, 122, 124, 183. 총 이동 거리 236 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작651672373144985122612471838

C-LOOK · 오른쪽 먼저 · 총 322 트랙

오른쪽 요청 끝 183에서 왼쪽 첫 요청 14로 복귀합니다. 그 구간에서는 요청을 서비스하지 않습니다.

C-LOOK · 오른쪽 먼저의 헤드 이동왼쪽부터 시작 및 여덟 서비스 위치 53, 65, 67, 98, 122, 124, 183, 14, 37. 총 이동 거리 322 트랙. 가로 축은 방문 순서이며 시간 축이 아닙니다.010020053시작651672983122412451836147378

FCFS · 총 640 트랙

입력된 도착 순서를 그대로 서비스합니다.

FCFS의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 98, 183, 37, 122, 14, 124, 65, 67. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 640트랙.트랙 번호위치0100200시작53198218333741225146124765867위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67

이동 거리: 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = 640

SSTF · 총 236 트랙

매 순간 현재 헤드에서 가장 가까운 남은 요청을 고릅니다.

SSTF의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 65, 67, 37, 14, 98, 122, 124, 183. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 236트랙.트랙 번호위치0100200시작53165267337414598612271248183위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183

이동 거리: 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59 = 236

C-LOOK · 오른쪽 먼저 · 총 322 트랙

오른쪽 요청 끝 183에서 왼쪽 첫 요청 14로 복귀합니다. 그 구간에서는 요청을 서비스하지 않습니다.

C-LOOK의 세로 서비스 순서와 트랙 위치시작과 서비스 위치는 53, 65, 67, 98, 122, 124, 183, 14, 37. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 322트랙. 183에서 14로 돌아가는 점선은 중간 요청을 서비스하지 않는 복귀이고 그 거리 169도 합산한다.트랙 번호위치0100200시작53165267398412251246183714837위→아래: 서비스 순서간격은 경과 시간이 아님

시작 위치 → 서비스 순서

53 → 65 → 67 → 98 → 122 → 124 → 183 → 14 → 37

이동 거리: 12 + 2 + 31 + 24 + 2 + 59 + 169 + 23 = 322

요청은 처음부터 모두 대기하며 새 유입이 없는 예입니다. 총 거리는 연속 방문 위치 차이의 절댓값을 모두 더합니다. 넓은 화면의 가로 축은 시작+서비스 순서, 세로 축은 트랙 번호입니다. C-LOOK 점선 복귀 183 → 14의 거리 169도 합산합니다. 거리는 응답 시간이나 모든 요청열의 성능 순위를 뜻하지 않습니다.

이 예의 조건

  • 본문과 전체 도표의 예를 따라 시작부터 마지막 서비스까지 진행합니다.

관계도의 보충 설명

전체 도표의 표기·관계·조건
구분전체 도표의 내용
관계 설명시작과 서비스 위치는 53, 98, 183, 37, 122, 14, 124, 65, 67. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 640 트랙.
관계 설명시작과 서비스 위치는 53, 65, 67, 37, 14, 98, 122, 124, 183. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 236 트랙.
관계 설명시작과 서비스 위치는 53, 65, 67, 98, 122, 124, 183, 14, 37. 가로 좌표는 0부터 200까지 같은 트랙 번호 척도이고 세로 좌표는 시작과 서비스 순서 1부터 8이다. 점과 연결선은 순서에 따른 헤드 위치이며 경과 시간이 아니다. 총 거리 322 트랙. 183에서 14로 돌아가는 점선은 중간 요청을 서비스하지 않는 복귀이고 그 거리 169도 합산한다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
시작

세 정책의 입력을 동일하게 둔다.

  • 헤드·누적 거리 1: head 53
  • 헤드·누적 거리 2: 요청 [98,183,37,122,14,124,65,67]
  • 모든 요청 대기
처음 두 서비스

정책별 선두 선택이 갈린다.

  • 헤드·누적 거리 1: FCFS 53→98→183, 누적 130
  • 헤드·누적 거리 2: SSTF/CLOOK 53→65→67, 누적 14
  • 두 요청 처리
여섯 서비스 뒤

같은 정책을 계속 적용한 누적 상태다.

  • 헤드·누적 거리 1: FCFS 끝 124, 누적 579
  • 헤드·누적 거리 2: SSTF 끝 122, 누적 175
  • 헤드·누적 거리 3: CLOOK 끝 183, 누적 130
  • 각 정책에서 여섯 요청 처리; 두 요청은 아직 대기
마지막 서비스

C-LOOK의 복귀에도 실제 거리를 더한다.

  • 헤드·누적 거리 1: FCFS 끝 67 총 640
  • 헤드·누적 거리 2: SSTF 끝 183 총 236
  • 헤드·누적 거리 3: CLOOK 183→14→37 총 322
  • 모든 요청 소진; 거리≠응답시간

SSD의 등장

SSD(Solid State Drive)는 반도체(NAND 플래시) 기반의 저장 장치로, 기계적 움직임이 없습니다.

탐색 시간과 회전 지연이 0입니다.

다음 수치는 특정 장치의 보장 성능이나 최신 제품 비교가 아니라 규모를 설명하는 예시입니다.

특성HDDSATA SSDNVMe SSD
순차 읽기~200 MB/s~550 MB/s~3,500 MB/s
순차 쓰기~200 MB/s~520 MB/s~3,000 MB/s
랜덤 읽기 (IOPS)~100~90,000~500,000
랜덤 쓰기 (IOPS)~100~80,000~400,000
지연 시간3~15ms~0.1ms~0.02ms

SSD에서는 전통적인 디스크 스케줄링의 의미가 크게 줄어듭니다.

기계적 탐색은 없지만 플래시 채널·캐시·가비지 컬렉션·부하에 따라 지연이 달라집니다. 같은 장치의 모든 접근 시간이 동일하지는 않습니다.

NVMe SSD는 PCIe 버스에 직접 연결되어 SATA 인터페이스의 병목을 제거합니다.

NVMe는 여러 제출·완료 큐를 지원합니다. 큐 개수와 큐당 엔트리 수, 실제 장치 한도를 구분해야 하며 숫자 하나를 SATA와 NVMe의 공통 큐 깊이처럼 비교하지 않습니다.


Linux I/O 스케줄러

Linux에서 I/O 요청은 커널의 I/O 스케줄러를 거칩니다.

none: blk-mq에서 추가 I/O 스케줄러 없이 하드웨어 큐로 요청을 전달하는 선택입니다. 구형 noop과 같은 이름의 구현이 아니며 전체 요청 완료 순서가 FIFO라는 보장도 아닙니다. 장치 특성과 부하에 따라 낮은 오버헤드가 도움이 됩니다.

deadline (mq-deadline): 각 요청에 만료 시간(읽기 500ms, 쓰기 5초)을 부여합니다.

오래 기다린 요청을 우선하는 정책과 정렬·병합을 함께 사용합니다. 만료 설정은 장치의 완료 시간 상한을 보장하는 deadline이 아닙니다.

실제 사용 가능 스케줄러와 설정은 blk-mq 및 해당 장치의 sysfs에서 확인합니다.

CFQ (Completely Fair Queuing): 프로세스별로 공평하게 I/O 대역폭을 분배합니다.

데스크톱 환경에서 반응성을 유지합니다.

커널 5.0에서 제거되었습니다.

BFQ (Budget Fair Queueing): CFQ의 후계자.

프로세스별 I/O 예산을 관리합니다.

대화형 작업의 지연과 프로세스 간 공정성을 개선하려는 정책이며 모든 부하에서 지연을 없애는 보장은 아닙니다.

kyber: 지연 시간 기반 스케줄러.

읽기/쓰기의 목표 지연 시간을 설정하고, 큐 깊이를 자동 조절합니다.

목표 지연과 처리량을 실제 부하에서 비교해 선택합니다.

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

# NVMe SSD에 none 설정
echo "none" > /sys/block/nvme0n1/queue/scheduler

# HDD에 mq-deadline 설정
echo "mq-deadline" > /sys/block/sda/queue/scheduler

# I/O 성능 모니터링
iostat -xz 1 5
# %util: 장치 사용률, await: 평균 응답 시간
# await은 대기와 서비스 시간을 포함; 요청 크기·큐·처리량과 함께 해석

I/O 성능 최적화 실무

Zero-Copy

단순한 파일 읽기 후 소켓 쓰기 모형은 다음 이동 경로로 설명할 수 있습니다. 실제 복사 횟수는 캐시·장치 지원에 따라 다릅니다.

디스크→커널 버퍼→사용자 버퍼→커널 소켓 버퍼→NIC.

sendfile은 파일 데이터를 사용자 공간으로 가져왔다가 다시 넘기는 복사를 피할 수 있습니다. DMA를 포함한 모든 이동이 사라지거나 항상 정확히 두 번만 남는다는 뜻은 아닙니다.

Nginx, Kafka 등 고성능 서버가 사용합니다.

I/O 배치와 병합

I/O 스케줄러는 인접한 블록에 대한 개별 요청을 병합(Merge)합니다.

인접하고 병합 조건을 충족하는 4KiB 요청 네 개는 16KiB 요청으로 묶을 수 있습니다.

애플리케이션 레벨에서도 작은 쓰기를 모아서 큰 쓰기로 배치하면 성능이 크게 향상됩니다.

ionice

프로세스의 I/O 우선순위를 설정합니다. 효과는 사용 중인 스케줄러와 I/O 경로의 지원에 따라 달라집니다.

백업 작업은 낮은 우선순위로, 데이터베이스는 높은 우선순위로 설정하면 서로 간섭이 줄어듭니다.

ionice_example.sh
# Idle 클래스로 백업 실행 (다른 I/O가 없을 때만 실행)
ionice -c 3 rsync -a /data /backup

# Best-effort 클래스의 높은 우선순위로 DB 관련 I/O
ionice -c 2 -n 0 mysqld

다음 장에서는 OS가 자원을 보호하고 시스템의 보안을 유지하는 방법을 다루겠습니다.

위 셸 명령은 장치 이름과 권한을 확인해 적용할 설정 예시이며 이번 작업에서 실행하지 않았습니다.

디스크 요청 큐, 스케줄러 선택, SSD 예외, I/O 튜닝 지표를 함께 점검합니다.