Programa C travou em espera ininterrupta durante a execução de E/S de disco no Mac OS X Snow Leopard

StackOverflow https://stackoverflow.com/questions/2017283

  •  19-09-2019
  •  | 
  •  

Pergunta

Uma linha de fundo:Eu sou o desenvolvedor de Redis, um banco de dados NoSQL.Uma das novidades que estou implementando é a Memória Virtual, pois o Redis leva todos os dados na memória.Graças ao VM Redis ser capaz de transferir objetos raramente usados ​​da memória para o disco, há uma série de razões pelas quais isso funciona muito melhor do que deixar o sistema operacional fazer o trabalho para nós trocando (objetos redis são construídos a partir de muitos objetos pequenos alocados em espaços não contíguos lugares, quando serializados em disco pelo Redis eles ocupam 10 vezes menos espaço em comparação com as páginas de memória onde residem e assim por diante).

Agora tenho uma implementação alfa que funciona perfeitamente no Linux, mas não tão bem no Mac OS X Snow Leopard.De vez em quando, enquanto o Redis tenta mover uma página da memória para o disco, o processo do Redis entra no estado de espera ininterrupto por alguns minutos.Não consegui depurar isso, mas isso acontece em uma chamada para fseeko() ou fwrite().Depois de minutos a chamada finalmente retorna e o redis continua funcionando sem nenhum problema:nenhum acidente.

A quantidade de dados transferidos é muito pequeno, algo como 256 bytes.Portanto, não deve ser uma questão de uma grande quantidade de E/S executada.

Mas há um detalhe interessante sobre o arquivo swap que é alvo da operação de gravação.É um arquivo grande (26 Gigabytes) criado abrindo um arquivo com fopen() e depois ampliado usando ftruncate().Finalmente o arquivo é unlink()ed para que o Redis continue a fazer referência a ele, mas temos certeza de que quando o processo Redis sair, o sistema operacional realmente liberará o arquivo de troca.

Ok, isso é tudo, mas estou aqui para mais detalhes.E, a propósito, você pode até encontrar o código real no Redis git, mas não é trivial entender em cinco minutos, visto que é um sistema bastante complexo.

Muito obrigado por qualquer ajuda.

Foi útil?

Solução

Pelo que entendi, o HFS+ tem suporte muito ruim para arquivos esparsos.Portanto, pode ser que sua gravação esteja acionando uma expansão de arquivo que está inicializando/materializando uma grande fração do arquivo.

Por exemplo, eu sei que mapear um novo arquivo grande e vazio e depois gravar em alguns locais aleatórios produz um arquivo muito grande no disco com HFS +.É muito irritante, pois mmap e arquivos esparsos são uma maneira extremamente conveniente de trabalhar com dados, e praticamente todas as outras plataformas/sistemas de arquivos existentes lidam com isso normalmente.

O arquivo de troca é gravado linearmente?Significa que substituímos um bloco existente ou escrevemos um novo bloco no final e incrementamos um ponteiro de espaço livre?Nesse caso, talvez fazer chamadas ftruncate menores e mais frequentes para expandir o arquivo resultasse em pausas mais curtas.

Além disso, estou curioso para saber por que o redis VM não usa mmap e apenas move os blocos na tentativa de concentrar blocos quentes em páginas quentes.

Outras dicas

antirez, não tenho certeza se serei de muita ajuda, pois minha experiência com a Apple é limitada ao Apple ][, mas vou tentar.

A primeira coisa é uma pergunta.Eu teria pensado que, para memória virtual, a velocidade de operação seria uma medida mais importante que o espaço em disco (especialmente para um banco de dados NoSQL onde a velocidade é o ponto principal, caso contrário você estaria usando SQL, não?).Mas, se o seu arquivo de troca for 26G, talvez não :-)

Algumas coisas para tentar (se possível).

  1. Tente realmente isolar o problema para procurar ou escrever.Tenho dificuldade em acreditar que uma busca possa demorar tanto, pois, na pior das hipóteses, deveria ser uma mudança no ponteiro do buffer.Ainda assim, não escrevi o OSX, então não posso ter certeza.
  2. Tente ajustar o tamanho do arquivo de troca para ver se é isso que está causando o problema.
  3. Você já expandiu dinamicamente o arquivo de troca (em oposição à pré-alocação)?Se você fizer isso, pode ser isso que está causando o problema.
  4. Você sempre escreve o mais baixo possível no arquivo?Pode ser que a criação de um arquivo 26G não o preencha com dados, mas, se você criá-lo e gravar no último byte, o sistema operacional poderá ter que zerar os bytes antes disso (adiando a inicialização, se houver).
  5. O que acontece se você pré-alocar o arquivo inteiro (gravar em cada byte) e não desvinculá-lo?Em outras palavras, deixe o arquivo lá entre as execuções do seu programa (criando-o se ele ainda não existir, é claro).Em seguida, em seu código de inicialização do Redis, basta inicializar o arquivo (ponteiros e outros).Isso pode eliminar quaisquer problemas como os do ponto 4 acima.
  6. Pergunte também nos vários sites do BSD.Não tenho certeza de quanto a Apple mudou nos bastidores, mas o OSX é apenas BSD no nível mais baixo (Pax se abaixa para se proteger).
  7. Considere também perguntar nos sites da Apple (se ainda não o fez).

Bem, essa é a minha pequena contribuição, espero que ajude.Boa sorte com seu projeto.

Você desativou o cache do seu arquivo?ou sejafcntl(fd, F_GLOBAL_NOCACHE, 1)

Você já tentou depurar com DTrace e/ou Instruments (front-end dtrace experimental da Apple)?

Explorando o Leopard com DTrace

Depurando o Chrome no OS X

Como Linus disse uma vez na lista de discussão do Git:

"Percebo que as pessoas do OS X têm dificuldade em aceitá -lo, mas os sistemas de arquivos OS X geralmente são uma porcaria total e total - ainda mais que o Windows".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top