How to identify I/O-Bottlenecks on Oracle Linux

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)“.

Leave a Comment

Your email address will not be published.