Cache efetivo de vídeos do Youtube com Squid
Uns meses atrás, fiz um post no meu blog sobre como fazer cache no Youtube. Apesar de funcionar, a solução não era eficaz. Isso porque o Youtube possui um sistema de balanceamento de banda, enviando-nos cada vez para um subdomínio diferente. A solução fazia o cache do recurso; no entanto, dificilmente utilizava-o.
Pesquisando na Internet, encontrei a resposta para o problema. A solução é um recurso dentro do próprio squid. Seu objetivo é criar uma equivalência entre URLs diferentes. Para tanto, chama um programa externo (um helper), que deve ser criado por nós.
Veja seu squid.conf. Lá, vai encontrar comentada a linha storeurl_rewrite_program. Este recurso chama o helper externo que faz uma reescrita de URL. Você pode dizer: "Ah, mas url_rewriter eu ja conheço e não serve". Só que este não é o url_rewriter "normal". A diferença entre ambos é que o resultado do storeurl_rewrite só é utilizado no momento de gravar a URL e comparar o resultado.
Vou dar um exemplo para você entender melhor. Considere as seguintes requisições que pedem o mesmo arquivo em 3 servidores espelhados:
http://img1.orkut.com/imagem1.jpg [1]
http://img2.orkut.com/imagem1.jpg [2]
http://img3.orkut.com/imagem1.jpg [3]
Temos um script externo chamado pelo storeurl_rewrite que traduz a regex "img[0-9].orkut.com" para "imgokt.INTERNO". Se na entrada do helper forem inseridas as strings [1], [2] ou [3], o resultado será:
http://imgokt.INTERNO/imagem1.jpg [4]
Se o helper for colocado no url_rewrite "normal" vai dar um erro, porque o domínio imgokt.INTERNO não existe. Se você colocar em storeurl_rewrite, o squid vai solicitar [1] ao servidor original e gravar como [4]. No momento em que [2] for requisitado, ele irá transformar a requisição em [4] e verificar que já está no cache. Logo, vai dar HIT ao invés de solicitar de novo. O mesmo para [3]. Transforma, compara e retorna o equivalente. Entendeu?
Para usar o recurso, você vai precisar montar na mão um script para fazer a tradução das URL. Eu criei um em PHP para fazer o tratamento da URL do Youtube. O passo inicial foi feito através das regras do thundercache v2.2. Mas analisando o access.log, vi que era necessária uma atualização nas regras. O helper vai em anexo. É interessante também aplicar as regras explicadas no meu outro post para fazer a gravação.
No caso do Youtube, extraímos de uma URL gigante o ID e a qualidade do vídeo. A URL final (para propósitos de equivalência) fica mais ou menos assim:
http://flv.youtube.inComum/?id=abcdefghjklmnopqrstuvwxyz&fmt=34
Então, sempre que o vídeo com o mesmo id e a mesma qualidade for pedido, o squid entregará o conteúdo do cache. Faça o teste com dois navegadores diferentes. Atenção: o recurso (arquivo) de vídeo do Youtube costuma expirar rapidamente. Você também vai precisar de uma regra para fazê-lo durar mais. A instalação completa está descrita no arquivo instalar.txt, em anexo.
O script faz equivalência de url dos vídeos do Youtube, do imgX.orkut.com, staticX.orkut.com e Avast.
Além do código em si, é bom entender algumas particularidades do squid. A maior delas é a de que nem toda instalação é igual. Algumas versões podem ser (muito) diferentes. Em algumas, o script pode simplesmente esgotar a memória do seu servidor por causa de uma falha do próprio squid. Você deve ler o leiame.txt antes de colocar em produção.
Para testar o script "offline", ou seja, somente para verificar a tradução das URLs, simplesmente transforme-o em executável e rode-o no console, digitando as URLs de teste.
Projeto
Hoje, infelizmente, quem encontra algumas respostas para boas soluções em cache, transforma seus projetos em software proprietário. Eu gostaria muito de seguir o caminho inverso e começar um projeto para manter um script livre e gratuito. Para isso, preciso de almas bondosas para colaborar com ele, incluindo opções para outros domínios e me mandando logs do squid e outros feedbaks. Se alguém quiser portar para python ou outra linguagem de script (ou mesmo C), é bem-vindo. Se você concorda, poste um comentário. Se tiver gente suficiente interessada, começamos o projeto.
UPDATE: O programa virou projeto. Está hospedado no SourceForge. Se você trabalha com Squid, pode também se inscrever na lista de discussão.
| Anexo | Tamanho |
|---|---|
| inComum.tar.gz | 2.65 KB |


Márcio R. C. N.:
Olá, Tenho um provedor com 260 clientes e também juntamente com um parceiro forneço links para alguns provedores na região sul da Bahia.
Queria parabenizalos pela iniciativa e se eu puder ajudar de alguma forma estou as ordens.
Souza:
Olá ! Luciano, uso CENTOS 5.4 no Squid : ele diz um erro na linha cache allow all
Como posso corrigir? Tem como direcionar o cache para um HD extra?
Obrigado.
William Esteves:
Parabens pela iniciativa
luciano.pinheiro:
Glauco, você tem razão. Nem tinha percebido. :)
Li aqui que é um problema específico do amd64, mas não tenho como testar.
Então peço a você que faça a seguinte modificação e mande pra gente aqui a resposta: substitua todos os unsigned int x por std::string::size_type x no código (são 3 substiuições).
Depois disso, se conseguir compilar, veja se o software tá funcionando.
Pode executá-lo e digitar URLs que podem ser convertidas, outras que não podem e ainda strings que não são URLs.
Se der certo seu código, a gente implementa isso na versão oficial aqui.
PS: Todo mundo que quer ajudar no projeto, a melhor forma é entrar na lista de discussão.
Glauco:
Mais veja que compilei no amd64:
[...]
Quando vou usar depois de compilado no amd64:
[root@server1 /home/user/inComum]# ./inComum
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::erase
Abort trap: 6 (core dumped)
Lauro Franco:
luciano.pinheiro:
Glauco, você deve recompilar o inComum para funcionar no amd64.
A string é
% g++ -Wall -o "inComum" "inComum.cpp"
Glauco:
No i386 funcionou corretamente, porém no amd64 não funcionou.
Veja o que acontece:
[root@server1 /home/user/inComum]# g++ -Wall -o "inComum" "inComum.cpp"
inComum.cpp: In function 'std::string get_path(std::string)':
inComum.cpp:74: warning: comparison is always true due to limited range of data type
inComum.cpp: In function 'std::string get_domain(std::string)':
inComum.cpp:86: warning: comparison is always true due to limited range of data type
inComum.cpp: In function 'int main()':
inComum.cpp:102: warning: comparison is always true due to limited range of data type
inComum.cpp:153: warning: comparison is always true due to limited range of data type
[root@server1 /home/glauco/inComum]# ./inComum
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::erase
Abort trap: 6 (core dumped)
[root@server1 /home/user/inComum]# uname -a
FreeBSD server1 7.2-STABLE FreeBSD 7.2-STABLE #0: Mon Nov 16 21:23:52 BRST 2009 user@server1:/usr/obj/usr/src/sys/R1 amd64
André Prinou:
Luciano boa tarde vc tem msn pra pode flar com vc hj presto suporte e serviços a clientes com thunder 3 e lusca mais su contra como estao fazendo com thunder4 e queria falar com vc em pvt se possivel ok obrigado.
ajcorrea:
Caro Luciano,
colaboro com o projeto LUSCA que é um "fork" do squid, mantido em C, vou testar seu projeto e ver o que consigo, talvez até fazer parte do projeto lusca quando atingir uma maturidade "STABLE" (se for o caso).
Lendo os comentários, vejo que muita gente usa squid como proxy, mas joga a culpa da lentidão no squid. o "deplyment" de um proxy não é simplesmente fazer CTRL+C e CTRL+V na squid.conf do seu amigo.. vizinho.. ou do forum de internet.. proxy precisa ser estudado, analisado, fazer o projeto do HARDWARE, etc etc... Temos proxies com mais de 200 mbit de trafego em cima.. um exemplo CLARO são várias CDN´s rodando cacheboy (lusca) como proxy reverso, servindo conteudo em velocidades acima de gibagit/s (o VLC player por exemplo, usa o cacheboy cdn).. a LAST.FM roda em cima também de squid/lusca !!
meus contatos estão ai, caso queira trocar uma ideia, fique a vontade !!
parabens pela iniciativa !! grande abraço !
welisson:
Alguém tem experiencia, com esse script em ambiente com alto numero de clientes.
luciano.pinheiro:
Respostas ao osmano807:
Primeiro: a equipe do squid teve uns "probleminhas" de entendimento. pegaram o 2.6 e adicionaram umas funcionalidades e, ao mesmo tempo, melhoraram o código. Chegou um dia em que as duas coisas não encaixavam mais. Aí lançaram o 2.7 E O 3.0. Significou que algumas funções disponíveis no 2.7 não estavam no 3.0. Mas url_rewrite não foi uma delas, nem storeurl_rewrite.
Segundo: O meu exemplo aqui deste post é em PHP-CLI. O projeto está sendo desenvolvido em C++.
Terceiro: Existem outros proxies, com outras funcionalidades. O pessoal do Squid diz que ele começa a engasgar a partir de 3000 requisições por segundo.
Quarto: Meu projeto não está em GPL. Está em BSD.
Quinto: O SquidRewrite (ou outro rewriter "normal") não funcionaria pra cache do youtube. Aliás, funcionar até funcionaria, mas o retorno seria inviável (de menos de 10%). Eu gostei do sistema de flexibilização de regras.
Sexto: ok.
Resposta ao alderjanio:
No squid.conf existem todas as configurações disponíveis COMENTADAS. Não tem como eu dizer aqui em que linha você deve botar essas configurações. Só posso dizer que você deve procurar uma determinada configuração comentada e, na primeira linha em branco abaixo dela (exatamente antes de começar a outra configuração comentada), você deve colocar as configurações de instalação do inComum. Por exemplo, procure por
# refresh_pattern
Abaixo, haverá as refresh_patterns padrão. Coloque ali a linha de configuração do refresh_pattern. Se não deu certo sua instalação, pode ter certeza de que você esqueceu algum detalhe. Para testar, digite squid -X ou squid -k parse.
Se ainda assim você não conseguiu instalar, vá até a lista de discussão e vamos continuar esse papo lá.
osmano807:
Primeiro: essas funções, se não me engano, foram RETIRADAS do squid 3.x, ou seja, parará de funcionar.
Segundo: JAVA? Estavam querendo fazer em Java? :lol: (sim sim, eu não gosto _muito_ de Java)
Terceiro: Isso já foi testado por muitos, funciona, mas depender do squid (que está ficando lento, tá ouvindo?), é osso. Além do consumo de memória, sei lá...
Quarto: não gostam que fecham o source... OK... mas sempre que algum source foi liberado, foi copiado, modificado e transformado em software pago... Brasil não respeita a GPL!
Quinto: vejam o meu SquidRewrite no sourceforge, vão ter um ponto de partida em C++
Sexto: usem o SVN :P
alderjanio:
ola luciano
muito bom seu projeto é sua opnião sobre livre e gratuito
já implementei ele e funcionou muito bem
porém tivi um problema tentar fazer o squid rodar transparent
jah estava com esse problema antes de instalar o seu projeto
resumindo
formatei meu servidor ele esta rodando transparente porém num esta mais fazendo
cache de videos
duvida 1 : ele funciona no squid transparente
duvida 2 : o leiame ta bem explicado porem sou novo no linux e sei que e pedir muito
mas se você pudesse por os locais onde inserir as linha adicionais
ou postar um squid.conf pronto
obrigado
muito bom sua iniciativa e seu projeto
luciano.pinheiro:
Anonimo, os vídeos ficam armazenados no Squid. O que o inComum faz é obrigar o Squid a tratar os vídeos que possuem o mesmo ID como o mesmo vídeo. Esta é, na verdade, uma função do Squid (a storeurl_rewrite).
O inComum simplesmente trabalha com strings, com o objetivo de padronizá-las e repassá-las de volta ao Squid. Nada mais. O resto é função do próprio Squid.
Além disso, na instalação, você diz pro Squid tratar os vídeos como arquivos cacheáveis normais (por padrão ele não faz isso).
Por sinal, atualizei as regras. Agora, o inComum funciona com Youtube, Avast, Orkut (imagem e static) e daqui a pouco coloco nova versão com Vimeo.
Anonimo:
onde fica armazenado os videos
alderjanio:
ola sou novo no linux, me considero usorio basico creio que não poderei contribuir com o projeto no momento, porém costaria de elogiarlos pela frase "caminho inverso", pois estou passando por esse problema com thundercache funcionava direitinho, porém apos o lançamento da versão comercial parou de funcionar
obrigado pela iniciativa vou testar hoje
luciano.pinheiro:
Dito, os códigos não são inseridos todos juntos. No configuração padrão do squid, as diretivas estão comentadas numa ordem coerente. É que o squid precisa que algumas coisas estejam definidas antes de outras. Você poderia seguir esta ordem.
Por exemplo, existe uma seção de refresh_pattern, outra do cache_allow e ainda outra do storeurl_rewrite. Se você colocar cada pedaço do código em sua respectiva seção, vai funcionar legal.
Se você tiver algum outro problema, pode entrar na lista de discussão do inComum: https://lists.sourceforge.net/lists/listinfo/incomum-users.
Dito:
os codigos sao inseridos todos juntos? pois o meu esta dando erro na linha cache allow all
Olace:
Oi, estou testando em casa, e gostei muito porque é fácil a instalação e configuração.
Ele funciona muito bem, estou disposto a ajudar no que for possivel.
Obrigado!
pastor Luciano Pinheiro:
bom saber que existe outro luciano pinheiro deus te abençoe
luciano.pinheiro:
Marco, solicitei a inscrição do projeto em um repositório de projetos. Estou aguardando a resposta.
luciano.pinheiro:
Alexandre, passei por isso sim em um servidor debian. No ubuntu, isso não ocorria. Como expliquei lá no leiame.txt, várias versões do squid fazem coisas diferentes.
No seu caso, o Squid envia uma linha em branco (só o \n) para o helper de vez em quando (talvez para testar se ele está ativo). Fiz o tratamento para que, quando isso ocorresse, o script fosse finalizado (pensei ser a melhor solução para o caso de um amigo que usava fedora e que o squid deixava processos php zumbis).
Talvez esse tratamento não seja necessário em sua versão do sistema (distro/kernel/squid/php). Comente as seguintes linhas (e depois monitore para ver se ele não vai ficar deixando zumbis):
if(strpos($argv, 'http://') === false){ exit(0); }Se os processos ficarem "órfãos", seria melhor manter o código acima ou (melhor ainda) atualizar/mudar seu sistema.
Alexandre:
Boa noite, tenho tentando implantar o seu script. mas o meu squid vive reiniciando os processos do rewrite
a mensagem no cache.log é
2010/02/15 21:10:36| Too few store_rewriter processes are running
2010/02/15 21:10:36| Starting new helpers
2010/02/15 21:10:36| helperOpenServers: Starting 10 'inComum.php' processes
2010/02/15 21:10:37| WARNING: store_rewriter #10 (FD 31) exited
2010/02/15 21:10:37| WARNING: store_rewriter #9 (FD 30) exited
2010/02/15 21:10:37| WARNING: store_rewriter #8 (FD 29) exited
2010/02/15 21:10:37| WARNING: store_rewriter #7 (FD 28) exited
2010/02/15 21:10:42| WARNING: store_rewriter #1 (FD 13) exited
você chegou a passar por isso?
as versões do squid e php são:
root@server:/var/log/squid> php -v
PHP 5.2.10 with Suhosin-Patch 0.9.7 (cli) (built: Jul 13 2009 14:45:41)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
with Zend Extension Manager v1.2.2, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.3, Copyright (c) 1998-2007, by Zend Technologies
root@server:/var/log/squid> squid -v
Squid Cache: Version 2.7.STABLE6
configure options: '--exec_prefix=/usr' '--bindir=/usr/sbin' '--libexecdir=/usr/lib/squid' '--localstatedir=/var' '--datadir=/usr/share' '--sysconfdir=/etc/squid' '--enable-snmp' '--enable-removal-policies=heap,lru' '--enable-storeio=aufs,coss,diskd,null,ufs' '--enable-ssl' '--with-openssl=/usr/kerberos' '--enable-delay-pools' '--enable-linux-netfilter' '--with-pthreads' '--enable-ntlm-auth-helpers=SMB,fakeauth' '--enable-external-acl-helpers=ip_user,ldap_group,unix_group,wbinfo_group' '--enable-auth=basic,digest,ntlm,negotiate' '--enable-digest-auth-helpers=password' '--enable-useragent-log' '--enable-referer-log' '--disable-dependency-tracking' '--enable-cachemgr-hostname=localhost' '--enable-basic-auth-helpers=LDAP,MSNT,NCSA,PAM,SMB,YP,getpwnam,multi-domain-NTLM' '--enable-cache-digests' '--enable-ident-lookups' '--enable-negotiate-auth-helpers=squid_kerb_auth' '--with-large-files' '--enable-follow-x-forwarded-for' '--with-maxfd=16384' '--enable-arp-acl'
Marco:
Sugiro que o cídigo seja colocado no github para que possamos trabalhar nele.
Douglas:
Idéia muito boa e muito útil...
Uma Sugestão:
Entendo muito pouco de progamação e quase nada de de PHP, mas pelo que ví a complexidade do script é tão grande(claro que tenho ciência da dificuldade que deve ter sido trabalhar com lógica nesse caso).
Mas acredito que se esse escript fosse escrito em liguagem de baixo nível, C no caso, provocaria menos impacto de performance.
Só uma sugestão...
Flavio Menezes dos Reis:
Olá Luciano! Tenho um pequeno provedor e nunca cheguei a me aventurar a utilizar o thundercache, nunca achei uma solução elegante, muito embora a maioria dos usuários possa estar agradada. Agora a questão de utilizar o squid e apenas um helper acho bem elegante. Vou estudar o código e quem sabe reimplementá-lo em java e fazer alguns testes de performance. Assim que tiver domínio sobre seu funcionamento posso tentar portar para outros domínio e contribuir com o projeto. Parabéns. Que sejamos sempre livres.
Salomão:
Gostei da idéia de trilhar o caminho inverso. Tenho experiência com squid e squidGuard e linux a 17 anos e programo em linguagens como Python, Java, JavaME e PHP. Vou verificar a sua solução para saber se tenho como contribuir com o projeto.
Enviar novo comentário