Parecido com o artigo sobre consumo de CPU e Memória, hoje escreverei sobre I/O, contemplando parte teórica e prática. Antes de ir para às ferramentas em efetivo, só gostaria de compartilhar a imagem abaixo, retirada da obra “Linux and Solaris Recipes for Oracle DBAs”. Achei muito interessante, para vermos as diversas camadas que precisamos saber que existem e podem nos gerar problemas:
Vmstat
Uma forma simples de acompanhar se há um grande fluxo de I/O no servidor é através do comando “vmstat”, especificamente nas colunas bi e bo, conforme diz o man abaixo:
Este é um exemplo do comando executado em uma VM que não está experimentando muitos eventos de I/O:
[oracle@oel7 ~]$ vmstat 1 10 -S m
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 10566 12 4691 0 0 21 0 471 545 4 2 89 5 0
0 0 0 10566 12 4691 0 0 0 0 2101 2953 1 1 99 0 0
0 0 0 10566 12 4691 0 0 48 0 2316 3052 2 1 97 0 0
0 0 0 10566 12 4691 0 0 0 0 2011 2664 1 1 99 0 0
0 0 0 10565 12 4691 0 0 20 0 2072 2842 1 1 99 0 0
0 0 0 10566 12 4691 0 0 48 0 2166 3028 1 1 99 0 0
1 0 0 10565 12 4691 0 0 0 0 2020 2679 1 1 99 0 0
0 0 0 10561 12 4691 0 0 25 0 3265 3729 4 5 91 0 0
1 0 0 10561 12 4691 0 0 48 0 1883 2446 2 2 97 0 0
0 0 0 10564 12 4691 0 0 0 0 2556 3201 2 2 96 0 0
[oracle@oel7 ~]$
Com o comando abaixo, vamos simular a criação de um arquivo de 2GB e acompanhar o vmstat:
[oracle@oel7 ~]$ cd /oracle
[oracle@oel7 oracle]$ dd if=/dev/urandom of=GIGtestfile bs=1M count=2048 oflag=direct &
[1] 18568
[oracle@oel7 oracle]$
Vemos um número acima da média na coluna bi:
[oracle@oel7 ~]$ vmstat 1 15 -S m
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 10590 14 4715 0 0 196 0 384 503 2 2 95 1 0
1 0 0 10590 14 4715 0 0 74784 0 5601 5230 1 17 82 1 0
1 0 0 10591 14 4715 0 0 75832 0 5082 5209 0 16 83 1 0
1 0 0 10590 14 4715 0 0 75836 0 5293 5119 0 16 83 1 0
1 0 0 10591 14 4715 0 0 75808 0 4799 5033 1 16 82 1 0
0 1 0 10590 14 4715 0 0 76908 0 4928 4990 0 16 83 1 0
0 1 0 10590 14 4715 0 0 75776 0 4790 4921 1 16 82 1 0
1 0 0 10590 14 4715 0 0 75852 0 4819 4937 0 16 83 1 0
0 0 0 10591 14 4715 0 0 50192 0 3987 4312 0 11 88 1 0
0 0 0 10591 14 4715 0 0 0 0 2165 2804 1 1 99 0 0
0 0 0 10591 14 4715 0 0 60 0 2064 2771 1 1 99 0 0
1 0 0 10591 14 4715 0 0 24 0 1820 2444 1 1 99 0 0
1 0 0 10592 14 4715 0 0 0 0 1871 2609 1 1 99 0 0
0 0 0 10591 14 4715 0 0 72 0 2158 2945 2 1 97 0 0
0 0 0 10591 14 4715 0 0 16 0 1871 2509 1 1 99 0 0
[oracle@oel7 ~]$
[oracle@oel7 oracle]$ 2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 28.0244 s, 76.6 MB/s
[1]+ Done dd if=/dev/urandom of=GIGtestfile bs=1M count=2048 oflag=direct
[oracle@oel7 oracle]$
Executando o utilitário stress para provocar eventos de I/O e acompanhar o ambiente:
[oracle@oel7 oracle]$ stress --cpu 1 --io 2 --hdd 2 --hdd-bytes 1GB --timeout 20s
stress: info: [22128] dispatching hogs: 1 cpu, 2 io, 0 vm, 2 hdd
stress: info: [22128] successful run completed in 20s
[oracle@oel7 oracle]$
[oracle@oel7 ~]$ vmstat 1 15 -S m
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 3 0 10524 81 4719 0 0 243 0 386 505 2 2 96 1 0
6 0 0 10514 91 4719 0 0 68928 0 27215 39741 19 21 50 10 0
2 3 0 10500 99 4719 0 0 54452 0 25345 35242 24 29 39 9 0
3 3 0 10495 106 4720 0 0 65578 0 27136 39320 19 22 46 12 0
4 0 0 10489 113 4720 0 0 65651 0 23326 38991 19 22 48 11 0
5 0 0 10485 118 4720 0 0 68290 0 23503 40173 19 22 48 10 0
3 0 0 10480 123 4720 0 0 71564 0 24071 41831 19 20 50 10 0
4 0 0 10477 126 4720 0 0 63325 0 21934 37358 19 20 48 13 0
4 0 0 10473 130 4720 0 0 69096 0 23402 40640 19 20 50 11 0
3 0 0 10470 133 4720 0 0 70816 0 23801 41330 19 21 50 11 0
5 0 0 10468 135 4720 0 0 71528 0 23943 41790 19 20 50 10 0
4 0 0 10465 138 4721 0 0 70617 0 23636 41026 19 19 51 11 0
4 0 0 10464 140 4721 0 0 68601 0 23729 40119 19 22 49 9 0
0 0 0 10464 140 4721 0 0 46584 0 16904 28403 13 15 66 7 0
0 0 0 10465 140 4721 0 0 0 0 1847 2518 0 0 99 0 0
[oracle@oel7 ~]$
IOtop
Caso o iotop não esteja instalado, basta fazer o seguinte:
[oracle@oel7 ~]$ iotop
bash: iotop: command not found...
...
[root@oel7 ~]# yum install iotop
Loaded plugins: langpacks, ulninfo
ol7_UEKR5 | 3.0 kB 00:00:00
ol7_latest | 3.6 kB 00:00:00
(1/4): ol7_UEKR5/x86_64/updateinfo | 345 kB 00:00:06
(2/4): ol7_latest/x86_64/updateinfo | 3.5 MB 00:01:03
(3/4): ol7_latest/x86_64/primary_db | 44 MB 00:05:08
(4/4): ol7_UEKR5/x86_64/primary_db | 62 MB 00:07:03
Resolving Dependencies
--> Running transaction check
---> Package iotop.noarch 0:0.6-4.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
====================================================================================================================================================================
Package Arch Version Repository Size
====================================================================================================================================================================
Installing:
iotop noarch 0.6-4.el7 ol7_latest 52 k
Transaction Summary
====================================================================================================================================================================
Install 1 Package
Total download size: 52 k
Installed size: 156 k
Is this ok [y/d/N]: y
Downloading packages:
iotop-0.6-4.el7.noarch.rpm | 52 kB 00:00:03
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : iotop-0.6-4.el7.noarch 1/1
Verifying : iotop-0.6-4.el7.noarch 1/1
Installed:
iotop.noarch 0:0.6-4.el7
Complete!
[root@oel7 ~]#
..
[root@oel7 ~]# cat /etc/sudoers | grep oracle
oracle ALL=/usr/sbin/iotop
[root@oel7 ~]#
O IOTOP é basicamento o comando TOP, mas focado nos eventos de I/O. Uma vez que identificamos uma anormalidade na camada de I/O do servidor (que provavelmente também provocou aumento de Load), podemos tentar identificar mais detalhes por ele. No exemplo abaixo, vemos as informações exibidas, como o PID, leitura e escrita, etc:
[oracle@oel7 ~]$ sudo iotop
[sudo] password for oracle:
Total DISK READ : 54.96 K/s | Total DISK WRITE : 27.36 M/s
Actual DISK READ: 69.67 M/s | Actual DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1319 be/3 root 0.00 B/s 2.54 M/s 0.00 % 46.45 % [jbd2/sdg1-8]
16192 be/4 oracle 0.00 B/s 257.64 K/s 0.00 % 29.56 % stress --cpu 1 --io 2 --hdd 2 --hdd-bytes 1GB --timeout 30s
16190 be/4 oracle 0.00 B/s 216.42 K/s 0.00 % 22.21 % stress --cpu 1 --io 2 --hdd 2 --hdd-bytes 1GB --timeout 30s
16189 be/4 oracle 0.00 B/s 0.00 B/s 0.00 % 7.21 % stress --cpu 1 --io 2 --hdd 2 --hdd-bytes 1GB --timeout 30s
16191 be/4 oracle 0.00 B/s 0.00 B/s 0.00 % 2.97 % stress --cpu 1 --io 2 --hdd 2 --hdd-bytes 1GB --timeout 30s
4568 be/4 oracle 54.96 K/s 27.48 K/s 0.00 % 0.08 % ora_ckpt_cortex
1318 be/3 root 0.00 B/s 10.31 K/s 0.00 % 0.07 % [jbd2/sdf1-8]
15159 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.01 % [kworker/u12:3]
3761 be/4 grid 0.00 B/s 13.74 K/s 0.00 % 0.00 % oraagent.bin
3803 be/4 grid 0.00 B/s 6.87 K/s 0.00 % 0.00 % ocssd.bin
1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % systemd --switched
IOstat
Gosto bastante desta ferramenta, pois ela já exibe os devices, e com os parâmetros “xd”, é possível avaliar a % de uso, facilitando a investigação. O “10” significa o tempo em segundos que as informações serão atualizadas:
[oracle@oel7 ~]$ iostat -xd 10
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
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.01 0.19 2.52 1.47 101.64 163.59 133.00 0.15 36.73 9.75 82.92 0.82 0.33
dm-0 0.00 0.00 2.36 1.58 94.81 164.17 131.43 0.11 27.42 9.98 53.44 0.79 0.31
dm-1 0.00 0.00 0.02 0.00 0.45 0.00 49.54 0.00 11.85 11.85 0.00 0.81 0.00
sdc 0.00 0.00 0.26 0.96 3.20 9.63 21.11 0.00 1.24 3.28 0.70 0.99 0.12
sdb 0.00 0.00 0.22 0.32 3.54 1.29 17.72 0.00 1.35 2.93 0.26 1.02 0.06
sdd 0.00 0.00 0.22 0.34 1.86 2.82 16.69 0.00 2.31 2.61 2.11 0.98 0.05
sde 0.00 0.00 3.94 1.23 63.06 13.44 29.58 0.01 2.50 3.08 0.64 0.68 0.35
sdf 0.01 0.83 1.06 1.11 128.72 8.34 126.43 0.01 6.72 12.88 0.81 0.53 0.11
sdg 0.02 358.70 7.98 134.50 954.20 2809.42 52.83 0.08 0.58 5.60 0.28 0.22 3.13
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 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 0.00 0.00 0.60 0.00 6.00 20.00 0.00 0.50 0.00 0.50 1.50 0.09
sdb 0.00 0.00 0.00 0.30 0.00 1.20 8.00 0.00 0.00 0.00 0.00 1.00 0.03
sdd 0.00 0.00 0.00 0.30 0.00 1.20 8.00 0.00 0.00 0.00 0.00 1.00 0.03
sde 0.00 0.00 1.60 0.60 25.60 6.00 28.73 0.00 0.91 1.19 0.17 0.59 0.13
sdf 0.00 1.50 0.00 8.60 0.00 40.40 9.40 0.01 1.09 0.00 1.09 0.38 0.33
sdg 0.00 13688.40 0.10 4814.20 0.40 74010.40 30.75 0.73 0.15 7.00 0.15 0.19 89.59
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 1.10 0.00 1.90 0.00 16.25 17.11 0.00 1.84 0.00 1.84 0.21 0.04
dm-0 0.00 0.00 0.00 3.00 0.00 16.25 10.83 0.01 1.83 0.00 1.83 0.13 0.04
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 0.00 0.00 0.60 0.00 6.00 20.00 0.00 0.17 0.00 0.17 1.17 0.07
sdb 0.00 0.00 0.00 0.30 0.00 1.20 8.00 0.00 0.00 0.00 0.00 1.00 0.03
sdd 0.00 0.00 0.00 0.30 0.00 1.20 8.00 0.00 0.00 0.00 0.00 1.00 0.03
sde 0.00 0.00 1.60 0.60 25.60 6.00 28.73 0.00 1.23 1.56 0.33 0.73 0.16
sdf 0.00 1.90 0.00 8.90 0.00 43.20 9.71 0.01 0.99 0.00 0.99 0.35 0.31
sdg 0.00 14524.90 0.00 5012.90 0.00 78151.20 31.18 0.68 0.14 0.00 0.14 0.19 94.47
^C
Observação: o iostat trabalha na camada dos devices lógicos. Ou seja, caso o problema seja em um disco físisco de Storage, apresentado como uma LUN, esse nível de detalhe não é exposto no output.
Oracle Database Layer
Com os comandos acima, já conseguimos identificar os processos que estão mais consumindo I/O, e em quais devices. Na camada de banco de dados, conseguimos listar os processos que estão aguardando recurso de I/O pela consulta abaixo:
SELECT a.username, a.sql_id, b.object_name, b.object_type, a.event
FROM v$session a
,dba_objects b
,v$event_name c
WHERE b.object_id = a.row_wait_obj#
AND a.event = c.name
AND c.wait_class = 'User I/O';
Há também a possibilidade de investigarmos estes eventos pelos relatórios AWR (caso licenciado) ou Statspack, nas sessões que tratam de I/O.
Sysstat/pidstat
Caso o IOTOP seja impeditivo, pela necessidade de instalação, uma alternativa de tentar identificar processos e seus respectivos consumo de I/O seria usando o comando “pidstat”, que faz parte do pacote “sysstat”. Descobri essa possibilidade através do Oracle Note “Oracle Linux: How to monitor I/O activity per process (Doc ID 2910779.1)“:
[oracle@oel7 ~]$ pidstat -d
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
08:39:03 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
08:39:03 PM 54321 3285 748.52 1730.71 970.84 bash
08:39:03 PM 54321 15426 8.95 0.00 0.00 bash
08:39:03 PM 54321 31973 0.00 104.02 103.05 stress
08:39:03 PM 54321 31975 0.00 102.47 101.54 stress
[oracle@oel7 ~]$ pidstat -d
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
08:39:09 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
08:39:09 PM 54321 3285 747.72 1936.92 1175.95 bash
08:39:09 PM 54321 15426 8.94 0.00 0.00 bash
[oracle@oel7 ~]$
No exemplo acima, de forma proposital, vemos que há 2 processos que não aparecem na segunda execução do comando, pois o seu processo origem foi finalizado. Ou seja, só é possível ver as condições de uso no momento da execução. Caso queiramos guardar as informações para análise posterior, podemos usufruir do comando de exemplo abaixo:
[oracle@oel7 ~]$ while true; do date | tee -a /tmp/ioperprocess.stat; pidstat -d | tee -a /tmp/ioperprocess.stat; sleep 5; done
[oracle@oel7 ~]$ cat /tmp/ioperprocess.stat
Thu Jan 19 20:41:28 -03 2023
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
08:41:28 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
08:41:28 PM 54321 1425 0.00 19.90 19.73 stress
08:41:28 PM 54321 1427 0.00 20.33 20.15 stress
08:41:28 PM 54321 1513 0.00 0.00 0.00 tee
08:41:28 PM 54321 3285 729.63 1890.05 1147.49 bash
08:41:28 PM 54321 15426 8.73 0.00 0.00 bash
Thu Jan 19 20:41:33 -03 2023
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
08:41:33 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
08:41:33 PM 54321 1425 0.00 37.19 36.87 stress
08:41:33 PM 54321 1427 0.00 39.51 39.19 stress
08:41:33 PM 54321 1553 0.00 0.00 0.00 tee
08:41:33 PM 54321 3285 728.98 1888.38 1146.48 bash
08:41:33 PM 54321 15426 8.72 0.00 0.00 bash
Thu Jan 19 20:41:38 -03 2023
Linux 4.14.35-1902.3.2.el7uek.x86_64 (oel7.localdomain) 01/19/2023 _x86_64_ (6 CPU)
08:41:38 PM UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
08:41:38 PM 54321 1425 0.00 54.51 54.05 stress
08:41:38 PM 54321 1427 0.00 58.31 57.82 stress
08:41:38 PM 54321 1599 0.00 0.00 0.00 tee
08:41:38 PM 54321 3285 728.34 1886.72 1145.48 bash
08:41:38 PM 54321 15426 8.71 0.01 0.00 bash
Thu Jan 19 20:41:43 -03 2023
Testing I/O rates
Quando é necessário medir as taxas de I/O do sistema (principalmente para provar aos nossos SAs que nosso HDD do laptop pessoal está melhor que o Storage disponibilizado), podemos usar o comando “dd”.
Estimativa para escrita:
[oracle@oel7 ~]$ time dd if=/dev/zero of=swivfile bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 11.5458 s, 93.0 MB/s
real 0m11.549s
user 0m0.007s
sys 0m0.739s
[oracle@oel7 ~]$
Estimativa para leitura:
[oracle@oel7 ~]$ time dd of=/dev/null if=swivfile bs=1M count=1024 iflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 10.0512 s, 107 MB/s
real 0m10.053s
user 0m0.009s
sys 0m0.176s
[oracle@oel7 ~]$
More robust Tools
Para o objetivo deste artigo, as ferramentas apresentadas são mais do que suficientes para o trabalho. Porém, caso você esteja envolvido em um Stress Test, ou análise de capacity, há 2 ferramentas que podem ajudar: IOZONE e IOMETER. Elas devem ser usadas com muito cuidado, pois podem afetar negativamente o ambiente (tanto em termos de performance, quanto na consistência dos dados persistidos). Recomendo bastante a leitura do Oracle Note “Oracle Linux: How to Measure I/O Performance on Linux (Doc ID 1931009.1)“.