Como a chamada contínua sync () pode causar alta espera de IO?

1

Pelo que entendo da chamada da biblioteca sync() é que ela permite que um processo libere todos os buffers sujos no disco

The service routine sys_sync( ) of the sync( ) system call invokes a series of auxiliary functions:

wakeup_bdflush(0);
sync_inodes(0);
sync_supers( );
sync_filesystems(0);
sync_filesystems(1);
sync_inodes(1);

Se eu executar sync() uma vez, depois disso, não deverá haver nada no buffer.

Estou usando uma ferramenta chamada stress que, quando executada com -i flag gera N funcionários girando em sync ()

stress --i 1

Este comando supõe consumir uma alta espera de E / S, pois ele continua enviando sync() chamadas, Eu confirmei usando ltrace ,

sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0
sync()                                                                                                               = 0

Alguém pode explicar por que as chamadas de sincronização contínuas consomem muitos pedidos de veiculação? Eu estava assumindo que, após a primeira sincronização, o buffer de chamadas deveria estar vazio.

    
por MaverickD 15.10.2018 / 04:49

1 resposta

0

sync () é como um commit de banco de dados, mas para o seu disco. (na verdade, para bancos de dados transacionais, um commit geralmente envolve uma chamada sync () para ajudar a garantir o ACID ... você precisa se esforçar para evitá-lo) Em vez de passar pelos canais normais de otimização de desempenho do sistema operacional, está dizendo ao sistema operacional: 'faça isso agora mesmo!' Com a fiação, o desempenho dos discos mecânicos tem tudo a ver com a física: leva tempo para a unidade posicionar a cabeça onde quer que seja para realmente executar a operação solicitada (e mesmo quando chega lá, ela tem que esperar o disco girar para a posição correta sob a cabeça antes que ele possa fazer o que veio para fazer.) Quando você está constantemente (ou mesmo ocasionalmente) sincronizando, você está evitando muitas oportunidades de otimizar este trabalho via buffering e agendamento. Observe também que quando você chama sync (), você está fazendo isso para todas as gravações pendentes no sistema de arquivos , incluindo metadados, não apenas um único arquivo ou sistema de arquivos.

Então, vamos ver um cenário simplificado em que você tem um programa que precisa gravar quatro setores no disco: um na trilha mais interna (w1), um na faixa mais externa (w2), um na trilha do meio da trilha. disco (w3), e finalmente um de volta na pista mais interna (w4) ...

Se o seu programa gravar w1, em seguida, chama sync (), o seu sistema imediatamente manda a unidade executar a gravação, o que faz com que a unidade se mova até a faixa mais interna e escreva o setor. Então w2 ocorre seguido por um sync (), então agora o drive tem que percorrer todo o caminho até a pista externa para escrever o setor. Próxima w3 ocorre e a unidade tem que voltar para o centro do disco e escrever o setor. Finalmente w4 ocorre e a unidade tem que voltar para a pista mais interna e escrever o setor. O que a CPU está fazendo o tempo todo que a cabeça da unidade está movendo? Literalmente esperando.

Se você não tivesse feito todas essas chamadas sync (), o SO armazenaria todas essas gravações e retornaria imediatamente ao programa ('sim, sim ... eu chego a ele eventualmente') e agora tem w1-w4 em buffer. Tanto o sistema operacional quanto a unidade podem agendar as solicitações de qualquer maneira que faça sentido, sem forçar a unidade a escrever cada setor independentemente ou mesmo em ordem. Então, digamos que o sistema operacional decidiu executar a gravação depois que o w4 entrou, ele irá enviar todas as 4 gravações para a unidade e a unidade pode ver que w1 e w4 devem ser executados primeiro (ou seja, a faixa mais interna), então deve fazer w3 (a faixa do meio) e, finalmente, w2 (a faixa mais externa). Então, ao invés de 4 buscas separadas (que são medidas em milissegundos), ele está apenas fazendo 3. E cada busca é menor em distância linear e, portanto, mais rápida, do que no cenário sync (). Comece multiplicando essa ineficiência por centenas de vezes ou mais e você começa a ver por que está gastando todo o seu tempo esperando quando você constantemente sincroniza (). As unidades flash têm eficiências de programação semelhantes (ou seja, várias gravações no mesmo bloco, etc.), mas elas não têm a mesma ordem de magnitude de impacto que as unidades mecânicas fazem.

    
por 15.10.2018 / 06:33

Tags