| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/01/2012 09:53:26
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
Bom dia,
venho ate vcs hoje com o intuito de obter algumas opiniões sobre o meu projeto de Web Crawler. Vale ressaltar que este é um projeto pessoal, não se trata de "dever de casa" nem nada do gênero.
O meu crawler tem o funcionamento basico de todos os outros
1) visitar um site
2) coletar informações
3) coletar links
4) visitar outro site
O que eu estou tentando é melhorar o desempenho da aplicação e reduzir o consumo de memoria. Ao realizar o passo 3, o crawler insere os links encontrados no frontier global da aplicação.
A estrutura que eu estou usando é um Stack. porem pude reparar que os links na base da pilha não estão sendo visitados. Pensei em utilizar um LinkedList pois cada thread retira o primeiro link da pilha, ou seja, eu não faço remoção no meio do buffer, apenas nas extremidades e o LinkedList comporta estas funcionalidades. Vcs estao de acordo com a escolha ? coinhecem outra estrutura que pode otimizar a performance ?
No teste de stress, rodando com 100 threads, o consumo de memoria alcança a casa dos 200 Mega de RAM, alguem me sujere alguma estrategia para reduzir o consumo de memoria ? eu não gostaria de fazer cache no disco pois isso prejudica o desempenho. Alguma solução mais viavel ?
Percebi tambem que o uso de expressoes regulares para percorrer grandes textos consome muita RAM, isso e normal ?
Bem, se alguem ai ja codificou este tipo de aplicação ? gostaria de sugestões a respeito
Att,
This message was edited 1 time. Last update was at 23/02/2012 07:29:49
|
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/01/2012 10:22:49
|
asaudate
GUJ Master
![[Avatar]](/images/avatar/974e2945a18e0bfb8e3aa8becac3e65c.jpg)
Membro desde: 01/09/2007 19:31:41
Mensagens: 1794
Localização: São Paulo
Offline
|
Nunca fiz nada assim, mas tenho estado bastante interessado em projetos desse tipo, pois estou precisando em um projeto pessoal meu e o que tem de open source ou é complexo demais ou é ruim demais.
Testei recentemente o apache nutch e o crawler4j. O Nutch é extremamente performático, conta com integrações com Hadoop, Solr e tudo o mais, mas é tão complexo que eu não conseguí descobrir como customizar o processo (ou seja, interferir no job map/reduce dele).
O crawler4j é mais simples, permite fazer isso, mas a cada release lançada são bugs novos, sem contar que não é compatível com as versões anteriores. Está sendo um pesadelo.
Estou pensando em começar a desenvolver um que atenda às minhas necessidades, mas partindo do ponto de aprendizado que estes projetos já me deram. Se estiver interessado em uma parceria, me mande uma MP.
[]'s
|
Alexandre Saudate
__________________________
Do not try to bend the spoon - that's impossible. Instead, only try to realize the truth: there is no spoon.
Série quickstart: Spring+Spring Security+Jersey (REST) +Hibernate (JPA) -> https://github.com/alesaudate/kickstart-springjerseyhibernate
Evite usar Axis2!!! Leia aqui para mais detalhes!
@alesaudate
Quer ler um blog especializado em web services e SOA?
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 09/01/2012 11:11:27
|
HumbertoJr
JavaBaby
Membro desde: 17/01/2004 20:15:38
Mensagens: 77
Offline
|
Cara,tenta dar uma lida no livro "A Arte do Java",nele tem um capítulo sobre como fazer um webcrawler que e´muito interessante!
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 13/01/2012 09:14:09
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
Pessoal , preciso mesmo de ajuda, eu alterei o projeto para gravar os links no MySQL, pq pensei que armazenar os links na memoria estivesse consumindo muita RAM, os dados encontrados tambem estao sendo armazenados no SGBD.
Fiz isso para evitar a criação de muitos objetos para acesso ao disco, mas mesmo assim as threads estão consumindo muita RAM e gerando Out Of Memory
não sei como resolver
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 13/01/2012 09:23:10
|
asaudate
GUJ Master
![[Avatar]](/images/avatar/974e2945a18e0bfb8e3aa8becac3e65c.jpg)
Membro desde: 01/09/2007 19:31:41
Mensagens: 1794
Localização: São Paulo
Offline
|
mmx wrote:Pessoal , preciso mesmo de ajuda, eu alterei o projeto para gravar os links no MySQL, pq pensei que armazenar os links na memoria estivesse consumindo muita RAM, os dados encontrados tambem estao sendo armazenados no SGBD.
Fiz isso para evitar a criação de muitos objetos para acesso ao disco, mas mesmo assim as threads estão consumindo muita RAM e gerando Out Of Memory
não sei como resolver
Em geral, os crawlers não salvam esse tipo de dado em bancos relacionais - até porque, esse tipo de coisa tem mais cara de bancos OLAP do que OLTP. É mais a cara de processadores como o Hadoop do que o MySQL. Tem também o BerkeleyDB, que é o que o crawler4j usa.
Quanto ao seu OutOfMemory, um bom profiler deve ajudar (aliás, pra esse tipo de aplicação, o uso de um profiler deve ser prática constante). Recomendo o JProfiler.
This message was edited 1 time. Last update was at 13/01/2012 09:47:18
|
Alexandre Saudate
__________________________
Do not try to bend the spoon - that's impossible. Instead, only try to realize the truth: there is no spoon.
Série quickstart: Spring+Spring Security+Jersey (REST) +Hibernate (JPA) -> https://github.com/alesaudate/kickstart-springjerseyhibernate
Evite usar Axis2!!! Leia aqui para mais detalhes!
@alesaudate
Quer ler um blog especializado em web services e SOA?
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 13/01/2012 09:31:11
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
obrigado por responder, vou pesquisar sobre as suas sugestões e posto os resultados
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/01/2012 01:01:44
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
bom, eu passei o projeto para o netbeans para usar o profiler, bem eu nunca tinha usado ele antes, mas se eu interpretei certo,
eu pude perceber o total de objetos de cada classe, e percebi que a API que eu estou usando pra trabalhar com HTML, a JSoup, pode ser o gargalo do meu programa.
\
percebi um grande consumo de objetos String, byte[] e char[], que estavam vindo da minha função para obter codigo de uma pagina web. O codigo e obtido mas pelo visto a memoria não e liberada.
observei que alimentando o meu buffer de links, com o limite maximo, mantem o consumo de RAM estavel, mesmo com 100 threads, parsear os dados com o uso de regex tb não consumiu muita memoria
Alguem conhece alguma maneira eficiente de obter codigo de uma pagina web que não consuma muita memoria ram ?
grato
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/01/2012 21:26:40
|
Stacker
Thread.start()
![[Avatar]](/images/avatar/6829204300eae5172fe01ae8e160b634.jpg)
Membro desde: 20/01/2012 18:06:40
Mensagens: 48
Offline
|
Eu estou projetando um Web Crawler somente por diversão, e sei o problema que você está tendo.
Na verdade, não é que as URLs da base da sua pilha nunca esteja sendo visitada, o problema é que a sua pilha sempre vai receber novas URL, fazendo com que a base sempre esteja com um nível de prioridade inferior.
Vamos imaginar por exemplo um site com a seguinte estrutura:
Index
|--- Produtos
|--- Funcionários
|--- Sobre
|--- Contato
|--- Telefone
|--- Email
O nosso Web Crawler começa a varrer os links da página Index. Então a pilha ficaria da seguinte forma:
Index -> Produtos -> Funcionários -> Sobre -> Contato (Contato é o topo da nossa pilha no momento).
Uma vez que varremos a Index, devemos passar para a próxima página. Aqui vai depender da sua lógica, mas vamos supor que ela pegue como próxima página o topo da nossa pilha. Sendo assim, nossa pilha ficaria da seguinte forma:
Index -> Produtos -> Funcionários -> Sobre -> Contato -> Telefone -> Email
E depois o processo iria se repetir até chegar em um momento onde não se tem mais saída (Algo quase impossível de ocorrer, considerando a topologia da rede).
Caso a sua lógica não seja essa, posta aqui no tópico a sua lógica para nós discutir.
O que eu acho o ideal é construir uma lista de adjacências, onde a lista principal são as páginas pai, e as de adjacência são as páginas filho. Dessa forma eu consigo controlar e analisar a semântica das conexões.
Veja o esquema abaixo:
Index -> Produtos -> Funcionários
|
Produtos -> Eletrônicos
|
Funcionários - Administrativos -> Operacional
Fica muito fácil trabalhar com as URLs organizadas em Pai/Filho e também útil para extrair informações.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/01/2012 22:08:30
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
Stacker, vc esta certo, a minha logica era essa mesmo, então eu alterei a estrutura para uma fila FIFO. A ordem dos links a serem vivitados não tem importancia no meu caso, tambem criei filtros pro spider rodar so dentro de um site se eu quiser, pq tava acontecendo do meu spider começar em um dominio e acabar parando em sites que eu não queria.
O meu grande problema agora e liberar memoria. Mesmo atribuindo null para as referencias de objetos , a memoria não é desalocada. Vou colocar o codigo de teste que eu estou avaliando
a memoria não cresce muito porem não é liberada. Eu creio que este codigo esta correto. Como que vc esta fazendo para pegar o codigo html de um site ? a sua função consome muita memoria ?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/01/2012 22:19:56
|
Stacker
Thread.start()
![[Avatar]](/images/avatar/6829204300eae5172fe01ae8e160b634.jpg)
Membro desde: 20/01/2012 18:06:40
Mensagens: 48
Offline
|
Utilize a biblioteca import java.net.* e use a classe URL.
Fica bem mais fácil de baixar conteúdo.
Eu ainda não terminei a implementação do meu Web Crawler, só trabalho nisso nas horas vagas, então não sei como será o consumo de memória.
Só terminei de implementar minhas estruturas de dados, que eu fiz questão de implementar do zero para ter maior controle.
Quanto ao consumo, onde você está armazenando essas páginas para o analisador sintático identificar os links?
Depois de quantas páginas analisadas que o consumo de memória aumenta?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 20/01/2012 22:22:32
|
Stacker
Thread.start()
![[Avatar]](/images/avatar/6829204300eae5172fe01ae8e160b634.jpg)
Membro desde: 20/01/2012 18:06:40
Mensagens: 48
Offline
|
Desculpa, agora que vi que você armazena numa String.
Nem prestei muita atenção no código .
Vou testar aqui no meu computador e já te respondo.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 21/01/2012 18:52:22
|
Stacker
Thread.start()
![[Avatar]](/images/avatar/6829204300eae5172fe01ae8e160b634.jpg)
Membro desde: 20/01/2012 18:06:40
Mensagens: 48
Offline
|
Eu acho que descobri o motivo pelo qual o consumo de memória está alto, mas antes eu preciso saber como você está identificando os links da página.
Você pode postar o código completo?
Certamente você está visitando a mesma página várias vezes, o que está acarretando em um maior consumo de memória.
O problema de estar visitando uma mesma página várias vezes é proveniente da lógica da Pilha.
Recomendo você experimentar a lista ligada de adjacências, seguindo a regra que descrevi anteriormente.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 23/01/2012 23:08:48
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
Stacker, não creio que seja este o motivo do meu consumo de memoria alto. o meu memory leak deve estar em dois pontos
1- As APIs do JSoup que eu estou usando pois não sei como elas trabalham com a memoria
2 - O meu buffer de links que é na verdade um ArrayBlockingQueue ou seja é uma fila
Como não da pra trabalhar com indices na fila, não da pra mim setar uma posição com NULL e eu não sei se ao executar um fila.pool() este fato ocorre
Mas vamos aos fatos, eu to trabalhando com 100 threads. é mais facil pro SO criar uma thread do que o contexto inteiro de um processo, mas cada thread vai consumnindo os recursos do meu programa ate atingir o limie e derrubar a maquina virtual.
Criar threads esta aumentando do consumo de RAM, mas pelo visto é algo inevitavel. Tem outro fator ai nesse meio, o buffer de links que é alimentado muito mais rapido do que é consumido
por exemplo se eu visitar um site e extrair 20 links dele, eu consumi 1 e inseri 20 no buffer. Se eu visitar 3 sites eu consumo 3 e terei um buffer com total de 60 links, ou seja, o buffer cresce muito rapido e consome mais RAM, e este buffer so contem links unicos.
eu estou pensando em algumas saidas:
1 - setar a memoria que a maquina virtual vai usar
2 - modularizar o projeto e transformar cada funcionalidade em um novo programa, vai ser custoso pro SO ficar chamando a maquina virtual com frequencia, mas a RAM vai sendo desocupada.
3 - trocar o JSoup pra metodos desenvlvidos por mim, pra controlar os objetos criados, etc
4- testar outras APIs
O Spider fatalmente vai consumir muita banda de rede e memoria, a banda de rede nõa me importa, o link pode ser sugado sem problemas, mas a RAm pode dar muita dor de cabeça, estas medidas que eu citei podem servir de alguma coisa
Vc concorda com o meu ponto de vista ? vcs do GUJ concordam ? sugerem outra coisa ?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 23/01/2012 23:14:33
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
esqueci de mencionar que o meu buffer de links e global e todas as threads inserem e removem links neste buffer, ou seja, os acessos são synchronized ok ? é o meu unico objeto static
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 27/01/2012 05:32:00
|
mmx
Entusiasta Java
Membro desde: 08/04/2008 15:40:11
Mensagens: 23
Offline
|
up !
|
|
|
 |
|
|