[Dicas-L] Linux Virtual Memory Management e lentidao ao copiar arquivos grandes para midia lenta
Colaboração: Dorian Bolivar
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:
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
(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, é:
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.
http://yarchive.net/comp/linux/dirty_limits.html
http://lwn.net/Articles/682582/
http://unix.stackexchange.com/questions/107703/why-is-my-pc-freezing-while-im-copying-a-file-to-a-pendrive/107722#107722
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.