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.
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.
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).
O Guest escreve dados no buffer ("Quero gravar X no setor Y").
O Guest toca uma campainha (o mecanismo de
kickou VMExit) para avisar o Host. Isso é custoso. O processador para o que a VM está fazendo e troca de contexto para o Host.O Host acorda, lê o papel, executa a gravação no hardware real.
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.
Slots PCI: Cada disco consumia um slot PCI endereçável. Havia um limite de cerca de 28 discos por VM.
Recursos: O suporte a
discard(TRIM) demorou a chegar e amadurecer novirtio-blk, embora em kernels modernos (5.0+ e QEMU recentes) isso já esteja resolvido ou mitigado via configuração (discard=on).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.
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 usandoscsi-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_commandouscsi_dispatch_cmd, você está pagando o "imposto SCSI".No
virtio-blk, você verá chamadas diretas paravirtio_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
Pense: O dado precisa de tradução? Se for um DB cru, elimine o intermediário.
Meça: Use
perfpara ver se a camada SCSI está consumindo >5% da CPU em I/O wait.Opere: Se mudar para
virtio-blk, lembre-se de alterar o nome do dispositivo no/etc/fstab(de/dev/sdapara/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á.
Marta G. Oliveira
DevOps Engineer & Storage Nerd
Automatiza provisionamento de storage com Terraform e Ansible. Defensora do 'Infrastructure as Code' para storage.