0x0102
I/O 작업이 지나가는 관문, I/O 스케줄러 본문
I/O 스케줄러는 디스크 성능을 최대화하기 위해 구현된 커널의 일부이며,
모든 작업은 스케줄러를 통해 블록 디바이스에 전달된다.
이 때, 병합과 정렬이라는 두가지 방식을 사용하며 알고리즘에 따라 성능이 조절될 수도 있다.
이번에는 I/O 스케줄러의 역할과 알고리즘들, 워크로드를 확인해보자.
1. I/O 스케줄러의 필요성
디스크와 관련된 작업은 시간이 오래 소요되기 때문에 커널은 스케줄러를 통해 성능을 높이고자 한다.
이 때 병합과 정렬 두 가지 방법을 사용한다.
1) 병합
여러 개의 요청을 하나로 합치는 것
Request Queue에 여러 요청을 블록 디바이스의 Dispatch Queue에 그대로 넘겨주는 대신, 하나로 합쳐 넘겨줌으로써 디스크로의 명령 전달을 최소화하고 성능을 향상시킬 수 있다.
2) 정렬
I/O 요청들을 정렬없이 순서대로 처리하게 되면 블록 이동이 잦아지고 불필요한 이동이 발생한다.
따라서 정렬을 통해 섹터 순서대로 최적의 경로를 갈 수 있도록 재배치한다.
2. I/O 스케줄러 설정
현재 시스템에 적용 가능한 스케줄러와 설정되어있는 스케줄러 정보는 cat scheduler로 확인할 수 있다.
[]로 표시된 부분이 현재 설정된 스케줄러이고 이외의 것들이 설정 가능한 스케줄러이다.
변경은 echo를 통해 가능하다.
3. cfq I/O 스케줄러
cfq(Completely Fair Queueing) // 프로세스들이 발생시키는 요청들이 모든 프로세스에서 공정하게 실행
cfq 스케줄러는 나뉜 I/O 요청들을 cfq 큐에 넣고 각 동일한 time slice를 할당한 다음 이 값을 기준으로 큐들을 순차처리한다.
그래서 모든 프로세스들에 동등한 I/O 처리 기회를 주지만 일부 I/O를 많이 일으키거나 빨리 처리되어야하는 프로세스들의 경우 차례를 기다려야 하므로 성능이 낮아질 가능성이 있다.
cfq 스케줄러에서 튜닝 가능한 값은 12가지가 있다.
1) back_seek_max
현재 디스크의 헤드가 위치한 곳을 기준으로 backward seeking의 최댓값
값 기준 안에 들어오는 요청을 다음 요청으로 간주하여 처리
인접한 섹션의 요청을 바로 처리하여 헤더의 움직임을 줄일 수 있지만 다른 요청이 밀릴 수 있어 적당한 값을 유지하는 것이 좋다.
만약 시스템에 순차 쓰기가 주를 이룬다면 이 값을 줄이는 게 좋다.
2) back_seek_penatly
1의 페널티를 정의
같은 이동 거리임에도 헤더 위치에 따라 작은 번호로 이동하는 것이 더 무겁고 성능에 좋지 않은 작업이라고 인지
3) fifo_expire_async (주로 쓰기)
비동기적인 I/O 작업에 대한 만료시간 정의
4) fifo_expire_sync (주로 읽기)
동기적인 I/O 작업에 대한 만료시간 정의
5) group_idle
group_idle이 설정되어 있다면 같은 cgroup안에 포함된 프로세스들에 대해 큐를 이동할 때 대기 없이 바로 다음 큐로 넘어가도록 동작
그러나 같은 cgroup 안의 요청을 처리하고 다른 cgroup으로 이동할 때 group_idle에 정의된 시간만큼 대기
6) group_isolation
서로 다른 cgroup 간의 차이를 명확하게 해주며 기본값은 0
1로 설정하면 임의접근도 cgroup 값의 영향을 받게 되고 각 cgroup 분류가 더 명확해진다.
7) low_latency
I/O 요청을 처리하다가 발생할 수 있는 대기 시간을 줄이는 역할
boolean으로 0이나 1, 즉 disable/enable를 의미하며 이 값으로 timeslice를 조절한다.
성능에 가장 큰 영향을 끼치는 요소로 생각된다.
8) slice_idle
cfq는 큐 처리를 완료하고 바로 다음 큐로 넘어가지 않고 slice_idle에 설정된 시간만큼 기다린다.
다시 요청이 오면 디스크 헤드 움직임을 최소화하여 디스크 접근시간을 줄일 수 있지만
아무 요청도 오지 않는다면 기다리는 시간은 버려지게 된다.
9) slice_sync
time slice의 기준 값 중 하나로 sync 요청에 대한 time slice 기준
큐에 sync 작업이 하나라도 있으면 해당 큐의 time slice는 이 값을 따라간다.
10) slice_async
slice_sync와 기능은 동일하지만 큐에 async 요청이 있을 때 설정되는 time slice 기준 값
11) slice_async_rq
cfq가 큐에서 한번에 꺼내 dispatch queue에 넘기는 async 요청의 최대 개수
12) quantum
slice_async_rq와 반대로 sync 요청을 꺼내 dispatch에 넘기는 최대 개수
4. deadline I/O 스케줄러
I/O 요청별로 완료되어야하는 deadline을 갖고 있는 스케줄러
+) 반드시 그 시간 안에 완수될 수 잇다는 것을 보장하는 값은 아님
deadline 스케줄러에서 튜닝 가능한 값은 5가지가 있다.
1) fifo_batch
한번에 dispatch queue를 통해 실행할 I/O 요청 개수
기본값은 16개로 16개가 하나의 batch로 간주됨
2) front_merges
현재 헤더 위치의 앞쪽으로 I/O 요청이 발생하는 경우 탐색하는 값
boolean 형태로 기본값은 1
워크로드가 순차 쓰기 혹은 읽기 일때 0으로 설정하면 성능이 조금 더 향상된다.
3) read_expire
발생한 요청 중 read 요청에 대한 deadline을 결정할 때 사용하는 값
기본값은 500ms
4) write_expire
발생한 요청 중 write 요청에 대한 deadline 결정
기본값은 5000ms
5) writes_starved
위에서 알 수 있듯 deadline 스케줄러가 읽기 요청 처리를 더 선호하기 때문에 쓰기 요청 처리가 지연될 수 잇다.
이 때 읽기와 쓰기 요청 사이 밸런스를 조절하는 역할을 한다.
단위는 횟수이며 기본값은 2이다. (읽기 2번에 처리 1번 처리)
5. noop I/O 스케줄러
병합만 하는 I/O 스케줄러
큐도 하나만 존재하며 인입된 I/O 요청에 대해 병합 여부만 확인 후 가능하다면 병합 작업을 한다.
별도의 섹터별 정렬 작업은 하지 않는다.
이는 플래시 디스크의 경우 정렬하는 것이 성능을 더 악화시키므로 플래시 디스크 경우에 권고된다.
별도의 튜닝할 수 있는 값은 존재하지 않는다.
6. cfq와 deadline의 성능 테스트
각 스케줄러들은 나름의 특성이 있어 워크로드에 따라 결정해야한다.
I/O요청이 하나만 온다면 큰 차이가 없겠지만 여러 요청이 온다면 차이가 발생한다.
cfq는 다수의 프로세스들의 요청을 공평하게 분배해서 처리하지만, deadline은 요청이 언제 발생했냐가 기준이며
임의 접근이 많이 발생하는지, 순차 접근이 많이 발생하는지에 따라 워크로드의 차이도 성능 차이를 일으킬 수 있기 때문이다.
테스트 결과
웹 서버(순차 접근이 많고 I/O요청이 많지 않음) - 스케줄러가 성능에 큰 영향을 주지 않음
파일 서버(임의 접근이 많고 I/O요청이 많을 수 있음) - deadline 스케줄러가 더 좋은 성능을 보임
+) 동영상 스트리밍이나 인코딩 서버는 사용자들의 요청을 균등하게 처리하는 cfq가 유리하며 DB서버와 같이 특정 프로세스가 많은 양의 요청을 일으키는 경우에는 deadline 스케줄러가 더 효율적임
7. I/O 워크로드 살펴보기
현재 시스템에서 발생한 I/O워크로드는 iotop 명령으로 확인할 수 있다.
'Study > DevOps' 카테고리의 다른 글
DevOps - dirty page가 I/O에 끼치는 영향 (1) | 2024.02.05 |
---|---|
DevOps - TCP 재전송과 타임아웃 (0) | 2024.02.02 |
DevOps - TCP Keepalive를 이용한 세션 유지 (0) | 2024.02.01 |
DevOps - TIME_WAIT 소켓이 서비스에 미치는 영향 (0) | 2024.01.29 |
DevOps - NUMA, 메모리 관리 새로운 세계 (1) | 2024.01.26 |