SVN #fail com muitos arquivos

26/8/2009 | Tags:, , , , | Escrito por: Dirceu Pauka Jr.

Durante a semana precisei trabalhar em um projeto que tem muitas imagens geradas por script. Decidi fazer cache dessas imagens deixando em disco/memcached.

O problema: SVN lento para fazer operações com muitos arquivos (no meu caso nem são muitos: 10000).

A solução: tar -zcvf buttons.tar.gz buttons/

E no deploy: tar -zxvf buttons.tar.gz

Comprimi todos arquivos em um só e depois de colocar em produção descomprimi. Assim o SVN não dá azia e não preciso me preocupar com RMagick no server ;)



YQL + Y! Geocoding API + Google Maps

14/7/2009 | Tags:, , , , , | Escrito por: Dirceu Pauka Jr.

Sábado eu comecei a procurar uma casa para morar. Eu preciso de uma casa grande e sem vizinhos, assim posso fazer umas festinhas e vender minha cervejinha artesanal. A casa também precisa ficar próxima ao “busão da UEL“.

O problema: nenhum site de imobiliária presta, quanto mais em Londrina.

Poucos sites de imobiliárias mostram as opções em um mapa e nenhuma das páginas que “unem os imóveis de várias imobiliárias” funcionam.

A solução: escrever código.

Com Yahoo Query Language (YQL) eu busquei as “casas para alugar” de 7 imobiliárias.
De fato essa é a parte mais complicada e demorada uma vez que cada imobiliária usa um “padrão” diferente para apresentar as informações e o trabalho aumenta ainda mais por causa da má construção de certas páginas.

Das 7 imobiliárias foi possivel extrair cerca de 100 casas para locação.

Para inserir as informações no mapa foi preciso de uma API de Geocoding. Esse tipo de serviço transforma um endereço (rua e número) em coordenadas geográficas (latitude, longitude).
Minha primeira tentativa foi usar a API de Geocoding do Google porém a Geocoding API do Yahoo! se saiu melhor quando o endereço tem “sujeira” (erros de digitação e/ou encoding zuado).

O resultado:

Picture-6

Muito mais fácil agora.

Tech stuff

O código que une os resultados das imobiliárias foi escrito em Ruby.
A gem typhoeus faz as requisições HTTP.
YQL foi usado para filtrar o conteúdo das páginas.
A gem geokit permite fazer Geocoding em apenas uma função: YahooGeocoder.geocode(”rua”).
Memcache faz cache dos resultados (muitas requisições HTTP machucam).
Sinatra para que o código Ruby vire uma aplicação web.
Google Maps API para inserir os resultados no mapa.

Códigos:
nerd_searching_house.rb
/ index.erb

Exemplo

Veja o resultado da brincadeira.

Colocar em produção e manter esse “toy project” não está nos meus planos. O exemplo ficará desatualizado em breve e se você precisar de algo atualizado fique a vontade para fazer o código funcionar ;)



glTail – Visualização de Log

26/12/2008 | Tags:, , , , , , , | Escrito por: Dirceu Pauka Jr.

glTail é um visualizador de logs escrito em Ruby. Os gráficos são gerados com a biblioteca ruby-opengl e a física das partículas é feita com Chipmunk, uma lib para desenvolvimento de física em games que possui ótima integração com Ruby.

Com ele é possível ter acesso a estatísticas em tempo real de vários serviços como Apache, Nginx, MySQL, Squid e aplicações Merb/Rails.

Tudo que você precisa para utilizar é instalar a gem (sudo gem install gltail) e alterar o arquivo de configuração para os dados de SSH e caminho de arquivos do seu servidor.

O amigo @evertonfraga testou a ferramenta com o log do Nginx no We heart it e mandou o vídeo pro Qik, vejam que legal que é:



Processing

26/11/2008 | Tags:, , | Escrito por: Dirceu Pauka Jr.

Não deve fazer mais que seis meses que CouchDB e Hadoop (que pretendo observar de longe) e Processing e Objective-C começaram entrar na minha cabeça. Espero que essas coisas não afastem meus problemas atuais em Ruby (Merb).

O motivo de eu estar tão animado com Processing (e Arduino é lógico) é resumido nessa frase do why.

(…) não é só a popularidade do Processing que é animadora. Uma coisa é uma linguagem se tornar popular entre cubículos e salas de servidores. Processing é um ambiente ganhando respeito em salas de aulas, salas de edição e até em baladas.
http://hackety.org/2008/11/25/sevenYearsLaterProcessingLeavesBeta.html

Realmente… eu lembro de ter visto a Björk usando isso há mais de 1 ano.
Veja uma animação feita com Processing:


Metamorphosis from Glenn Marshall on Vimeo.

Como mostrado aqui é possível utilizar Ruby para fazer Live Coding com Processing. Existem também outras bibliotecas em outras linguagens.



Rack Cache – Fazendo cache corretamente

23/11/2008 | Tags:, , , , , , , | Escrito por: Dirceu Pauka Jr.

Então nós temos o HTTP a muito tempo e algumas coisas que foram revistas na versão 1.1 (RFC 2616) do protocolo só estão estão sendo implementadas para valer agora.

Uma parte importante do REST é a preocupação com o uso e implementação de alguns metodos HTTP esquecidos até agora.

Outra nova preocupação é sobre as implementações de cache do protocolo.
O protocolo HTTP vem com várias especificações sobre como cache pode ser feito nessa camada, porém, até agora foi uma parte esquecida tanto nas aplicações como nos clientes de HTTP.

Como várias aplicações (não pense somente em navegadores, mas também Web Services) começaram a seguir essas especificações para fazer cache local, era lógico que viriam implementações para os servidores que utilizamos hoje em dia.

Eu não sei você, mas eu já estou com Nginx + Rack a muito tempo. Rack é uma interface entre o servidor HTTP e o framework Ruby. No meu caso o framework é o Merb e o servidor é o Thin. O Nginx só dá uma de proxy reverso. E é ai que entra um grande potencial para ele. Com alguns cabeçalhos HTTP sendo trocados corretamente o Nginx consegue funcionar como servidor de cache facilmente.

Rack::Cache é um adapter para Rack (que servidores como Thin e Ebb usam e frameworks como Merb e Sinatra também). Além de usar corretamente os cabeçalhos HTTP sobre cache, o Rack::Cache age como um mecanismo de caching completo e totalmente fora da aplicação. Permitinde inclusive que o armazenamento seja feito no Memcached.

Por enquanto é necessário a inclusão manual do código na aplicação que está executando o Rack. Em breve espero que os próprios servidores ou frameworks incorporem as funcionalidades dessa gem Ruby.



Espancando um Web Server com Ruby

19/10/2008 | Tags:, , , , , , | Escrito por: Dirceu Pauka Jr.

Eu resolvi fazer alguns testes com Threads e Timeouts no Ruby hoje e para tal resolvi lidar com algo real: chamadas a APIs.

Problema

O problema todo da escalabilidade acontece por um simples motivo: uma chamada que demora para responder gera uma bola de neve no sistema. E esse problema da bola de neve se repete em várias partes do sistema todo. É isso que ocorre com as querys longas no MySQL ou upload de arquivo que trava uma instância do servidor e deixa todas próximas requisições lentas.

Por isso que é muito mais importante diminuir o tempo das querys longas no MySQL do que qualquer outra coisa. Você provavelmente consegue tirar mais tempo das querys mais longas, certo? Pense no lance de proporção, certo?

Problemas em escalar leitura em MySQL são comuns e por isso as soluções são amplamente conhecidas. Apesar de existir lock para leitura e outras características que machucam muito o trabalho de quem tem que escalar base de dados relacionais, caras como o Flickr fazem um bom uso do MySQL até hoje (sempre com ajuda de cache, lembre-se disso).

Mas e se a fonte de dados da aplicação é algo muito mais lento que um MySQL? E se a fonte de dados é digamos um WebService? Ou no pior dos casos: Web Scraping?

Um WebService ou uma API RESTfull não tem latência controlada como uma query rodando no MySQL local (ou em um cluster de) pode ter. Para começar a falar sobre WebServices eu penso logo em 200ms de latência só para atingir o servidor. E acredite, na maioria das vezes isso é pouco e de qualquer forma é o tempo de resposta que uma query comum no MySQL deve levar.

Além da lentidão você tem que pensar que a coisa toda pode não funcionar. Você pode fazer a requisição HTTP e ela não voltar. É da natureza do HTTP não retornar algumas requisições.

Agora você pensa em centenas de requisições entrando na fila a cada segundo em um sistema que busca os dados em uma API de tempo de resposta médio de 2 segundos. Esqueça a moleza do MySQL. 2 segundos aqui (no meu exemplo de API) é o tempo de resposta mínimo! Ferrou.

Eu já passei por isso. A maneira básica de lidar é cache. Você sabe. Todo mundo sabe…

Mas ainda acontece que as requisições são muito lentas! Muito! O cache não pode ser para sempre e as vezes acontecem coisas que lhe obrigam a limpar todo o cache.

Não importa quantos processos Ruby você abrir (ou quantas requisições/segundo seu Apache sirva em uma maquina de 16 bits), sua aplicação não escala e a culpa é da sua fonte de dados que para piorar é externa e você não pode fazer nada.

Solução

Eu estou planejando cortar muito processos Ruby de uma aplicação em Merb que bate 2MM req/dia com uma solução parecida com a experiência de hoje (que alias se encontra no final do post).

Por enquanto, para manter o serviço no ar a solução foi usar o que havia de melhor na infra: Nginx, Memcached e Thin. Ainda assim eu preciso de 75 instancias do Thin para que tudo funcione (lembre-se: cache não é eterno e requisições sem cache são extremamente lentas).

Como irei mudar o cenário? Quase da mesma forma como espanquei um WebServer a poucas horas com somente um processo Ruby aberto e muito menos banda do que um VPS costuma ter… “Threads”.

Usei Threads de Ruby aqui para a experiência que vou passar, mas para produção recomendo o uso de bibliotecas que irão gerenciar o trabalho. Nanite leva a carga de conhecimento em engenharia que a EngineYard possui, e apesar de não ter uma solução baseada especificamente na questão de threads pode servir para distribuir instâncias do servidor entre várias maquinas numa rede local (lógico que não é – e nem pretende ser – uma implementação do MapReduce). Ainda preciso fazer um bom teste com Nanite e conhecer soluções como NeverBlock. De qualquer forma, essas são boas soluções para o problema de escalabilidade. Pode confiar :)

Abaixo o código (experimental) que derrubou um IIS (inclusive expondo pedaços da aplicação). Ele mostra como eu usei o máximo da banda disponível para fazer tantas requisições em um servidor remoto até ele cair. Isso com somente um processo Ruby.

Em casos comuns o gargalo seria do script Ruby que faz as requisições no outro servidor, no caso desse script eu tranformei o gargalo em banda e na capacidade do outro servidor de me responder. Situação bem melhor do que gargalo na requisição em si.

Ouvi dizer que essa não é a maneira mais fácil de lidar com o problema, certamente no Ruby NeverBlock é uma solução legal. Como eu disse, preciso olhar com atenção.

Boa parte do código serve para estimar o tempo necessário para conclusão da tarefa e para exibir quanto tempo cada Thread está levando.
O ideal é achar um bom número para colocar no método join da Thread. Tente deixar esse número um pouco acima do tempo médio que o servidor remoto (ou serviço externo) responda tranquilo suas requisições sem cair no mesmo problema de bola de neve. O grande segredo do código está nesse valor e você precisa ajustar ele para sua realidade.

Notas da brincadeira:

  • Prefira utilizar Ruby 1.8.6. A documentação do 1.8.7 não está muito real. Principalmente com bibliotecas, onde enfrentei um probleminha com as classes Date e Time no 1.8.7.
  • Cuidado com comparação de Floats (principalmente se tratando de datas), Floats são números muito mais complexos do que parecem.
  • Hadoop


MerbCamp

15/10/2008 | Tags:, , , | Escrito por: Dirceu Pauka Jr.

O MerbCamp rolou em São Diego, Califórnia nos dias 11 e 12 desse mês. O pessoal da EngineYard mostrou ter feito um ótimo trabalho para o lançamento do Merb 1.0.

O foco da EngineYard está bem voltado em “fazer a coisa escalável”. E não é só no bizarro mundo da guerra de frameworks e linguagens. O Ezra apresentou um gem que cria um balanceador de carga entre vários processos Ruby, que eu não acho tão importante em si mas enxergo esse como um projeto que saiu da estrutura do Vertebra. Para quem não sabe Vertebra é o nome do projeto que rola dentro da EngineYard para criação de uma interface de aplicações para computação distribuída (cloud, já cansei de ouvir e tentei mudar um pouco :)

Abaixo uma apresentação com o que o pessoal do projeto Merb na EngineYard pensa sobre o atual estagio dele:

Merb Camp Keynote
View SlideShare presentation or Upload your own. (tags: merbcamp)

Perceberam que para mostrar que Rails é bem lento em comparação a Merb eles usaram o PHP como saco de pancada?

Voltando ao projeto do Ezra chamado de “Nanite“, prestem atenção nele! Logo de cara eu já identifiquei que ele resolve um grande problema que eu iria enfrentar futuramente em uma aplicação: Assincronicidade. Uma ótima resolução para problemas com escalabilidade é tranformar as partes mais lentas do sistema em assincronas. O Nanite serve como um auxilio para o desenvolvimento de uma aplicação que irá conter “background jobs”. O George fez um post legal sobre o tema: “Programação Assíncrona“, vale conferir!



Parsear HTML sem expressão regular

2/10/2008 | Tags:, , , , , | Escrito por: Dirceu Pauka Jr.

Então certo dia lá estava eu, tentando uma expressão regular para interpretar (ou parsear) HTML. Uma tarde inteira tentando “achar” um elemento do HTML e substituir por outro. Apanhando da Regex

Levantei, bebi agua e reclamei alto da vida. O Marco me perguntou o motivo do momento de fúria. Expliquei e fui submetido a mais um daqueles momentos “como eu sou tão estupido” que está ficando comum comentar aqui.

“Usa o jQuery porra!”

Uma das principais coisas fodas do jQuery é como ele trata o DOM (Document Object Model) das páginas e como ele permite buscar pela arvore de elementos “desse tal” de DOM. Ele armazena tudo de maneira bem leve e consegue procurar absurdamente rápido dentro dos elementos do HTML.

E o melhor: o jQuery permite que você crie essa “arvore de elementos” enviando uma string que contenha HTML/xHTML (XML para ser mais exato).

O código fala mais que a histórinha:

Historinha

‘);

// pega elementos que estejam dentro de uma

  • var as1 = $(’li.last a’, els);

    // pega elementos que estejam dentro de uma

  • var as2 = $(’li a.nice’, els);

    Para procurar o elemento você pode usar “CSS Selector” (igualzinho CSS3) e ainda tem a ajuda das várias funções de busca que o jQuery possui.

    Ah! Vale lembrar que não é só no jQuery que é possível usar essa mágica. Existem bibliotecas parecidas em outras linguagens.
    Em Ruby eu venho usando bastante a Hpricot. Elas utiliza a mesma lógica de armazenamento do jQuery e permite uso de seletores CSS e XPath.
    Em PHP já me mostraram a SimpleHtmlDOM, parece bem fácil também.
    Procure saber biblioteca é legal para usar na sua linguagem preferida e nunca mais tenha problemas em parsear HTML utilizando expressões regulares.



  • Rails Summit Latin America

    13/8/2008 | Tags:, , , | Escrito por: Dirceu Pauka Jr.


    Rails Summit Latin America
    Nos dias 15 e 16 de Outubro acontece em São Paulo o Rails Summit Latin America.

    O evento terá a presença de mágicos da comunidade Ruby como Dr. Nic, monstros como Chad Fowler, Chris Wanstrath (GitHub), Charles Nutter (jRuby) e a dupla Phusion (Ninh Bui e Hongli Lai). Estão também agendadas palestras de nomes da comunidade nacional: Manoel Lemos (BlogBlogs), Vinícius Manhães Teles (Improve it), George Guimarães (Pagestacker), Fabio Akita (LocaWeb) e outros que espero conhecer o trabalho assistindo as palestras.

    O valor será R$300,00 se você comprar antes de 09/09/2008 e R$400,00 após 10/09/2008. Na minha opinião, um preço bem abaixo do valor real do evento.

    A programação completa e a inscrição pode ser acessada aqui.

    Obs: A quantidade absurda de links foi proposital. Se você está interessado em estudar Ruby/Rails, siga os caras!



    Ruby é sobre deletar código

    5/8/2008 | Tags:, , | Escrito por: Dirceu Pauka Jr.

    Ok, eu não sou um jedi em Ruby ainda, mas lendo o Ruby Cookbook[bb] pretendo me tornar um. O comportamento que você vai perceber nas telas eu aprendi lá!

    Wow – nós estamos deletando mais código do que estamos mantendo!

    Yeah, claro que estamos. Você não faz isso sempre?

    As duas imagens abaixo foram adaptadas da apresentação Rails Taking the Red Pill que o Demetrius Nunes fez lá no Rio on Rails. Ela demonstra no código o paradigma “Convenção sobre Configuração” adotado pelo Rails.

    Tentar a perfeição na primeira implementação é uma forma de especulação. É extremamente difícil julgar a clareza de algo que você não pode ler, ou a performance de algo que você não pode executar.

    Quanto mais fácil de refatorar, ou reescrever (uma forma de refatorar), melhor. Essa é uma das razões de eu ser a favor de linguagens densas.

    As citações são traduções de trechos do artigo Wearing Out My Delete Key de James Golick, leia!