VirtIO-blk vs. VirtIO-SCSI: Anatomia da Latência e o Mito da Performance

      16 de dezembro de 2025 Marta G. Oliveira 8 min de leitura
      VirtIO-blk vs. VirtIO-SCSI: Anatomia da Latência e o Mito da Performance

      Pare de chutar configurações no KVM. Entenda a arquitetura de ring buffers, o impacto real do overhead SCSI e quando o VirtIO-blk ainda vence.

      Compartilhar:

      Você recebe o chamado às 3 da manhã. O banco de dados está engasgando. O dashboard mostra latência de disco disparando, mas quando você olha para o storage array físico, ele está dormindo. IOPS baixos, throughput ridículo. Onde está o gargalo?

      Bem-vindo à cena do crime. A vítima é a performance de I/O, e o culpado geralmente está escondido na camada de abstração que você configurou seis meses atrás e esqueceu: o driver de disco da sua máquina virtual.

      A escolha entre virtio-blk e virtio-scsi raramente é feita com base em evidências; geralmente é baseada no padrão do hypervisor (como o Proxmox ou VMware) ou em "sabedoria tribal" de fóruns antigos. Mas quando escalamos para milhares de IOPS, essa escolha define o teto físico da sua infraestrutura. Vamos dissecar essa anatomia.

      A Ilusão do "Driver Padrão"

      Para o sistema operacional Guest (a VM), o disco é uma mentira. Não existe prato girando nem chips NAND conectados diretamente. Existe uma região de memória compartilhada e um protocolo de comunicação.

      A maioria dos administradores escolhe VirtIO-SCSI porque é o padrão em muitas distribuições modernas e "parece" mais robusto. Ele emula uma controladora SCSI, permitindo que o Guest use comandos SCSI padrão que ele já conhece há 30 anos.

      Outros escolhem VirtIO-blk porque ouviram dizer que é "mais rápido", embora muitas vezes não saibam explicar o porquê, ou quais funcionalidades perdem no processo.

      A diferença não é apenas uma questão de nomenclatura. É uma questão de quantas camadas de tradução seus dados precisam atravessar antes de sair da memória da VM e chegar ao Host.

      O Custo da Abstração: O caminho da direita (SCSI) obriga o kernel a traduzir comandos de bloco genéricos para comandos SCSI e vice-versa, adicionando ciclos de CPU à latência. Figura: O Custo da Abstração: O caminho da direita (SCSI) obriga o kernel a traduzir comandos de bloco genéricos para comandos SCSI e vice-versa, adicionando ciclos de CPU à latência.

      Mecânica dos Fluidos: Virtqueues e Ring Buffers

      Para entender onde a latência nasce, precisamos olhar para o mecanismo de transporte: as Virtqueues.

      Imagine que o Guest e o Host (KVM/QEMU) são duas pessoas em salas separadas por um vidro à prova de som. Eles não podem falar, mas podem passar papéis por uma gaveta deslizante (o Ring Buffer na memória compartilhada).

      1. O Guest escreve dados no buffer ("Quero gravar X no setor Y").

      2. O Guest toca uma campainha (o mecanismo de kick ou VMExit) para avisar o Host. Isso é custoso. O processador para o que a VM está fazendo e troca de contexto para o Host.

      3. O Host acorda, lê o papel, executa a gravação no hardware real.

      4. O Host coloca a confirmação na gaveta e toca a campainha do Guest (Interrupção).

      Cada "toque de campainha" é uma interrupção. Se você tem um banco de dados fazendo 50.000 gravações pequenas por segundo, você tem uma tempestade de interrupções. A eficiência desse protocolo determina se sua CPU passa o tempo processando dados ou apenas trocando de contexto (Context Switching).

      VirtIO-SCSI: O Burocrata Flexível

      O virtio-scsi foi criado para resolver limitações de escalabilidade. Ele não é apenas um driver de disco; é uma controladora completa.

      • A Vantagem: Ele desacopla o dispositivo do barramento PCI. Você pode ter centenas de discos (LUNs) em uma única controladora. Ele suporta nativamente comandos vitais como UNMAP (ou TRIM), essencial para que o storage físico saiba quais blocos foram deletados e recupere espaço (Thin Provisioning).

      • O Custo: Como visto na imagem anterior, ele exige tradução. O kernel do Linux gera um pedido de bloco genérico -> Camada SCSI traduz para comando SCSI -> Driver VirtIO encapsula -> Envia ao Host -> Host desencapsula -> Host traduz de volta para bloco ou repassa ao hardware.

      Essa serialização e desserialização de comandos SCSI consome ciclos de CPU. Em cargas baixas, é imperceptível. Em cargas extremas de I/O randômico pequeno (4k), a sobrecarga da pilha SCSI pode adicionar microssegundos preciosos a cada operação.

      VirtIO-blk: A Rota Expressa

      O virtio-blk é o minimalista. Ele sabe que está em um ambiente virtual e não tenta fingir ser um cabo físico antigo.

      • A Mecânica: O protocolo é simplificado. O comando é basicamente: "Leia/Escreva no deslocamento X". Não há necessidade de decodificar conjuntos complexos de comandos SCSI.

      • A Performance: Por pular a camada SCSI intermediária no Guest, o caminho do código (code path) é mais curto. Menos instruções de CPU por I/O. Isso resulta em latência ligeiramente menor e, crucialmente, menor uso de CPU para o mesmo throughput.

      Por que não usamos sempre? Historicamente, o virtio-blk tinha limitações severas.

      1. Slots PCI: Cada disco consumia um slot PCI endereçável. Havia um limite de cerca de 28 discos por VM.

      2. Recursos: O suporte a discard (TRIM) demorou a chegar e amadurecer no virtio-blk, embora em kernels modernos (5.0+ e QEMU recentes) isso já esteja resolvido ou mitigado via configuração (discard=on).

      3. Passthrough: Comandos SCSI genéricos (para gravadores de fita ou dispositivos exóticos) não passam.

      O Divisor de Águas: Multi-Queue (blk-mq vs scsi-mq)

      Aqui é onde a maioria dos diagnósticos falha. Você pode mudar de SCSI para Blk e não ver diferença nenhuma se ignorar o paralelismo de filas.

      Antigamente, todo o I/O de uma VM era canalizado para uma única fila de interrupção. Se sua VM tinha 16 vCPUs tentando gravar no disco, elas precisavam brigar (lock contention) para colocar o pedido na única fila disponível. Uma vCPU ficava sobrecarregada lidando com as interrupções de retorno.

      O advento do Multi-Queue permitiu criar múltiplas filas de envio e conclusão, mapeando-as para as vCPUs.

      Paralelismo Real: Sem multi-queue, seus vCPUs entram em disputa (lock contention) para escrever no disco. Com multi-queue, a escala é quase linear. Figura: Paralelismo Real: Sem multi-queue, seus vCPUs entram em disputa (lock contention) para escrever no disco. Com multi-queue, a escala é quase linear.

      Tanto o virtio-blk quanto o virtio-scsi modernos suportam multi-queue, mas a implementação varia.

      • No VirtIO-blk, a configuração geralmente é direta (queues=N).

      • No VirtIO-SCSI, você precisa garantir que a controladora esteja configurada para expor múltiplas filas (num_queues=N) e que o Guest esteja usando scsi-mq.

      Callout de Risco: Simplesmente ativar multi-queue no Host não garante o uso no Guest. Se o Guest for um Linux antigo (pré-kernel 3.13 para blk, ou pré-4.x para scsi otimizado), ele pode ignorar as filas extras e continuar gargalando em um único núcleo.

      Autopsia: Como Medir a Dor

      Não confie na minha palavra. Vamos para a linha de comando verificar se o overhead de tradução ou a falta de filas está matando sua performance.

      1. Verificando a Fusão de Interrupções (iostat)

      No Guest, execute:

      # Observe a coluna 'aqu-sz' (tamanho médio da fila) e '%util'
      iostat -x -k 1
      

      Se o aqu-sz estiver alto (100+), mas o host físico estiver tranquilo, o gargalo é a interface virtual ou a falta de filas.

      2. Caçando o Overhead de SCSI (perf)

      Esta é a prova definitiva. Se você suspeita que o virtio-scsi está gastando muita CPU traduzindo comandos, use o perf no Guest durante um teste de carga:

      # Grava 10 segundos de perfil de CPU
      perf record -a -g sleep 10
      perf report
      

      Analise a árvore de chamadas.

      • Se você vir muito tempo gasto em funções como scsi_queue_rq, sd_init_command ou scsi_dispatch_cmd, você está pagando o "imposto SCSI".

      • No virtio-blk, você verá chamadas diretas para virtio_queue_rq, pulando a burocracia.

      3. Verificando Multi-Queue Ativo

      Verifique se as interrupções estão balanceadas entre as CPUs no Guest:

      cat /proc/interrupts | grep virtio
      

      Se você vir apenas uma linha de interrupção para o dispositivo de bloco acumulando milhões de eventos, enquanto outras linhas estão zeradas ou inexistentes, o Multi-Queue não está funcionando, independente do driver escolhido.

      Veredito Prático: Matriz de Decisão

      Não existe "melhor". Existe a ferramenta certa para o trabalho. Como investigador, sua recomendação deve ser baseada na carga de trabalho.

      Cenário Recomendação Por quê?
      Banco de Dados (High IOPS) VirtIO-blk Menor latência por operação. Menor overhead de CPU (sobra mais CPU para o SQL). A complexidade do SCSI não agrega valor aqui.
      Boot Drive / OS Genérico VirtIO-SCSI Compatibilidade máxima. Suporte robusto a TRIM/UNMAP para economizar espaço no storage (Thin Provisioning). Facilidade de gerenciar muitos volumes.
      Muitos Discos (20+) VirtIO-SCSI O virtio-blk esgota slots PCI rapidamente (a menos que use pontes PCI complexas). SCSI escala melhor para densidade de LUNs.
      Dispositivos de Fita / Passthrough VirtIO-SCSI Obrigatório. O virtio-blk não passa comandos de controle complexos.

      Resumo Operacional

      1. Pense: O dado precisa de tradução? Se for um DB cru, elimine o intermediário.

      2. Meça: Use perf para ver se a camada SCSI está consumindo >5% da CPU em I/O wait.

      3. Opere: Se mudar para virtio-blk, lembre-se de alterar o nome do dispositivo no /etc/fstab (de /dev/sda para /dev/vda) antes de reiniciar, ou sua VM entrará em kernel panic.

      A performance não é mágica; é engenharia. Elimine o atrito, e a velocidade aparecerá.

      #KVM Storage Tuning #VirtIO Performance #Linux Virtualization #Disk Latency #QEMU Storage
      Marta G. Oliveira

      Marta G. Oliveira

      DevOps Engineer & Storage Nerd

      Automatiza provisionamento de storage com Terraform e Ansible. Defensora do 'Infrastructure as Code' para storage.