Iostat to narzędzie do monitorowania wykorzystania dysku twardego w naszym systemie. Przy jego pomocy zobaczymy wszystkie informacje o stanie naszego urządzenia i zdiagnozujemy ewentulane wąskie gardło.

Najwolniejszym elementem systemów komputerowych od zawsze były pamięci masowe. Wystarczy powiedzieć, że czas dostępu do pamięci cache procesora mierzymy w pojedynczych nanosekundach, dostęp do pamięci RAM w dziesiątkach nanosekund, a czas dostępu do informacji zapisanych na klasycznym dysku twardym w milisekundach. Różnica więc jest ogromna.

Jednym z narzędzi jakim możemy monitorować wydajność dysku jest iostat, będący częścią pakietu sysstat. Jak sama nazwa wskazuje służy ono do pomiarów parametrów związanych z urządzeniami wejścia/wyjścia (I/O).

Przykładowo pomiar obciążenia dysku sda w interwałach 10-cio sekundowych uruchamiamy następująco:

root@server:~# iostat -cx -d sda 10
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
 2.35    0.00    0.85    0.40    0.00   96.39
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
 sda               0.00     2.00    0.00    1.60     0.00    20.80    26.00     0.03   21.50    0.00   21.50  11.50   1.84

Zajmiemy się na razie linią Device:

  • rrqm/s  oraz wrqm/s – średnia liczba połączonych żądań odczytu i zapisu wysłanych na sekundę do urządzenia
  • r/s oraz w/s – średnia liczba żądań odczytu i zapisu wysłanych na sekundę do urządzenia,
  • rkB/s oraz wkB/s – średnia liczba kilobajtów na sekundę odczytanych i zapisanych w urządzeniu,
  • avgrq-sz – średnia liczba sektorów na żądanie (zarówno odczyt jak i  zapis) – (rsec + wsec) / (r + w),
  • avgqu-sz – średnia długość kolejki żądań wysłanych do urządzenia,
  • await – średni czas oczekiwania na wykonanie żądania wysłanego do urządzenia. Obejmuje zarówno czas spędzony w kolejce do urządzenia jak i czas na realizację żądania przez urządzenie – await = czas_spędzony_w_kolejce + svctim,
  • svctim – średni czas w jakim urządzenie wykonało zlecone żądanie,
  • %util – procent swojego czasu jaki urządzenie poświęciło na realizację żądań
  • .

Pracę naszego systemu możemy więc scharakteryzować następująco:

  • średnio w ciągu sekundy system wysyłał do urządzenia sda 1.6 żądań zapisu,
  • średni czas oczekiwania (uwzględniając kolejkę) na zrealizowanie żądania wyniósł 21.50ms
  • w kolejce na realizację żądanie spędziło średnio 21.50ms – 11.50ms = 10.00ms
  • urządzenie średnio realizowało żądanie w czasie 11.50ms
  • urządzenie średnio 1.84% swojego czasu poświęciło na realizację żądań

Stwórzmy teraz plik o wielkości 10GB, w sposób nieco obciążający serwer i przyjrzyjmy się najważniejszym parametrom:

root@server:~# dd if=/dev/zero of=test.img bs=1024 count=10240000
 root@server:~# iostat -cx -d sda 10
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
 1.97    0.00    9.80   10.84    0.00   77.40
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
 sda               0.00     7.70    7.70  167.50    31.60 82796.80   945.53    57.11  318.19    6.23  332.53   5.01  87.72

Widzimy, jak wzrasta utylizacja dysku, zbliżając się do 90% i jak bardzo wzrósł parametr await. Chciałbym w tym miejscu przede wszystkim zwrócić uwagę na parametr %iowait, określający czas oczekiwania procesora na zakończenie operacji I/O. Ten parametr pod nazwą “%wa“pokazuje również komenda top w pierwszych wierszach:

root@server:~# top
top - 08:40:06 up 34 min,  3 users,  load average: 0.08, 0.09, 0.38
 Tasks: 192 total,   1 running, 191 sleeping,   0 stopped,   0 zombie
 Cpu(s): 11.2%us,  1.5%sy,  0.4%ni, 81.5%id,  5.4%wa,  0.0%hi,  0.1%si,  0.0%st
 Mem:   4127368k total,  3428180k used,   699188k free,   224420k buffers
 Swap:  1952764k total,      152k used,  1952612k free,  2313936k cached

Generalnie mówiąc %iowait = %wa = czas oczekiwania przez procesor na zakończenie operacji I/O. Przy znacznych wartościach %iowait mamy sytuację, gdy procesor czeka na zakończenie jakiś operacji dyskowych bądź sieciowych, pozostając tak naprawdę bezczynny, a my obserwujemy wtedy bardzo wolną pracę systemu i wysoką wartość load average, mimo że procesor pozostaje nieobciążony. Tak więc %iowait mówi nam bardzo wiele o stanie naszego systemu.

Jest tutaj jednak pewna mała pułapka którą chciałbym pokazać. Wygenerujmy znów nasz 10GB plik jednocześnie obserwując %wa programem top, bądź %iowait przy pomocy iostat:

root@server:~# top
top - 08:59:16 up 53 min,  3 users,  load average: 0.82, 0.35, 0.28
 Tasks: 193 total,   1 running, 192 sleeping,   0 stopped,   0 zombie
 Cpu(s):  2.0%us,  9.5%sy,  0.0%ni, 74.8%id, 13.6%wa,  0.0%hi,  0.2%si,  0.0%st
 Mem:   4127368k total,  2288852k used,  1838516k free,   224708k buffers
 Swap:  1952764k total,      152k used,  1952612k free,  1187276k cached

Jak widzimy, procesor średnio 13% swojego czasu czeka na zakończenie operacji I/O, co jest mniej więcej zgodne z naszymi oczekiwaniami. Zobaczmy jednak, co się stanie, gdy zajmiemy system generacją pliku, jednocześnie obciążając mocno procesor zupełnie innym zadaniem:

root@server:~# dd if=/dev/zero of=test.img bs=1024 count=2024000
root@server:~# stress -c 4
 stress: info: [5558] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
top - 09:10:30 up  1:04,  4 users,  load average: 1.92, 0.58, 0.35
 Tasks: 201 total,   6 running, 195 sleeping,   0 stopped,   0 zombie
 Cpu(s): 96.5%us,  3.1%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.4%si,  0.0%st
 Mem:   4127368k total,  3001736k used,  1125632k free,   225756k buffers
 Swap:  1952764k total,      152k used,  1952612k free,  1876184k cached
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 5559 root      20   0  2204   76    0 R   96  0.0   0:26.94 stress
 5562 root      20   0  2204   76    0 R   95  0.0   0:25.90 stress
 5561 root      20   0  2204   76    0 R   91  0.0   0:25.64 stress
 5560 root      20   0  2204   76    0 R   86  0.0   0:26.14 stress
 5566 root      20   0  5604  588  500 D   20  0.0   0:02.58 dd

W magiczny sposób %wa=0.0, a widzimy że dd pracuje tworząc plik. Nie mamy powodu przypuszczać, że nagle nasz proces dd zaczął działać inaczej i procesor przestał czekać na zakończenie operacji I/O.

Zerknijmy na strony man programów top i iostat.

top: wa  --  iowait - Amount of time the CPU has been waiting for I/O to complete.
iostat: iowait – Show the percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.

No cóż. Mimo że %wa=%iowait to w opisie parametrów jest jakby subtelna różnica i opis iowait jest jakby precyzyjniejszy a co ważniejsze dokładnie odzwierciedla sytuację z którą mamy właśnie do czynienia.

Precyzując – %iowait = %wa = procent czasu w jakim procesor jest nieobciążony podczas gdy trwają znacznej wielkości operacje I/O. Jeśli więc obciążymy procesor innym zadaniem to nie pozostaje on bezczynny w oczekiwaniu na I/O innego procesu – wartości %wa spadają.

W normalnych środowiskach, mając na przykład serwer bazodanowy i niewydolny system dyskowy, powinniśmy zobaczyć wysokie wartości iowait, gdyż zakładamy że jest to system na którym poza procesami bazy nie będzie innych procesów obciążających w taki sposób procesor, że wpłyną one na wartość parametru %iowait. Ale warto o takim fakcie pamiętać i mieć na uwadze, że sytuacje takie mogą się zdarzyć, a my możemy źle zinterpretować dane dostarczane przez narzędzia pomiarowe.

  • iotop też jest dobre pokazuje w czasie rzeczywistym zapisy i odczyty z procesów

  • nat

    Dobry tekst, znów dowiedziałem się czegoś nowego, dzięki.

  • xxx

    Czy Autor mógłby sprawdzić w słowniku języka polskiego znaczenie słowa utylizacja? Tak na przyszłość. Żeby i On się czegoś dowiedział, nie tylko my…

    • Tomasz

      Autor sprawdził. Sprawdził też słowo mysz.
      I z uporem maniaka będzie używał utylizacja zamiast "wykorzystanie" tak samo jak i mysz zamiast "ręczny manipulator stoło-kulotoczny".