Crashing meu disco usando Java

6

Eu tenho um programa em Java que deve fazer as seguintes 3 coisas:

  1. Faça o download de um arquivo de um website.
  2. Execute o arquivo através de testA e testB (ambos em java)
  3. Exclua o arquivo e salve os resultados do teste no disco.

Isso é feito para cerca de 1.000.000 sites diferentes. Era suposto ser uma tarefa bastante simples, já que eu simplesmente colei partes de outros programas: testA e testB já executados separadamente para dezenas de milhões de páginas diferentes sem problemas, e a rotina que baixou as páginas também foi executado por um milhão de páginas algumas vezes, e nunca teve problemas. Todos eles estão sendo executados em uma máquina Ubuntu 10.4.

No entanto, ao fazer esses 3 um após o outro, qualquer disco que os arquivos estavam sendo gravados para falhas. A primeira vez que o executei em um HD USB externo, que tive que desconectar manualmente e reconectar para que ele continuasse a operação (o Linux não reconheceria isso de outra forma). Na próxima vez, em um HD interno, todo o sistema foi desativado e tive que reiniciá-lo manualmente. O mesmo aconteceu ao gravar em um disco RAM.

O problema é que não consigo isolar o problema. Leva muito tempo para que ocorra uma falha (cerca de 50 horas ou mais, mas é bastante aleatório), portanto, os testes demoram muito tempo e não há registros do sistema da falha indicando onde / como isso acontece. A máquina ou HD simplesmente pára de responder.

Exceto pela falha, tudo funciona bem. Os arquivos são criados e excluídos normalmente, os threads não morrem e são executados corretamente, e ambos os testes funcionam bem. Alterar a memória ou o número de threads não teve efeito no tempo de bloqueio. Eu já verifiquei Sockets ou algo parecido não ser fechado, mas eu nem sei como começar a testar, eu não tinha ideia de travar um sistema tão catastroficamente seria possível com Java.

EDIT: Por hangup quero dizer que, quando eu executo em um HD externo o HD não é reconhecido pelo Linux, e quando eu executo no HD interno ou em um Ram Disk o o computador não responderá a nenhuma E / S, sem que nada seja gravado no disco, logs do cactii não sejam gravados, etc. Não é possível conectar-se usando SSH, por exemplo.

Um exemplo de como o programa é executado:

List<String> pagesToDownload = getFromDataBase();
for(i=0;i<NumThreads;i++){
    launchTestThread();
}

E depois, em cada thread:

String pageName = getNextPageToDownload();
File downloadedFile = downloadPage(pageName);
TestAResults testAResults = runTestA(downloadedFile);
TestBResults testBResults = runTestB(downloadedFile);
writeToDatabase(downloadedFile, testAResults, testBResults);
downloadedFile.delete();

Individualmente, as funções runTestA , runTestB e downloadedPage funcionam para quantidades ainda maiores de arquivos, mas, quando chamadas dessa forma, não funcionam. E isso no mesmo hardware.

EDIT2: Acho que descartei o problema de ser o hardware. Um software tão intensivo em hardware foi executado na mesma máquina nos últimos 7 dias sem nenhum problema. De qualquer forma, assim que eu conseguir uma máquina não utilizada, vou testar o programa nela.

Além disso, tudo no teste está sendo gravado no banco de dados até o ponto em que a falha ocorre e os dados estão corretos. O downloadedFile não é passado como parâmetro durante o método writeToDatabase, apenas o nome e tamanho.

Por fim, fiz algumas verificações extensivas de vazamentos de memória ou de manipuladores de arquivos e não encontrei nenhum, inclusive dentro dos testes de trabalho. Neste momento, meu dinheiro está em algum bug estranho na exclusão do arquivo.

EDIT3: Eu finalmente consegui uma outra máquina onde testar a rotina. Outro hardware, mas mesma versão do Ubuntu (10.4 LTS). E também cai lá, então eu realmente duvido que seja um problema de hardware. Isso deixa um bug do sistema operacional, um bug da JVM ou um bug de programação (não há JNI ou algo parecido em execução). Vou tentar executar o teste em algum outro ambiente (configurar um teste no FreeBSD será bem fácil, e posso tentar encontrar uma máquina Windows para testar isso) para verificar isso.

EDIT4: Respondendo a pergunta de Bob Cross sobre o tamanho dos arquivos, eles são páginas típicas da web, com uma média de cerca de 20kb. Eu tenho que deletá-los já que a idéia é expandir o aplicativo, tornando o uso do disco insuportável. Mas vou tentar uma corrida livre de exclusão assim que puder. A máquina onde eu estava rodando esses testes está sendo usada agora, e estou tendo dificuldades em obter algum hardware ocioso.

    
por Phadek 29.09.2010 / 21:44

4 respostas

6

Se o sistema parar de responder, é um bug no sistema operacional ou um problema de hardware. Um programa não deve ser capaz de bloquear um sistema, não importando o quanto seja bugs.

Execute o seu programa em um sistema diferente e veja se ele fornece um diagnóstico útil para o seu programa, em vez de apenas passar por cima.

    
por 29.09.2010 / 22:06
4

É um pouco difícil ver exatamente o que você está fazendo com o resumo acima, mas tentarei fazer uma suposição com base nesse parágrafo:

However, when doing those 3 one after the other, whichever disk the files were being written to crashes. The first time I ran it on a External USB HD, which I had to manually disconnect and reconnect for it to resume operation (Linux wouldn't recognize it otherwise). Next time, on an Internal HD, the whole system went down, and I had to manually restart it. The same happened when writing to a Ram Disk.

Como você gerencia seu arquivo de resultados em relação a essa lista de milhões de sites que está verificando? Especificamente, seu código se parece com isso (segue o pseudocódigo abstraído):

  1. Abra o arquivo de resultados.
  2. O ciclo começa: para cada um milhão de sites
  3. TestA no site
  4. TestB no site: o loop termina
  5. Grave os resultados dos testes do site no arquivo de resultados.

Nesse caso, suspeito que você tenha um problema com o fato de que você está lentamente acumulando resultados que não foram gravados em seu arquivo de resultados. Eu suspeito que eles estão sentados em um dos vários caches esperando por uma chance de liberar essas alterações para o disco.

Se o que você está fazendo acima, tente isso:

  1. O ciclo começa: para cada um milhão de sites
  2. TestA no site.
  3. TestB no site.
  4. Abra o arquivo de resultados.
  5. Grave os resultados dos testes do site no arquivo de resultados.
  6. Fechar o arquivo de resultados: o loop termina

Isso deve garantir que, após cada teste, você escreva um resultado no arquivo. No mínimo, você deve ser capaz de observar o processo do seu programa.

EDIT : acompanhando a edição da pergunta:

writeToDatabase(downloadedFile, testAResults, testBResults); 

Duas perguntas:

  1. As alterações já foram gravadas no seu banco de dados? Como em, eles escrevem por um tempo e depois param? Ou o banco de dados está completamente vazio?

  2. É realmente assim que o código é escrito? Nesse caso, você tem um possível vazamento de memória: essa referência de Arquivo está sendo passada para o método writeToDatabase . Tem certeza de que nada está relacionado a essa referência?

É possível que você esteja mantendo muitas manipulações de arquivo como consequência das referências de arquivo vazadas e / ou identificadores de arquivos nativos. Vale a pena conferir.

EDIT AGAIN com base em mais feedback:

Right now, my money is on some strange bug on the file deletion.

Essa é uma possibilidade. Algumas coisas para pensar:

  1. Qual é o tamanho dos arquivos que você está baixando? Você poderia tentar uma execução de depuração sem as exclusões? Se você correr mais tempo sem esse código, certamente seria um resultado interessante.

  2. Ainda estou preocupado que você esteja vazando identificadores de arquivo. Se você verificar o número de arquivos processados e encontrar algum número suspeito de arquivos processados como um múltiplo de 1024, eu examinarei mais de perto o que quer que esteja no método delete. É um pouco difícil dizer sem a implementação, é claro.

por 29.09.2010 / 21:58
1

Sem mais informações, acho que você preencheu seu disco. Ser incapaz de se conectar via SSH é um pouco estranho, mas é possível se você não conseguir escrever auth.log .

    
por 29.09.2010 / 22:44
0

... é difícil dizer sem informações específicas.

Os fluxos de IO são todos bem fechados depois que os arquivos são gravados? Você tem alguns limites de IO definidos no unix? Existe algum problema de simultaneidade porque eles modificam arquivos ao mesmo tempo? Talvez você também possa fazer alguns Thread.sleep (...) de vez em quando para evitar saturar os discos.

... mas na verdade, eu não tenho ideia, esses são apenas meus dois centavos.

    
por 29.09.2010 / 21:55