Linux I/O 스케줄러 학습 정리
1. HDD 성능 최적화: 병합(Merge)과 정렬(Sort)
HDD는 물리적 헤드 이동 비용이 크기 때문에 커널 I/O 스케줄러가 두 가지 최적화를 수행한다.
병합 (Merge)
인접한 I/O 요청을 하나로 합쳐 헤드 이동 횟수와 시스템 콜 오버헤드를 줄인다.
요청 A: sector 100~107
요청 B: sector 108~115
→ 병합: sector 100~115 한 번에 처리
- Back merge: 새 요청이 기존 요청 뒤에 붙는 경우 (가장 일반적)
- Front merge: 새 요청이 기존 요청 앞에 붙는 경우
정렬 (Sort) — 엘리베이터 알고리즘
요청을 섹터 번호 순으로 정렬해 헤드가 한 방향으로 쭉 이동하며 처리한다.
입력 순서: 500 → 100 → 300 → 800
정렬 후: 100 → 300 → 500 → 800
→ Seek time(탐색 시간) 최소화
핵심: SSD는 탐색 시간이 없으므로 정렬이 오히려 지연을 유발 → NOOP/none 스케줄러 권장
2. I/O 스케줄러와 cgroup의 관계
cgroup이 **정책(얼마나 쓸 수 있는지)**을 정의하면, I/O 스케줄러가 그 정책을 실제 디스크 요청 순서로 구현한다.
프로세스 → cgroup (그룹화) → I/O 스케줄러 (자원 배분)
cgroup v1 — blkio 서브시스템
| 제어 방식 | 스케줄러 의존 | 설명 |
|---|---|---|
blkio.weight |
CFQ 필수 | 비례 가중치 기반 배분 |
blkio.throttle.* |
무관 | 절대값 속도 제한 (BPS/IOPS) |
cgroup v2 — io 서브시스템
blkio→io로 통합, 스케줄러 독립적 설계- BFQ 스케줄러와 결합 시 컨테이너/프로세스별 I/O QoS 보장
- Docker/k8s 기본 환경
| 구분 | cgroup v1 | cgroup v2 |
|---|---|---|
| 서브시스템 | blkio |
io |
| 스케줄러 의존성 | CFQ 필수 (weight 사용 시) | 독립적 (BFQ 권장) |
| 컨테이너 환경 | 제한적 | Docker/k8s 기본 |
3. Deadline 스케줄러가 데이터베이스에 적합한 이유
Deadline의 3가지 큐
1. Sort queue — 섹터 순 정렬 처리 (평상시)
2. Read FIFO — 만료 시간 500ms
3. Write FIFO — 만료 시간 5000ms
평소엔 Sort queue로 처리하다가, FIFO queue에서 만료된 요청이 생기면 즉시 우선 처리.
데이터베이스에 적합한 3가지 이유
| 이유 | 설명 |
|---|---|
| Starvation 방지 | 대량 쓰기 중에도 읽기 요청이 500ms 이상 굶지 않음 |
| 읽기/쓰기 만료 분리 | 읽기(500ms) 짧게, 쓰기(5000ms) 길게 → DB 특성과 일치 |
| 예측 가능한 지연 | 최악의 경우에도 만료 시간 이내 처리 보장 |
CFQ의 문제점
CFQ는 공평한 배분이 목적이라, DB 백그라운드 쓰기(checkpoint)가 큐를 점유하면 SELECT 요청이 starvation에 빠질 수 있다.
스케줄러 선택 기준 요약
| 스케줄러 | 적합한 환경 | 특징 |
|---|---|---|
| CFQ | 일반 서버, 다중 프로세스 | 프로세스별 공평한 I/O |
| Deadline | 데이터베이스, 읽기 응답 민감 환경 | Starvation 방지, 예측 가능한 지연 |
| NOOP | SSD, NVMe | 정렬 없음, 하드웨어에 위임 |
| BFQ | 컨테이너, cgroup v2 환경 | 공정한 대역폭 배분 |