Starling: Trabalhando com Filas em Ruby

October 10th, 2008 por jeveaux

Quem nunca ouviu a grande falácia de que Rails não escala? Isso foi moda durante algumas semanas enquanto o Twitter passava por problemas de escalabilidade, não necessariamente por culpa do Rails ou de Ruby, mas quem quer por lenha na fogueira não está muito preocupado com isso e quer mesmo é semear a discórdia. Muita água já passou por baixo da ponte, o Twitter agora está estável e as coisasfluem bem.

No começo deste ano o pessoal do Twitter anunciou e tornou open source o projeto Starling, criado por Blaine Cook. O Starling é o core do Twitter, ele é o servidor de filas responsável por manter em pé o Twitter. E agora como um projeto open source está disponível como gem e pode ser usado por qualquer outro projeto.

Indo direto ao ponto, o Starling é, basicamente, um servidor de filas implementado sob o protocolo do MemCache. O MemCache é um servidor de cache distribuído de altíssima performance e é largamente usado, principalmente em clusters de aplicações web.

Para usar o Starling é muito simples. Os primeiros passos são

Instalação

1) Instalar o servidor MemCache

CODE:
  1. jeveaux@kamael ~ $ sudo apt-get -y install memcached

2) Instalar a gem do MemCache e

CODE:
  1. jeveaux@kamael ~ $ sudo gem install memcache-client

3) Instalar a gem do Starling.

CODE:
  1. jeveaux@kamael ~ $ sudo gem install starling

E pronto, isso é tudo para começarmos a usar o Starling. Se você achou a instalação simples se prepare, pois a utilização é ainda mais simples.

Usando o Starling

Se você já usou o MemCache vai sentir-se familiarizado com o Starling. A diferença é apenas na implementação do protocolo, ou seja, a utilização em código será igual a do MemCache, só que ao fazer set e get as coisas acontecerão de uma forma um pouco diferente. Por enquanto a diferença maior que percebi foi em relação do método get, que quando usado no MemCache apenas retorna um valor do cache e o mantém lá, já no caso do Starling o get retorna o valor e o remove da memória. Analisando com calma isso faz sentido, afinal não estamos mais falando de cache e sim de filas, mesmo que a implementação da fila seja feita usando cache.

Mas antes de irmos para os exemplos de código, precisamos fazer com o que o servidor de filas - duh, Starling - esteja disponível e rodando. Vamos iniciar o Starling na porta 22122 (-p) e como um daemon (-d):

CODE:
  1. jeveaux@kamael ~ $ sudo starling -p 22122 -d

Isso já basta para iniciar o servidor do Starling e deixá-lo disponível para uso. Agora então vamos alimentar a fila, crie o arquivo: alimentar_fila.rb.

CODE:
  1. #alimentar_fila.rb
  2. require 'rubygems'
  3. require 'memcache'
  4. starling = MemCache.new 'localhost:22122'
  5. starling.set 'fila', 'qualquer objeto'

Ao executar este arquivo (ruby alimenta_fila.rb) não teremos nenhum resultado visual, mas acredite, a fila chamada de'fila' no exemplo está recebendo objetos. Agora o trabalho será para - como dizem - consumir a fila. Vamos ao consumir_fila.rb.


CODE:
  1. #consumir_fila.rb
  2. require 'rubygems'
  3. require 'memcache'
  4. starling = MemCache.new 'localhost:22122'
  5. loop {
  6.   objeto_fila = starling.get 'fila'
  7.   if !objeto_fila.nil?
  8.     puts 'recuperado da fila:' + objeto_fila
  9.   end
  10. }

E agora sim estamos prontos para colocar e remover objetos em uma fila. O exemplo para consumir os objetos ficará em loop, então você pode executá-lo numa janela do bash e em outra janela ir executando o exemplo para alimentar a fila com objetos e acompanhar o comportamento dos procedimentos de alimentar e consumir a fila. A recuperação da fila será imediata, instantânea, afinal, assim como o MemCache, o Starling está preparado para receber milhares de operações por segundo.

E é isso, o seu servidor de filas já está rodando e sendo alimentado/consumido. Agora é aplicar para o que você está precisando :D

Problemas

Há um probleminha chato com a gravação de log em disco que o Starling faz das filas. Todo o set feito gera o objeto na memória e também em disco - geralmente em /var/spool/starling/. O problema é que o get somente remove o objeto da memória e não do disco. Aparentemente isso foi feito pra ser assim mesmo e segundo o próprio Blaine Cook este arquivo de log não ficará sendo incrementado para sempre, pois, depois de um certo tamanho (o engraçado é que ele não fala esse certo tamanho) ele será rotacionado, mas por enquanto ainda não descobri este certo tamanho e o arquivo tem crescido infinitamente.

E apenas uma observação quanto ao consumir_fila.rb: Não deixe-o executando por muito tempo e nem muito menos esqueça de finalizá-lo pois como ele fica em loop infinito poderá ocupar o seu processador a toa.

Code To Ruin

October 12th, 2007 por jeveaux

Já devo ter comentado em outras ocasiões aqui no blog que eu gosto muito dos posts do blog Worse Than Failure (antigo The Daily WTF). E essa semana saiu um post chamado Avoiding Development Disaster, um excelente artigo que fala sobre os projetos de desenvolvimento de software e as lições aprendidas nestes projetos, mas que muitas vezes gastaram milhões e milhões de dolares, geraram uma excessiva documentação inútil que nunca será lida por alguém e milhões de linhas de código que jamais serão executadas em produção, enquanto poderiam ter sido facilmente encontradas num bom livro de engenharia de software. O artigo mostra também os vários caminhos que os projetos podem seguir - tendenciosos ou não - rumo ao sucesso ou ao fracasso.

Avoiding Development Disaster

Começando com Python #3/undefined

July 23rd, 2007 por jeveaux

Continuando a nossa série de posts sobre como aprender Python, vamos agora começar a falar de OO com Python. Para quem não viu os outros posts, pode ler o primeiro post aqui e o segundo aqui.

Não, eu não esqueci de continuar postando sobre python, apenas demorei um pouco na seqüência.

Objetos são a unidade fundamental de qualquer sistema orientado a objetos. Orientação a objetos é um termo que descreve uma série de técnicas e soluções para problemas computacionais. No nosso caso específico, vamos falar apenas de programação Orientada a Objetos, que é um paradigma de programação no qual um programa é estruturado em objetos, e que enfatiza abstração, encapsulamento, polimorfismo e herança. Em Python, tudo é um objeto (tipos, valores, classes, funções, métodos e, é claro, instâncias).

Em Python, a estrutura essencial para definir novos objetos é a classe. As classes são definidas em código-fonte, onde recebem um nome identificador e encapsulam um conjunto de atributos (dados) e métodos (operações). Vejamos a estrutura simples de uma classe em Python:


CODE:
  1. class MinhaClasse:
  2.     atributo1 = valor;
  3.     atributo2 = valor;
  4.     def metodo1(self):
  5.         #faz alguma coisa
  6.     def metodo2(self, atributo1):
  7.         #faz alguma coisa

Vejamos uma classe funcional agora:


CODE:
  1. class HelloWorld:
  2.     'Minha Primeira Classe em Python'
  3.     i = 123
  4.     def funcao(self):
  5.         return 'Hello World!!!'

As classes suportam dois tipos distintos de operações, são elas: instanciação e referência a atributos.

A referência a atributos possui uma sintaxe padrão para os objetos de classses em Python: obj.atributo. Sendo obj o seu objeto classe e atributo algum atributo válido, seja ele um atributo (variável) do seu objeto classe ou um objeto função (operação). Usando a classe acima podemos referenciar HelloWorld.i e HelloWorld.funcao, estas referências serão válidas e retornarão um inteiro (123) e um objeto função, respectivamente.

A instanciação do objeto classe é como nas demais linguagens orientadas a objetos, nós vamos basicamente iniciar um objeto de um determinado tipo (o tipo é o objeto classse) e atribuir a algum atributo. A instanciação (calling) de uma classe, por default, cria um objeto vazio. Por exemplo, para instanciarmos nossa classe de exemplo:


CODE:
  1. x = HelloWorld()

Porém, muitas classes podem precisar criar um novo objeto em um estado inicial pré-determinado. Para estes casos, existe um método especial que pode ser definido pela classe, é o método __init__(), conforme próximo exemplo. O método __init__() é o construtor da classe e poderá ter ou não atributos, isso vai depender das necessidades de cada classe.


CODE:
  1. class HelloWorld:
  2.     'Minha Primeira Classe em Python'
  3.     i = 123
  4.     def __init__(self):
  5.         self.i = 123456
  6.     def funcao(self):
  7.         return 'Hello World!!!'

Agora, após esta alteração em nossa classe, caso ocorra uma referência ao atributo i sem que haja uma instanciação da classe, o valor retornado será 123, mas caso a classe tenha sido instanciada, o valor retornado será 123456.


CODE:
  1. print HelloWorld.i
  2. 123
  3. x= HelloWorld()
  4. print x.i
  5. 123456

"- E aquela String perdida ali no começo da classe?", você já se perguntou isso? Aquela String é chamada de docstring e pode ser acessada através do atributo __doc__, que no nosso caso irá retornar a String "Minha Primeira Classe em Python". As docstring podem ser inseridas no início de funções, classes e métodos, é uma convenção criada para documentação. Esta documentação poderá ser consultada depois usando o pydoc com o comando help. Abaixo acesso direto ao atributo __doc__ da classe.


CODE:
  1. print HelloWorld.__doc__
  2. Minha Primeira Classe em Python

Consulta ao help da classe usando o pydoc.


CODE:
  1. help(HelloWorld)
  2. Help on class HelloWorld in module __main__:class HelloWorld
  3.  |  Minha Primeira Classe em Python
  4.  |
  5.  |  Methods defined here:
  6.  |
  7.  |  __init__(self)
  8.  |
  9.  |  funcao(self)
  10.  |
  11.  |  ----------------------------------------------------------------------
  12.  |  Data and other attributes defined here:
  13.  |
  14.  |  i = 123

Nós poderíamos ter definido mais informações de documentação nesta classe, nos métodos __init__() e funcao por exemplo. Se fosse o caso, basta adicionar os comentários entre aspas ('') na primeira linha de cada método.

Herança, herança múltipla, exceções e definições de escopo de atributos e métodos serão abordados no próximo post, já estou achando esse aqui muito longo, esta continuação já está em draft e sairá mais rápido! :D

Começando com Python #2/undefined

June 17th, 2007 por jeveaux

Vamos começar essa segunda parte aprendendo a usar o PyDev, plugin do Eclipse para programar em Python. Existem várias outras alternativas de ambiente de desenvolvimento, para quem não gosta do Eclipse ou não quer usa-lo com Python, pode escolher entre algumas das alternativas que conheço: IDE Eric, Anjuta, BOA Constructor, DrPython e quem gosta de IntelliJ IDEA pode usar o Pythonid como plugin.

Depois de um HelloWorld, uma das coisas mais difíceis é conseguir pensar em algo interessante para continuar os estudos e como ter um ambiente organizado e produtivo. Então veremos o PyDev e depois alguns outros exemplos mais interessantes.

Instalando PyDev

  1. Acesse: http://pydev.sourceforge.net/
    1. Instale pelo update do Eclipse: http://pydev.sourceforge.net/updates/
    2. Ou baixe o zip e faça a instalação manual: http://www.sourceforge.net/projects/pydev/
  2. Pronto! Simples e rápido.

PyDev Features

  • Suporte a Python 2.4, 2.5 e Jython;
  • Code completation e highlighting;
  • Wizards de projetos, módulos, etc;
  • Organize Imports e Autoformat Code;
  • Refactoring;
  • Code Assistant (CTRL+1);
  • Code Folding;
  • Eclipse Tasks integration;
  • Debugger completinho;
  • PyDev Perspective;
  • E muitas outras;

Leia mais »

Clássico: Desenvolvimento de Software

June 14th, 2007 por jeveaux

É um clássico realmente, mas eu precisava estrear o Off-Topic e me descontrair um pouco hoje também, o dia não foi dos melhores.

O segundo post sobre Python está a caminho.

Começando com Python #1/undefined

June 11th, 2007 por jeveaux

Pronto, nada melhor do que um feriadão acompanhado daquela viagem pra casa da mamãe hein; descanso, paz e sossego (e sem internet) é o que eu precisava pra repor as baterias e aliviar a maldita gastrite. E num dos vários devaneios diários resolvi que esta seria a semana do Python no blog, vou escrever aqui como eu conheci e aprendi Python.

E tudo começou em 2004, foi quando eu realmente me interessei por Python, até então eu não tinha contato com muitas linguagens de script além de JavaScript, PHP e Shell. Durante o FISL5.0 quando assisti a palestra Matando o Java e mostrando o Python, por Osvaldo Santana Neto e Ruda Moura e que diga-se de passagem foi muito engraçado, neste ano ocorria o primeiro Javali e todo o pessoal do Java resolveu invadir a palestra do Osvaldo e Ruda. Então juntei o incentivo que tive no FISL na palestra mais as cutucadas que sempre ouvia/lia do CV sobre Java e Python, e como ele mesmo dizia: "Para programar em Python é preciso ter culhões" e eu resolvi então testar os meus (sem duplo sentido por favor), e comecei a gostar de Python.

Leia mais »