Um dos conceitos que considero chave para a escalabilidade é a programação assíncrona.

Ela consiste em realizar qualquer tarefa (job) mais pesada em termos de recursos computacionais em um processo ou até mesmo máquina separada, fora do workflow natural do seu aplicativo web.

Aprendemos isso desde o começo do Pagestacker. Na primeira versão, a que ficou pronta em 48 horas para o Rails Rumble 2007, a importação de itens do delicious era síncrona. Ou seja, assim que o usuário clicava em ‘importar’, o processo Rails acessava o webservice do delicious, baixava o XML, lia o arquivo todo e começava a processar cada item e adicionar ao Pagestacker.

Obviamente, se o usuário tivesse poucos itens no delicious, a importação funcionava sem problemas. Porém, se o cara tivesse mais de mil itens, o processo Rails demorava tanto que ele “esquecia” de responder ao navegador do usuário, e um erro de timeout ocorria (geralmente na conexão TCP do sistema operacional do usuário).

Uma das primeiras mudanças que fizemos após o Rails Rumble foi deixar esse processamento assíncrono. Agora, o processo Rails apenas baixa o XML do usuário e retorna à operação normal. Um outro processo, em background, cuida de ler esse XML e criar os bookmarks dentro do Pagestacker.

Temos portanto, três componentes fundamentais:

  • o produtor, que vai gerar os jobs que serão executados;
  • o consumidor, que vai executar os jobs;
  • a fila, que é a “cola” (ou seja, a interface) entre o produtor e o consumidor.

Na minha opinião, o componente mais importante é a fila. Ela tem um trabalho crítico. Guardar as mensagens com os jobs a serem executados e distribuir essas mensagens quando for requisitada.

Um jeito simples de construir essa fila é guardando essas tarefas em uma tabela no banco de dados. Não é muito escalável, há alguns problemas de concorrência, mas é um jeito simples e em 99,9% dos casos o banco de dados já está lá pronto e rodando.

Para fugir de banco de dados, sugiro usar o Amazon Simple Queue Service (SQS). É parte da Amazon Web Services, o serviço de “cloud computing” da Amazon (isso mesmo, a livraria).

O SQS é, sem dúvida, o serviço mais simples da Amazon Web Services (AWS) e uma excelente forma de começar a usar a AWS. Mas não se deixe enganar pelo conceito simples, usar o SQS pode trazer benefícios enormes à sua aplicação.

Claro que você pode utilizar outros “gerenciadores de fila”, como o beanstalkd, ActiveMessaging e mesmo o BackgroundRB. Mas ter mais um serviço rodando na sua infra pode ser trabalhoso demais. E o SQS aguenta muito tráfego. E, como eu já disse, é um jeito simples de começar a usar os serviços da Amazon.

Idempotência

Quando estiver programando sua lógica para funcionar assincronamente, é importante que seu código seja idempotente.

O que é isso? Simples. Às vezes, algumas mensagens podem ser processadas duas vezes. Seja porque a mensagem foi gravada duas vezes pelos produtores, seja porque o gerenciador de fila enviou a mesma mensagem duas vezes.

Seu código deve ser capaz de consumir a mesma mensagem diversas vezes e não “quebrar” por causa disso.

Uma característica interessante do SQS ligada à idempotência é que quando você lê uma mensagem da fila, você define um tempo no qual essa mensagem não será mais exibida. Ela ficará invisível por um tempo. Assim você pode processar a informação da mensagem (executá-la) e só depois apagar a mensagem da fila (geralmente antes que a mensagem fique “visível” novamente).

Conclusão

Usar o conceito de programação assíncrona será certamente um benefício dentro do seu código.

É interessante notar como um conceito simples como um gerenciador de fila pode mudar totalmente a forma como você constrói aplicativos.

A fila está gigante e os jobs estão acumulando? Lance mais consumidores. Simples assim, pois eles já estão configurados para ler da fila. Pode ser em outra máquina, ou até mesmo em outro datacenter.

Tenho mais alguns estudos de casos, mas isso eu deixo para quem for assistir à minha palestra no Rails Summit 2008, na semana que vem! =D

Tags: , , , ,