tar lento no Ubuntu Server

1

Eu tenho dois servidores (acessados via SSH da Internet), um com CPU de alto desempenho e 32 GB de RAM. No entanto, quando eu tento tar um grande número de arquivos (cerca de 400.000) através do comando:

tar cvf archive.tar folder

Demora cerca de 2 horas. Quando eu executo o mesmo comando no meu computador, que tem uma especificação similar, mas menos RAM, demora cerca de 5 minutos para colocar um lote similar de arquivos.

Alguém tem alguma ideia ou alternativa? A linha de comando gera uma lista de todos os arquivos. Não sei se isso causa problemas.

    
por Kohjah Breese 07.04.2016 / 01:11

1 resposta

2

Fragmentação de disco. Se forem arquivos grandes, você pode usar filefrag para verificar a fragmentação dos arquivos individuais, mas há outro tipo de fragmentação que tende a acontecer com muitos arquivos pequenos: a ordem em que os nomes aparecem no diretório pode ser completamente diferente de a ordem em que os inodes aparecem no disco, e essa ordem pode ser completamente diferente da ordem dos blocos de dados no disco. Isso significa que quando você abre todos os arquivos na ordem em que seus nomes aparecem no diretório, o disco precisa procurar muito e atrasa as coisas. Escrevi o seguinte script python uma vez para calcular a correlação entre nomes, inodes e o primeiro bloco de dados de todos os arquivos no diretório atual, para que você possa medir isso:

#!/usr/bin/python

import os
from stat import *
import fcntl
import array

names = os.listdir('.')
lastino = 0
name_to_ino_in = 0
name_to_ino_out = 0
lastblock = 0
name_to_block_in = 0
name_to_block_out = 0
iblocks = list()
inode_to_block_in = 0
inode_to_block_out = 0

for file in names :
    try :
        st = os.stat(file)
    except OSError:
        continue
    if not S_ISREG(st.st_mode) :
        continue
    if st.st_ino > lastino :
        name_to_ino_in += 1
    else : name_to_ino_out += 1
    lastino = st.st_ino    
    f = open(file)
    buf = array.array('I', [0])
    err = fcntl.ioctl(f.fileno(), 1, buf)
    if err != 0 :
        print "ioctl failed on " + f
    block = buf[0]
    if block != 0 :
        if block > lastblock :
            name_to_block_in += 1
        else : name_to_block_out += 1
        lastblock = block
        iblocks.append((st.st_ino,block))
print "Name to inode correlation: " + str(float(name_to_ino_in) / float((name_to_ino_in + name_to_ino_out)))
print "Name to block correlation: " + str(float(name_to_block_in) / float((name_to_block_in + name_to_block_out)))
iblocks.sort()
lastblock = 0
for i in iblocks:
    if i[1] > lastblock:
        inode_to_block_in += 1
    else: inode_to_block_out += 1
    lastblock = i[1]
print "Inode to block correlation: " + str(float(inode_to_block_in) / float((inode_to_block_in + inode_to_block_out)))

Sistemas de arquivos antigos que tiveram muitos arquivos pequenos adicionados por um longo tempo tendem a ficar em má forma. Simplesmente copiar o diretório inteiro pode resultar em um destino muito melhor, então você pode excluir o original e substituí-lo pela cópia. O segundo problema que contribui para isso é o recurso de diretório indexado da htree do ext4, que é usado em diretórios com muitos arquivos neles para tornar a procura de um nome de arquivo individual muito mais rápido, mas essencialmente randomiza completamente a ordem dos nomes. Você pode verificar se um diretório está usando htrees com lsattr -d e procurar o atributo I .

Uma das razões pelas quais eu prefiro fazer backup com dump em vez de tar é que ele é imune a esse problema, pois lê todos os arquivos na ordem inode, independentemente da ordem em que os nomes aparecem no diretório. Ele ainda tem que lidar com o inode para bloquear a fragmentação. Uma cópia ou um passe de e2defrag pode ajudar com isso.

    
por psusi 07.04.2016 / 01:33