Arquitetura “pull” ou “push”: qual escala mais?

Apesar do que possa parecer, esse post não é sobre git. :)

Conversando com o Peleteiro esses dias ele me deu uma idéia interessante. Ia ser o máximo se houvesse um post automático no meu Twitter toda vez que eu ganhasse um achievement no Xbox! Os achievements são como se fossem medalhas: na medida que você vai jogando os jogos e passando de fase ou conquistando coisas, você vai ganhando mais pontos e mais medalhas. Resumindo, é totalmente inútil mas bem legal.

Como nos últimos tempos andei fazendo uma porção de robôs de Twitter para fazer uma porção de coisas, na mesma hora pensei em fazer mais um deles, que ficaria dando requests na API do Xbox Live até que aparecesse um novo achievement e então ele faria o post.

Na mesma hora me bateu a mesma sensação de ineficiência que tive quando fiz os outros robôs. Pra fazer essas coisas eu tenho que ficar fazendo polling no serviço de “n” em “n” minutos para saber das atualizações… Apesar de ser eficiente nao é lá muito eficaz.

Vou fazer uma brincadeira para mostrar o tamanho do problema. Somando só os robôs que fiz para a Globo.com, eu faço diariamente cerca de 72.000 requests para o Twitter (cerca de 25 robôs x 2 requests por minuto x 60 minutos x 24 horas). Ok, nem todo mundo faz robôs de Twitter, eu sei, mas vamos supor que uma pessoa em cada 100.000 faz robôs que nem eu. Isso significaria que só eu e mais uma pessoa fazemos isso no Brasil inteiro (o que não deve ser verdade, mas vamos continuar assim fazendo a conta por baixo). Então considerando que a população mundial é de quase 7 bilhões de pessoas, temos cerca de 70.000 pessoas fazendo o mesmo em todo o mundo. Sendo assim, pela minha conta de padaria o Twitter recebe algo em torno de 5,04 bilhões de requisições por dia, 210 milhões de requisições por hora, quase 60.000 requisições por segundo (só de robôs)!!!

Ok, o número deve ser bem diferente disso. O fato é que com certeza é muito alto.

Eu faço polling no Twitter para buscar por usuários que falaram uma determinada palavra (usando o RSS da busca do Twitter) e então adicioná-los. Funciona assim: quando uma pessoa escreve alguma coisa que eu estou procurando, eu adiciono ela como amigo(a). Apesar dessa quantidade imensa de buscas e requests, um robô adiciona apenas na faixa de 25 usuários por dia. Se houvesse alguma forma de saber que algum usuário escreveu alguma palavra que eu busco, nesse meu cenário só seria necessário fazer algo em torno de 625 requests por dia (menos de 1% da quantidade que eu faço).

O que eu estou propondo aqui não é nada novo. Além dos mecanismos tradicionais de polling (fazer “pull” de arquivos de tempos em tempos), estes tipos de serviços deveriam disponibilizar um mecanismo para o servidor avisar o cliente que alguma informação que ele deseja está disponível (”push”).

Depois da apresentação “Beyond REST? Building data services with XMPP” que rolou na OSCON 2008, o XMPP entrou na moda como uma possível solução para esse problema. Nessa arquitetura, os clientes se “inscrevem” em um serviço de mensagens instantâneas e mantém uma conexão aberta com o servidor para que, quando determinada informação estiver disponível, ela seja enviada ao cliente ao invés dele ter que ficar fazendo “polling”. Isso reduz consideravelmente a carga de requests recebida pela aplicação, mas é mais difícil de escalar para uma quantidade muito grande de usuários.

Uma solução que surgiu na nossa conversa foi um “pingback ao contrário”. Seria algo como o webhook do Github. Quando o usuário fizer um GET em um recurso, ele poderia mandar um header com uma URL, e quando houvesse alguma atualização do recurso o servidor poderia fazer um GET para esta URL com o objetivo de informar ao cliente que há informações novas disponíveis. Essa solução escala mais do que a primeira, mas tem um lado negativo: não funciona se o cliente não tiver um IP real disponível. No meu caso, por exemplo, que tenho robôs rodando no meu desktop da Globo.com (que não tem IP real), não seria possível usar esse tipo de serviço.

Também dá pra fazer algumas soluções mais criativas usando coisas que a princípio parecem esquisitas mas podem fazer sentido. Por exemplo, um servidor de e-mail como o Postfix poderia fazer esse trabalho com o pé nas costas. Quando o cliente acessasse um recurso, ele poderia informar em um header um e-mail para ser notificado quando houvesse atualização. É uma solução bem fácil de escalar e de fácil implementação – tanto pelo lado do cliente quanto do servidor – apesar de não ser muito comum.

Pelo que eu andei lendo o pessoal do Twitter já pensou nesse problema e para resolvê-lo criaram o Firehose, que é uma solução baseada em XMPP. Como eu falei, o problema não termina por aí – eles terão vários problemas novos para escalar XMPP para uma grande quantidade de usuários.

Enfim, esse problema é bem interessante… Na próxima oportunidade que tiver vou tentar fazer uma prova de conceito de todas essas opções para ver no que dá.

E para aqueles que ainda não entenderam, talvez fique um pouco mais claro agora: escalabilidade é muito mais uma questão de arquitetura de software e infra-estrutura do que de linguagens e frameworks.

Tags: , , , , , , , ,

13 Responses to “Arquitetura “pull” ou “push”: qual escala mais?”

  1. Tetsuo says:

    “Apesar de ser eficiente nao é lá muito eficaz.”
    Não seria o contrário? Funciona, portanto é eficaz, mas faz mais requisições do que você gostaria, portanto não é eficiente. :)

    Em relação à abordagem push, qual a vantagem, se pelo que você diz haveria um problema de escalabilidade, que era o que você provavelmente estava tentando resolver com o push? Ou era só a questão da eficiência (menos tráfego de rede)? Ao meu ver, a única vantagem (fora a rede) é que você receberia a notificação um pouco mais rápido, já que não teria que esperar o intervalo do polling.

    O polling não (necessariamente) é tão custoso, pois o HTTP tem mecanismos de verificação de alteração de um recurso. Se, por exemplo, você pudesse (não conheço a API do Twitter) criar uma busca pré-definida e associá-la a uma URL ‘GET’, o seu robô poderia, antes de solicitar o conteúdo da busca, perguntar ao servidor quando foi a última ‘alteração’, isto é, qual foi a última vez que alguém escreveu tal palavra. Esta requisição envolve apenas os headers, então você economiza bastante tráfego, e utiliza a arquitetura ‘pull’, que teoricamente é bem mais fácil de escalar.

    Certo, mas uma coisa é que solução permite uma melhor escalabilidade, outra coisa é que solução é a mais apropriada. Digo, quando você tem alguma possibilidade de decidir como a coisa é feita do outro lado, claro. Quando você utiliza um serviço como o Twitter, você é um mero usuário, e pode apenas aceitar a API que eles fornecerem.

    Porém, quando a escolha é sua, que arquitetura utilizar? Essa sim é uma pergunta interessante :)

    Eu já trabalhei uma vez com algo deste tipo, e acredito que o critério mais apropriado é: o maior interessado deve ter o controle.

    Se o maior interessado é quem, requisita a informação, ele deve poder fazer o ‘pull’, pois em caso de falha no sistema que fornece a informação, o requisitante pode simplesmente perguntar de novo quando este voltar, ao invés de ficar dependendo da capacidade de recuperação do outro (mensagens e eventos perdidos).

    E, se o maior interessado é do fornecedor da informação (ele quer te vender alguma coisa, por exemplo), aí sim o sistema deveria ser ‘push’, já que o ônus da recuperação e reenvio de mensagens perdidas seria feito pela parte mais interessada.

    A vantagem de deixar isto para a parte mais interessada é que a chance é maior dela criar um esquema mais confiável de recuperação de falhas. E também, quando você é a parte mais interessada, e possui o controle da situação, você pode ‘dar um jeito’ bem mais facilmente, em caso de falha da outra ponta.

    Mas no fim, é claro, ‘depende’ :)

  2. Andre Brito says:

    Acho que agora ficou muito mais que provado que o James pisou na bola quando falou: “Twitter guys made wrong project decision. That’s why is slow.”. :)
    Valeu pela conversa sobre o TCC. Ajudou bastante! E só pra finalizar, “pull” e “push” me lembram Kanban (obrigado mais uma vez).

    Abraço.

  3. Bruno Laturner says:

    Escalabilidade não é um problema, é um domínio bem entendido por diversas áreas, bibliotecários já trabalham e estudam isso desde os tempos dos monges copistas. Quem diga então a logística, praticada nos tempos do império romano.

    Problema é querer escalar e ainda ter controle rígido sobre os dados. É basicamente o quanto General confia no Coronel, que confia no Major, que confia no Capitão, que confia no Tenente que instrui os aspiras pra executar as instruções lá de cima.

    Basicamente, quem não confia, não escala.

  4. Se o Twitter não tem, pode-se fazer um para o Twitter. Mantendo o esquema de pooling nele do projeto X ao Twitter, mas habilitando um serviço de inscrição no projeto X. Muito interessante e promissor.

  5. Heleno Alves says:

    Muito instigante a apresentação do XMPP, principalmente como conceitos são reciclados para atender novas demandas a todo momento na nossa área. Analisei este protocolo ano passado a fim de viabilizar um IM corporativo e me afeiçoei muito pelo OpenFire, servidor Jabber Open Source.
    Sobre a arquitetura pull e push tenho acompanhado a evolução do projeto Grizzly, agora Atmosphere, que são plugados a servidores java.
    Mas com o protocolo aberto XMPP pode ser atingido um efeito similar em ambientes com tecnologias distintas.

  6. Ja trabalhei em uma empresa de Mobile Legacy Integration que necessitava de uma solução nestes parametros, porém a cabeça pquena dos arquitetos que provavelmente nem sabem o que é XMPP impediu de chegarmos a esse patamar.

    Muito interessante sua idéia e com certeza uma prova de conceito pode ajudar bastante a esclarecer a questão da escalabilidade.

  7. Não existira um problema, talvez maior, do lado do twitter por exemplo, para que em cada post verificar quais inscrições se interessam por ela?

  8. Pessoal, foi mal pela demora em liberar comentários. Esses dias foram meio corridos :)

    E em relação a todos os questionamentos, eu poderia dar várias respostas mas o comentário do Rafael Ferreira foi excepcional: existem várias maneiras de fazer a mesma coisa e cada uma delas pode ser mais apropriada em uma determinada situação.

    :D

    [ ]s, gc

  9. Matt says:

    Interessante o artigo Guilherme, mas essa calculadora de padeiro tá meio quebrada, não tá não? Você cortou uns três zeros aí da população brasileira =P !

    Abs,

    Matheus

  10. Franklin says:

    Guilherme, em primeiro lugar acompanho seus blogs (ingles e portugues) e acho vc uma referencia na area de Computacao. Parabens!
    Gostaria de aproveitar o topico e perguntar: vc ja fez algum trabalho com o Google Calendar? Estou trabalhando num projeto e ainda nao encontrei uma solucao diferente de polling.
    Obrigado.
    Abracos,
    Franklin.

  11. excelente ideia, também cheguei a pensar am algo similar, mas de longe essa parece bastante atraente e incentivadora, o que pudermos automatizar em nossas vidas vai ser melhor, em até as redes sociais.

Leave a Reply