De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Dorian Bolivar
Data de Publicação: 27 de setembro de 2016
Se você usa Linux, alguma vez já notou uma lentidão extrema - a ponto de algumas vezes deixar o sistema irresponsivo - ao copiar arquivos grandes, de alguns gigabytes, para mídias lentas, como pendrives USB (especialmente aqueles "genéricos", que oferecem baixa performance)? Se o seu computador é 64 bits e tem bastante memória RAM (8 GB ou mais), muito provavelmente já notou isso. Tanto é que até o Linus Torvalds já abordou esse problema [1], há alguns anos atrás; mesmo assim, ainda não há uma solução definitiva, mas existem tunings do subsistema de Virtual Memory do kernel do Linux que minimizam esse problema.
Antes de continuar, é preciso entender um pouco sobre alguns conceitos do gerenciamento de memória do Linux. Não vou entrar em muitos detalhes, pois este não é um artigo acadêmico, mas no final colocarei algumas referências para quem quiser se aprofundar mais. Um primeiro conceito que deve ficar claro é: o Linux trabalha por padrão com buffered I/O. De forma simplificada, isso significa que as operações de escrita simplesmente copiam os dados para a memória RAM [2], e depois, em background, o kernel vai fazendo a escrita em si (flush) no dispositivo destino. Dado isto, entra o segundo conceito: dirty memory, que é justamente essa informação que está temporariamente na memória RAM, esperando ser escrita em um dispositivo de armazenamento.
Acontece que, quando copiamos muitos dados para uma mídia lenta, há um problema
de bufferbloat, em que a fila de I/O requests fica gigantesca. Isso
acarreta toda a lentidão, já que outras operações de I/O são também afetadas,
além de outros efeitos colaterais. Dentre as alternativas propostas para
minimizar este problema, as mais simples envolvem ajustar os parâmetros
relacionados à dirty memory do subsistema de Virtual Memory do
kernel [3][4]. O objetivo é deixar a fila menor, definindo um threshold
mais agressivo para o flush da dirty memory para o dispositivo (o
daemon que controla isso é o pdflush
, para quem quiser se aprofundar).
Antes de experimentar os ajustes em questão, convém monitorar o seu sistema durante uma simulação, a fim de confirmar o problema. O sintoma mais óbvio é a lentidão, mas se você quiser ir mais a fundo, pode monitorar a quantidade de dirty memory com o seguinte comando:
watch -n1 grep -e Dirty: /proc/meminfo
Enquanto monitora, copie um arquivo grande, de alguns gigabytes, para um pendrive (não vale aquele pendrive USB 3.0 de última geração, hein?). Observe a dirty memory aumentar assustadoramente, para alguns GBs, até que o pdflush entra em ação e começa a escrever os dados no dispositivo.
Percebeu que, aparentemente, a cópia rapidamente deu-se como concluída, mas na prática ela estava longe de terminar? Daí a importância de não remover o pendrive sem ejetar antes: podem haver muitos dados pendentes de escrita em background, e a operação de ejeção só vai concluir após eles estarem devidamente gravados.
Agora, vamos ao tuning: os parâmetros importantes aqui são
vm.dirty_background_bytes
, vm.dirty_background_ratio
,
vm.dirty_bytes
e vm.dirty_ratio
. Na documentação do kernel você
encontra uma explicação detalhada do que cada parâmetro faz [5], mas
pelos nomes já dá para ter uma ideia. Só há um detalhe: os parâmetros com
"bytes" e "ratio" são mutuamente exclusivos, ou seja, ajustando um, o outro
automaticamente é desabilitado (ficando com valor 0). No meu sistema, os
valores default são:
vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 20 vm.dirty_bytes = 0 vm.dirty_ratio = 50
Perceba que até 50% da memória RAM total pode ser dirty! Vamos então ajustar os parâmetros para uma das recomendações, e ver o que acontece, repetindo a simulação:
sysctl -w vm.dirty_background_bytes=16777216 sysctl -w vm.dirty_bytes=50331648 watch -n1 grep -e Dirty: /proc/meminfo (repetir cópia do arquivo)
Bem diferente, não é? Sem contar que agora o indicador de progresso da cópia é mais confiável.
Outra opção, que dá resultados similares mas trabalha com percentuais da memória RAM, ao invés de valores absolutos em bytes, é:
sysctl -w vm.dirty_background_ratio=5 sysctl -w vm.dirty_ratio=10
Tal situação de bufferbloat é mais usual em desktops, onde é comum realizar a cópia de arquivos grandes para pendrives lentos, mas é também possível de acontecer, com cenários alternativos, em servidores, sendo importante conhecer o problema, a solução, e o que está por trás dela. Claro que os valores sugeridos no tuning são, como disse, recomendações; o ideal para o seu caso pode variar.
O que acho mais interessante em solucionar esses problemas é que, quando queremos ir além do básico, além da receita de bolo, aprendemos muito. Espero que também tenha sido sua percepção, e se quiser ir ainda além, é só explorar as referências.
Dorian Bolivar é Engenheiro de Sistemas especialista em Linux, com mais de 15 anos de experiência na área. Trabalha gerenciando diariamente centenas de servidores Linux. Visite o website: http://www.dorianbolivar.com.
This policy contains information about your privacy. By posting, you are declaring that you understand this policy:
This policy is subject to change at any time and without notice.
These terms and conditions contain rules about posting comments. By submitting a comment, you are declaring that you agree with these rules:
Failure to comply with these rules may result in being banned from submitting further comments.
These terms and conditions are subject to change at any time and without notice.
Comentários