brunch

You can make anything
by writing

C.S.Lewis

by 박지훈 Jun 22. 2018

Linux iostat





1-1 : iostat 소개

1-2 : iostat 사용 방법

1-3 : iostat %util, svctm 지표 오류 

1-4 : 마무리 정리...










1-1 iostat 소개

-  iostat 이란?

한 줄 요약 : Disk의 read/write 통계지표 및 CPU 사용률, queue 대기열 길이 등 io에 대한 지표를 실시간으로 볼 수 있는 유용한 tool이다.


Linux kernel에서 IO발생 시 CPU와 device의 사용률 정보를 [/proc/diskstats, /sys/block/디아비스/stat]에 저장한다. 

kerenl 에선 해당 diskstats 파일에 기록된 정보를 바탕으로 그 값들을 계산해  iostat 지표에 찍어 준다.

iostat 필드 중 대표적으로 많이 보는 %util  필드의 경우 아래와 같이 계산하여 출력한다.

 [ %util : io request에 대한 응답 시간을  통해 산출, 응답 시간은 tot_ticks을 이용해 계산하며, io 함수

호출 시마다 디스크가 처리한 응답 시간(tick) 만큼 더하는 방식.]

1-1 이미지

 + %util은 (1-1 이미지) io가 시작된 시점과 완료된 시점을 추적하여 계산합니다. a=>b, c=>d 사이의 시간을 카운터에 누적하며, 해당 값을 계산하는 코드는 아래 (이미지 1-2)와 같습니다.

1-2 이미지

in_flight 인 경우 now - then 값이 추가되는 방식. 




- iostat 설치 방법

 + CentOS : yum install -y sysstat

 + Ubuntu : apt-get install -y sysstat

 + 최신 버전 설치 : http://sebastien.godard.pagesperso-orange.fr/download.html















1-2 iostat 옵션 설명


제가 주로 쓰는 옵션은 아래와 같습니다.

iostat -dxm 1 -p ALL | grep -iw "device\|sda4\|nvme0n1" | awk '{now=strftime("%Y-%m-%d %T "); print now $0}'


-d : 디스크 사용량 정보를 출력

-x : 확장 정보 출력

-m : 초당 throughput. MB/s로 출력

-1 : 뒤에 숫자는 iostat 출력 텀의 초이다.

-p ALL : 시스템에 모든 디바이스를 출력

- 비고 : 위 커멘드는 "Device" 제목 커멘드 밑에 "sda4"와 "nvme0n1" 디바이스를 시간을 출력하면서 디버깅하겠다. [1-3 이미지 참조]

1-3


- iostat 출력 값에 대한 설명

============================================================================

rrqm/s : 큐에 대기 중인 초당 읽기 요청 수.

(/proc/diskstats field: #2)

The number of read requests merged per second that were queued to the device. 


wrqm/s  : 큐에 대기 중인 초당 쓰기 요청 수.

(/proc/diskstats field: #6)

The number of write requests merged per second that were queued to the device. 


r/s : 초당 읽기 섹터 수 

(/proc/diskstats field: #1)

The number of read requests that were issued to the device per second. 

OS의 block layer가 아니라 Process가 OS의 커널 영역으로 read/write 함수를 호출한 횟수


w/s : 초당 쓰기 섹터 수 

(/proc/diskstats field: #5)

The number of write requests that were issued to the device per second. 

OS의 block layer가 아니라 Process가 OS의 커널 영역으로 read/write 함수를 호출한 횟수


rMB/s : 초당 읽기 처리 크기 (r/s X 섹터 크기(블록 사이즈 크기))

(/proc/diskstats field: #3)

The number of megabytes read from the device per second. 


wMB/s : 초당 쓰기 처리 크기  (w/s X 섹터 크기(블록 사이즈 크기))

(/proc/diskstats field: #7)

The number of megabytes written to the device per second. 


avgrq-sz : 요청 건수의 평균 크기 ( 1 = 512byte )

(/proc/diskstats field: 없음)

The average size (in sectors) of the requests that were issued to the device. 


avgqu-sz : 해당 Device에 발생된 request들의 대기 중인 queue의 평균 length

(/proc/diskstats field: #11)

The average queue length of the requests that were issued to the device. 

 + avgqu-sz = await / svctm * %util

상세 설명 : svgqu-sz는 io스케줄러 queue + 디스크 queue의 대기열을 포함된 평균 수치이다.


+ io 스케줄러 queue depth 경로 : ex) /sys/block/nvme0n1/queue/nr_requests
+ 디스크 queue depth 경로 : ex) /sys/devices/pci0000:00/0000:00:01.0/0000:03:00.0/host0/target0:2:0/0:2:0:0/queue_depth

만약 avgqu-sz 수치보다 await 수치가 훨씬 높으면 디스크 쪽에서 병합이 있다고 판단하면 된다.


The avgqu-sz is the average number of io contained within both the io scheduler queue and storage lun queue. If the reported avgqu-sz in the sample is much less than the allowed lun queue_depth (and the sample time is small so averaging isn't hiding a much larger peak queue size), then there is little time spent within the scheduler queue. The scheduler will continue passing io to the driver while the number of io still outstanding to the driver (io currently being worked on by storage) remains under the lun's queue_depth limit. In such cases, then the await time is dominated by storage servicing time alone. Under these circumstances(low avgqu-sz), high await time is due to storage side issues.



await : 레이턴시 값 (svctm + waiting in the queue)

(/proc/diskstats field: #4)

The average time (in milliseconds) for I/O requests issued to the device to be served. This includes the time spent by the requests in queue and the time spent servicing them. 

 + await = svctm + however_long_in_quere

상세 설명 : await는 io 완료 시간 + 스케줄러에서 대기 큐에 소비된 시간을 합친 값입니다.

해당 값은 스케줄러, 드라이버, 컨트롤러, 실제 물리 디스크 단 까지 모든 대기 시간이 포함됩니다.



svctm 

(/proc/diskstats field: 없음)

The average service time (in milliseconds) for I/O requests that were issued to the device. Warning! Do not trust this field any more. This field will be removed in a future sysstat version. 

svctm의 경우 병렬 처리에 대한 경우를 고려해 계산됩니다만, 단순히 10개의 io를 던지고 10ms 안에 처리됐다면... 1개의 io는 1ms로 계산해 svctm 필드에 1.00으로 표기되는 방식입니다.



%util 

(/proc/diskstats field: #10)

Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value is close to 100%. 

Network Filesystem report 

The Network Filesystem (NFS) report provides statistics for each mounted network filesystem. The report shows the following fields:

Disk 가 버틸 수 있는 한계치를 %로 표시해 주는 필드입니다.

이는 스핀들 디스크에선 잘 처리해서 보여 주지만, 병렬 io처리를 하는 nand제품이나 cache 가 달린 Raid 구성 또는 스토리지에서는 신용할 수 없는 정보입니다. (1-3 단락에서 자세히 설명)


============================================================================


아래 예제로 설명 (1-4 이미지)

1-4

- 부하 : 4k 블록 사이즈로 read 10MB, write 10MB 부하를 줬다.

 + r/s : 4k x 1024 = 4MB (rMB/s) 

 + w/s : 4k x 1024 = 4MB (wMB/s)

 + avgrq-sz : 8 x 512 (byte) = 4kb (부하준 블록 사이즈 크기가 나온다. 만약 8k 블록 사이즈로 부하를 주면 16으로 표시될 것이다.)

 + %util : 1025(r/s) + 1025(w/s) / (0.32(svctm) / 10)


iostat 지표로 부하(read/write) 주는 job의 블록 크기, 부하 크기, 레이턴시 등의 정보를 볼 확인할 수 있다.

근데??? 저거 Nvme 디스크인 거 같은데 저 정도 (read&write) 4MB 정도로 %util : 65% 나 될까?? 이건 

1-4 순서에서 자세히 설명하겠다.


흔히들 iostat 지표를 볼 때는 뭔가 disk 느리다던가, 문제가 있을 때 보게 된다. 의미 있는 지표를 보는 방법은

1. 장착된 디스크의 종류 (sata, sas, ssd, nvme, 또는 raid로 구성됐는가? raid는 캐시가 달렸고 write-back 모드인가? 를 파악한다.)

2. 현재 구성된 디스크의 성능 한계치를 파악한다. (ex. ssd의 경우 read 300MB에 write 80MB 정도)

3. rMB/s, wMB/s로 현재 부하 크기를 보고, await 지표가 1 (ms) 이상 넘는지 등을 확인한다.

 + Nand 제품의 경우 await 값을 유심히 볼 필요가 있다. 해당 값은 레이턴시 지표로 보면 되고, 디스크 부하는 크지 않은데 await 값이 순간 올라가는 경우가 종종 있다. 



















1-3 iostat %util, svctm 지표 오류


iostat 은 이미 구글에 많이 나온 정보이고, 사실 해당 단락 때문에 블로그를 쓰게 됐습니다.


왜??? nvme 서버에서 io부하도 적은 데 %util 이 높게 나오지???? (이게 사건의 발단...)


 - 스핀들 디스크 (SATA, SAS 등)의 경우 플래터가 돌면서 헤더가 지정된 섹터를 찾아 한번에 한 가지 job씩 처리합니다. 즉 병렬 처리가 안 되는 구조이며, 이는 iostst 지표로 확인히 정확한 지표라 판단할 수 있습니다.

하지만 Nand (Nvme, ssd)의 경우 아래 (1-5 이미지)와 같이 die 칩셋이 채널로 구성되며, 각 채널별로 io를 분산 처리 즉 병렬 처리가 가능합니다.

병렬 처리하여 퍼포먼스를 높인 경우 iostat에서 이를 반영하여 계산하지 못합니다.

1-5

이게 무슨 소리냐면, Nand 제품에선 적은 부하를 줘도 %util 에선 과도하게 높은 지표를 출력할 수 있다는 얘기입니다.


아래 (1-6 이미지)는 nvme 디스크에 (fio 테스트, 4k 블록 사이즈, radomwrite 부하) numjob을 늘려가며 테스트 한 값입니다.

보시면 job=3부터 이미 %util 은 최대치를 뿌려주고 있습니다. 하지만 부하를 더 줄수록 write 성능은 계속 올라갑니다. 즉 %util 필드 자체는 의미가 없게 됩니다. 

1-6



참고 사이트 : 

https://brooker.co.za/blog/2014/07/04/iostat-pct.html

https://coderwall.com/p/utc42q/understanding-iostat





2019년 3월 22일 추가 내용


- rhel 7.6 + nvme 조합에서 none io스케줄러 사용 시 %util 과 svstm 지표가 io 발생 시 그 수치에 관계없이 최대값 출력합니다. (nvme default 스케줄러가 none입니다.)

원인은 커널에서 /proc/diskstats 수집에 대해 계산 오류이고, 곧 해당 이슈가 패치된 커널이 나올 예정이라고 합니다. (nvme 파티션이 통 파티션이 아닌 나눈 경우 개별 파티션에 대한 iostat 지표 (iostat -p ALL)는 해당 이슈에 적용되지 않습니다.)


 - rhel 7.5 (3.10.0-862 이상)부터 blk-mq io 스케줄러 (kyber, mq-deadline) 멀티 큐잉 스케줄러 사용 시 기존에 문제가 된 nand 레벨에서의 병렬 처리로 인한 %util 지표 오류가 개선됩니다.


해당 내용의 자세한 설명은 Lunatine 님의 블로그를 참고하세요.
















1-3 마무리 정리...



iostat 은 Disk에 문제가 발생할 때 주로 보게 되는 툴입니다.

하지만 Nvme 나 SSD와 같은 제품군은 iostat의 %util 필드로 판단 하기엔 신용도가 낮습니다. (멀티 큐잉 io스케줄러 사용 시 어느 정도 신뢰 지표로 사용할 수 있다.) 


%util 지표 외에 await과 read/write throughput (  xx MB/s ) 지표와, nand 제품의 성능 한계치 (별도의 부하 테스트나 제품 공식 성능 자료 참고)와 비교하며 모니터링에 참고하는 것도 좋다.


iostat 외에 iotop, blktrace, vmstat, perf  등 다양한 툴 (아래 이미지 참고) 들로 다른 레벨까지 모니터링할 수 있는 툴을 같이 보면서 병목 구간을 파악하고, nand 제품 자체의 문제로 판단될 경우 fio tool 등의 io 부하 툴로 비슷한 환경을 만들어 증상 재현해보는 것도 좋다. (nand 제품은 (특히 nvme) 아직까지 펌웨어 이슈로 인한 문제가 많다.)



bcc-tools의 경우 4 버전 이상의 커널에서 가능. (centos 7.6은 백포트로 일부 지원)

 

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari