[SP-pm] downloader survey

Stanislaw Pusep creaktive at gmail.com
Mon Oct 24 06:20:17 PDT 2011


Thiago, muito obrigado pela excelente resposta!
Realmente, há muita coisa a ser considerada, todavia, ainda estou longe de
chegar no gargalo do TCP/IP em si.
O que eu percebi é que, infelizmente, não existe nenhum módulo no CPAN
apropriado para gerenciar downloads de listas longas de URLs (as minhas
listas são de ~500 mil URLs de arquivos estáticos por sessão). Sim, é
possível usar LWP e apelar para um fork(), mas aí vi que consumia RAM/CPU
demais, *quando comparado a um processo externo*.
E, para mim, como programador Perl, é deveras frustrante delegar os
downloads ao lftp (http://lftp.yar.ru/)... Afinal, o que o lftp tem de tão
bom que eu não possa fazer em Perl?! ;)
Então, implementei o AnyEvent::Net::Curl::Queued, que é capaz de gerenciar
filas bem grandes de downloads, de forma assíncrona. Mas será que compensa
usá-lo ao invés do lftp? Para isso, comecei fazendo benchmarks.
Agradeço a todos pelas sugestões! Seguem as minhas observações:

   1. Eden, você está certo, os "filhotes" do LWP tem uma inicialização
   muito lenta; e o mais curioso é que boa parte da inicialização não está no
   new() propriamente dito, mas é feita durante o primeiro request(). Então,
   para ser justo, dividi a minha fila de downloads em 10 filas separadas, e
   aloquei um fork() para cada uma;
   2. LWP::Curl e AnyEvent::Multi::Curl são ambos derivados do WWW::Curl.
   Não vale a pena testar o WWW::Curl "cru", na minha opinião;
   3. LWP::Curl + forks é mais rápido do que a interface CLI do curl (ambos
   paralelizados do mesmo jeito que o LWP, com 10 filas independentes)!!!
   Atribuo isso a uma esquisitice do curl na hora de extrair as informações
   sobre o download: por alguma razão, esse processo é MUITO lento;
   4. wget tem o menor overhead de todas as alternativas por ser
   ridiculamente simples. Quase não tem dependências, por isso a sua
   inicialização é quase que instantânea;
   5. AnyEvent::HTTP é a melhor alternativa para acessar uma quantidade
   limitada de URLs *em paralelo*. Porém, para listas razoavelmente grandes,
   gerenciamento via callbacks e closures é meio tenebroso...
   6. Reiterando: o *MEU* interesse se restringe a pegar meio milhão de URLs
   e baixar de forma mais eficiente possível (isso é, o gargalo deve ser minha
   bandwidth, não minha CPU/RAM). Nesse caso, pouco me importa a possibilidade
   de fazer parsing de headers, gerenciar cookies ou processamento de HTML.
   Isso é, quando eu quiser, devo poder habilitar tudo isso; mas o default deve
   ser OFF. Portanto, o meu "Holy Grail" seria um libwget, que gerencia filas,
   extrai links e faz downloads recursivos :)

Para fechar, segue a tabela de benchmark atualizada:

                            URL/s WWW::Mechanize LWP::UserAgent HTTP::Lite
HTTP::Tiny AnyEvent::Curl::Multi  lftp AnyEvent::Net::Curl::Queued
AnyEvent::HTTP  curl LWP::Curl  wget
 WWW::Mechanize                196             --           -60%
-80%       -85%                  -86%  -88%
-89%           -92%  -97%      -97% -100%
 LWP::UserAgent                484           148%             --
-51%       -63%                  -66%  -70%
-72%           -80%  -93%      -93%  -99%
 HTTP::Lite                    989           405%           104%
--       -25%                  -32%  -39%
-42%           -59%  -85%      -86%  -99%
 HTTP::Tiny                   1312           569%           170%
33%         --                   -9%  -19%
-23%           -46%  -80%      -82%  -99%
 AnyEvent::Curl::Multi        1446           638%           198%
46%        10%                    --  -10%
-16%           -41%  -78%      -80%  -98%
 lftp                         1609           722%           232%
63%        23%                   11%    --
-6%           -34%  -75%      -77%  -98%
 AnyEvent::Net::Curl::Queued  1713           773%           253%
73%        30%                   18%    6%
--           -30%  -74%      -76%  -98%
 AnyEvent::HTTP               2437          1144%           403%
146%        86%                   69%   51%
42%             --  -63%      -66%  -97%
 curl                         6512          3228%          1244%
559%       397%                  351%  305%
281%           167%    --       -8%  -93%
 LWP::Curl                    7110          3524%          1364%
618%       442%                  391%  341%
315%           191%    9%        --  -92%
 wget                        88875         45240%         18215%
8877%      6675%                 6045% 5418%
5092%          3544% 1262%     1151%    --

ABS()



2011/10/20 Thiago Rondon <thiago em aware.com.br>

> On Thu, Oct 20, 2011 at 05:25:20PM -0200, Stanislaw Pusep wrote:
> >    OK, aqui vai o spoiler: estou fazendo benchmark (de overhead) de todos
> os
> >    HTTP agents que conheAS:o. E oA LWP estA! *MUITO* feio na fita:
> >    https://metacpan.org/module/AnyEvent::Net::Curl::Queued#OVERHEAD
> >    ABS()
>
> Stan,
>
> Eu vou apontar para outro lado, já que me parece que teu objetivo é
> perfomance para efetuar download de arquivos via http (tcp), e você
> já esta testando as alternativas que há como módulo para realizar
> tua tarefa. :)
>
> Me parece que teu caso é:
>
> - Uso do protocolo HTTP para baixar arquivos ;
> - Encontrar o melhor algoritimo para trabalhar em paralelo no seu
>  aplicativo;
> - Verificar se você tem "banda" necessária para este trabalho.
>
> Primeiramente, é interessante saber, quanto de banda você tem
> disponível ? Qual o tamanho dos arquivos que você vai efetuar download ?
> Ou seja, qual sua capacidade para buscar os arquivos, e qual
> 'concorrencia' ?
>
> Como é um caso para conectividade em paralelo, é interessante levantar
> alguns pontos da tua rede e do teu sistema operacional para saber se ele
> suporta e esta preparado para esta demanda. Isto pode afetar o
> comportamento
> de alguns módulos.
>
> Apesar do kernel 2.6 já ter muita coisa para o "autotuning" na pilha
> TCP, é interessante olhar para alguns parametros, tais como:
>
> - net/core/[r,w]mem_max e net/ipv4/tcp_[r,w]mem pode ser muito interessante
> em
>  casos onde há conexões em paralelo, com excesso uso de conexões e
>  dados.
>
> - net/ipv4/tcp_available_congestion_control - Este é um assunto que vale
>  ler, dependendo do local, da 'qualidade do link' você pode optar por
>  um algoritimo, se tiver banda em excesso e etc, pode ser outra. Há
>  muita atualização destes algoritimos ao longo do desenvolvimento do
>  kernel 2.6, vale verificar e atualizar o kernel se você for alterar
>  este parametro.
>
> - txqueuelen é um bom parametro também para ser trabalhado, pois pode te
>  oferecer uma boa perfomance neste cenário também, este parametro é
>  efetuado no device, por exemplo 'ifconfig eth0 txqueuelen 100000'
>
> Em relação ao algoritimo de concorrencia, dependendo da quantidade que
> você quer, e se você esta de olho em perfomance, é interessante olhar
> para o epoll no Linux. Eu ainda não usei os módulos que trabalham
> diretamente com ele, como o IO::Epool, mas há muita coisa surgindo
> baseado nesta caracteristica "nova" que esta disponível no kernel,
> tais como nginx e etc. Fica uma pergunta.. Será que isto vai fazer
> realmente diferença ? Eu não sei, mas gostaria de ver seus resultados
> aqui. :)
>
> Agora, o HTTP você pode utilizar o keep alive, dependendo também das
> suas requisições, são para o mesmo host ? Se você tiver uma lista, é
> uma boa ordenar por host, e dividir elas entre os processos que você
> vai separar, ou seja, se você tiver 30 arquivos no host X, e 30 no
> arquivo Y, organize eles para se aproveitar do keep alive, ou se for
> tudo diferente desative ele.
>
> Se os arquivos não foram compactados, e dependendo do tipo, e se
> banda for um 'problema', talvez vale apena ativar a compactação para
> buscar os arquivos, onde os servidores suportarem.
>
> Se a lista for 'grande' e 'diversificada', use o dns cache, e vá
> resolvando os nomes antes, para economizar uma etapa na hora que
> for para 'buscar'.
>
> Tome cuidado com roteadores bizarros que 'zoem' o MTU, isto pode
> afetar bastante, um MTU alto pode te ajudar com transferir pacotes
> com dados grandes.
>
> Enfim, foram ideias que tive agora sobre o problema. :)
>
> Acredito que o restante da discussão, é o que você já tá procurando,
> que é como os módulos trabalham, e efetuam a tarefa que você quer,
> mas poste os resultados aqui, pois também estou curioso. :-)
>
> Ps.: Lembre-se que todos os valores no /proc são volateis, então use o
> sysctl
> para manter ele persistente no teu sistema. :)
>
> Abs!
> -Thiago Rondon
> =begin disclaimer
>   Sao Paulo Perl Mongers: http://sao-paulo.pm.org/
>  SaoPaulo-pm mailing list: SaoPaulo-pm em pm.org
>  L<http://mail.pm.org/mailman/listinfo/saopaulo-pm>
> =end disclaimer
>
-------------- Pr�xima Parte ----------
Um anexo em HTML foi limpo...
URL: <http://mail.pm.org/pipermail/saopaulo-pm/attachments/20111024/0ac020eb/attachment-0001.html>


More information about the SaoPaulo-pm mailing list