Desenvolvimento

28 ago, 2012

Usando Linux SystemTap

Publicidade

Recentemente, algumas pessoas começaram a se perguntar como Arakoon, nossa loja de chave-valor distribuída, lida com o drive no qual os dados são armazenados. Para ser mais claro, isso se resume à forma como Tokyo Cabinet (que usamos atualmente como implementação de banco de dados) envia solicitações de gravação para o kernel, e como ele processa essas informações mais tarde, após traduzir os pedidos de nível de sistema de arquivos em operações de escrita na camada do bloco.

É importante saber isso devido ao uso de drives SSD – pense em nivelamento de desgaste e outras questões vêm com esses dispositivos.

O rastreamento de como o aplicativo grava dados em um arquivo pode ser conseguido usando a ferramenta strace, buscando por chamadas write(2) e pwrite(2)  (embora isso não seja necessariamente suficiente: o aplicativo pode ser escrito em um arquivo usando mapeamentos de memória mmap(2)).

Entretanto, na maioria dos carregamentos, isso não corresponde à forma como os pedidos de bloco são enviados para o hardware: as gravações podem ser bufferizadas, reordenadas etc. O que desejamos é uma maneira de reunir informações de solicitações de gravação na camada do bloco do kernel.

No Linux, pode-se usar SystemTap (que possui algumas semelhanças com o DTrace em Solaris) para fazer um hook no kernel no tempo de execução e recolher estatísticas, ou muitas outras informações. Também é possível escrever um script que se liga aos pontos de rastreio ou chamadas de função, então processa a informação recebida.

Não vou entrar na instalação de SystemTap, uma vez que isso dependerá da distribuição que você está rodando. Note que você pode não precisar de acesso root para executar os scripts (você também nem deveria!): no meu sistema Fedora 16, tudo o que eu tinha que fazer era colocar o meu usuário nos grupos stapsys, stapusr e stapdev (embora eu não tenha certeza de que realmente preciso estar em todos aqueles…). Você vai precisar depurar arquivos de símbolos de seu kernel disponível em execução, entre outras coisas (na minha experiência de tentar executar um script em um sistema onde alguns pré-requisitos estão faltando, isso resultará na ferramenta stap dizendo o que você precisa).

Escrever scripts SystemTap às vezes requer algum conhecimento interno do kernel, para saber onde fazer o hook. Uma vez que quis reunir algumas estatísticas sobre chamadas de nível de bloco, eu sabia que tinha que procurar por chamadas no subsistema «bio», abreviação de “Block IO “. Por sorte, SystemTap vem com algumas combinações predefinidas de hooks, chamados de ‘tapsets’. Elas são armazenadas (no meu sistema, pelo menos) em /usr/share/systemtap/tapset. Um desses arquivos é chamado ioblock.stp, o que parece interessante. Já que eu estava com muita preguiça para procurar a documentação, abri o arquivo em um paginador e li por ele. O tap ioblock.request parecia interessante, o que dá acesso a um valor size. Depois de ler alguns exemplos de scripts SystemTap, eis o que eu criei:

global writes

probe ioblock.request {
    if(bio_rw_num(rw) == BIO_WRITE)
        writes[devname] <<< size
}

probe end {
    printf("\n")
    foreach([devname] in writes-) {
        printf("Device: %s\n", devname)
        println(@hist_log(writes[devname]))
    }
}

Executar isso usando a ferramenta stap, e fechar depois de um tempo (usando CTRL-C), fornece o seguinte resultado:

$ stap -v blockio.stp
Pass 1: parsed user script and 92 library script(s) using 210196virt/30852res/3136shr kb, in 140usr/20sys/251real ms.
Pass 2: analyzed script: 3 probe(s), 21 function(s), 2 embed(s), 2 global(s) using 452960virt/226472res/92556shr kb, in 1500usr/100sys/2541real ms.
Pass 3: translated to C into "/tmp/stapeJldxD/stap_e40cc31c16b7dd290dabd43749c577a4_12507_src.c" using 452960virt/226600res/92684shr kb, in 10usr/0sys/12real ms.
Pass 4: compiled C into "stap_e40cc31c16b7dd290dabd43749c577a4_12507.ko" in 1780usr/350sys/2595real ms.
Pass 5: starting run.
^C
Device: sda5
value |-------------------------------------------------- count
    0 |@@@@@@@@@@@@@@@                                    30
    1 |                                                    0
    2 |                                                    0
      ~
  256 |                                                    0
  512 |                                                    0
 1024 |                                                    1
 2048 |                                                    0
 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@                        54
 8192 |@@@                                                 7
16384 |@                                                   3
32768 |                                                    0
65536 |                                                    0

Device: dm-2
value |-------------------------------------------------- count
    0 |@@                                                  5
    1 |                                                    0
    2 |                                                    0
      ~
  256 |                                                    0
  512 |                                                    0
 1024 |@                                                   2
 2048 |                                                    0
 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                      58
 8192 |@@@@@@@                                            14
16384 |@@@                                                 6
32768 |                                                    0
65536 |                                                    0

Device: dm-4
value |-------------------------------------------------- count
    0 |@                                                   2
    1 |                                                    0
    2 |                                                    0
      ~
  256 |                                                    0
  512 |                                                    0
 1024 |@                                                   2
 2048 |                                                    0
 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                      58
 8192 |@@@@@@@                                            14
16384 |@@@                                                 6
32768 |                                                    0
65536 |                                                    0

Device: dm-1
value |-------------------------------------------------- count
 1024 |                                                    0
 2048 |                                                    0
 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 50
 8192 |                                                    0
16384 |                                                    0

Device: sda
value |-------------------------------------------------- count
 1024 |                                                   0
 2048 |                                                   0
 4096 |@@                                                 2
 8192 |                                                   0
16384 |                                                   0

Pass 5: run completed in 10usr/50sys/15274real ms.

Isso é um histograma de solicitações de gravação bio para todos os dispositivos de bloco no meu sistema, enquanto o script estava sendo executado. Caso veja um monte de pedidos menores do que o tamanho da página em um dispositivo SSD (isso depende do hardware), você pode querer dar uma olhada nos padrões de gravação do seu aplicativo (embora, mesmo assim, as coisas possam não ser tão ruins quanto parecem à primeira vista, pois o drive SSD poderia executar lotes, remapeamento e qualquer outra coisa internamente).

Observe que a saída do script exibido acima não retrata o comportamento de Arakoon ou Tokyo Cabinet: ela mostra uma sessão padrão de desktop, (rodando Google Chrome, Evolution, Empathy, Skype e mais alguns aplicativos), durante um período de tempo muito curto. O teste foi executado em um sistema Fedora 16 para laptop, contendo um hard drive spinning usando uma combinação de Ext4 e XFS em vários volumes LVM2 no kernel 3.2.7-1.fc16.x86_64.

***

Texto original disponível em http://blog.incubaid.com/2012/03/06/tracing-block-device-write-request-sizes-in-linux-using-systemtap/