1) O documento descreve a experiência de 1 ano usando o Google AppEngine, incluindo os desafios de lidar com picos repentinos de tráfego e como o AppEngine permite escalabilidade elástica.
2) É fornecido um painel de controle completo para gerenciar e monitorar aplicações no AppEngine.
3) O AppEngine segue padrões Java como Servlets e JPA para permitir maior portabilidade, apesar das limitações do banco de dados BigTable.
Mitos e verdades do cloud do Google: 1 ano de experiências no AppEngine
1. Mitos e verdades do cloud do Google:
1 ano de experiências no AppEngine
@sergio_caelum | Caelum | QCon São Paulo 2010
2. Sérgio Lopes
sergio.lopes
@caelum.com.br
@sergio_caelum
Meu nome é Sérgio Lopes, sou instrutor e desenvolvedor na Caelum. Meu e-mail é
sergio.lopes@caelum.com.br e meu twitter é @sergio_caelum. Sou um feliz desenvolvedor do
Google AppEngine há 1 ano, quando resolvemos migrar o Caelum.com.br para o AppEngine em
Setembro de 2009.
Essa palestra é sobre o que aprendemos nesse 1 ano no cloud do Google.
@sergio_caelum | Caelum | QCon São Paulo 2010
3. O que aconteceria ao
seu sistema
se os acessos
dobrassem
agora?
Independente do tamanho do sistema hoje, imagine que ele aguente X usuário. Se neste exato
instante chegassem 2X, o que aconteceria? E 3X? 5X?
@sergio_caelum | Caelum | QCon São Paulo 2010
4. 14 dias de tráfego e
Esse é o gráfico de Requests/segundo do site da Caelum ao longo de duas semanas normais em
Agosto/Setembro de 2010. Até que um belo dia acontece o lançamento da nova apostila de Rails 3
do curso RR-71 da Caelum...
@sergio_caelum | Caelum | QCon São Paulo 2010
5. 14 dias de tráfego e
BUM!
... e, em apenas um instante, os acessos ao Site quintuplicam!
Enviamos uma campanha em newsletter para milhares de inscritos, divulgamos no Blog com
milhares de leitores e várias pessoas twitam. Tudo simultaneamente, em uma fria manhã de quinta-
feira.
Como lidar com esse tipo de pico? Como gerenciar os recursos computacionais necessários para
segurar o tranco? E mais, sem desperdiçar recursos nem antes e nem depois; afinal o normal do site
não é esse volume de acessos e o pico logo acaba.
Podemos lançar por partes. Enviar a newsletter aos poucos para pequenos grupos. Divulgar no Blog
apenas no dia seguinte. Mas piorar a experiência dos usuários por limitações técnicas? Perder
aquele momento de marketing onde milhares e milhares de pessoas estão falando de você?
Você passa a vida toda desenvolvendo um produto e querendo que ele dê certo. E um belo dia ele
estoura em sucesso. Como seu sistema reage? Ele capota ou segura o tranco naquele momento
importantíssimo de crescimento? No fim de 2009, sem sabermos, o portal da revista InfoExame fez
uma matéria citando nossas apostilas abertas. Foi uma correria para downloads, muitos e muitos
acessos no site. Imagine não aguentar o tranco em um momento tão especial e com tanta
visibilidade como esse?
@sergio_caelum | Caelum | QCon São Paulo 2010
6. Cloud Computing
A solução rápida e fácil? Cloud computing e computação elástica
@sergio_caelum | Caelum | QCon São Paulo 2010
7. Escalabilidade infinita
Com uma aplicação em cloud, conseguimos aguentar volumes altíssimos de tráfego sem
preocupação
@sergio_caelum | Caelum | QCon São Paulo 2010
8. Escalabilidade infinita
Elasticidade
Mas o principal é conseguir atender a essa demanda de escalabilidade nos momentos em que ela
for necessária. O cloud é elástico porque consegue alocar mais recursos no momento que for
necessário e liberar esses recursos quando não for mais necessário.
@sergio_caelum | Caelum | QCon São Paulo 2010
9. Escalabilidade infinita
Elasticidade
Disponibilidade
Sem o trabalho de manutenção de infra, gerenciamento de backups, replicação, clusters etc, sua
aplicação acaba mais disponível no cloud
@sergio_caelum | Caelum | QCon São Paulo 2010
10. Escalabilidade infinita
Elasticidade
Disponibilidade
Mais barato
Por causa da elasticidade do cloud, os recursos usados são apenas os estritamente necessários no
momento, sem desperdício, sem recursos ociosos. Logo, com um melhor aproveitamento dos
recursos computacionais, geramos economia de custo. Fora a terceirização do trabalho que traz
economias de recursos pela escala.
@sergio_caelum | Caelum | QCon São Paulo 2010
11. Infraestrutura como serviço
IaaS
Quando falamos de cloud, a primeira coisa que vem à cabeça é oferecer uma infraestrutura de
hardware pronta onde podemos comprar recursos de hardware infinitamente. Processamento,
armazenamento, banda, etc.
@sergio_caelum | Caelum | QCon São Paulo 2010
12. Infraestrutura como serviço
IaaS
PaaS
Plataforma como serviço
Mas muito tem se falado também em oferecer uma Plataforma de desenvolvimento em cima dessa
infraestrutura, para não ser apenas um monte de hardware.
O Google AppEngine é um PaaS.
@sergio_caelum | Caelum | QCon São Paulo 2010
13. Infraestrutura como serviço
IaaS
PaaS
Plataforma como serviço
Palestra “Arquiteturas em Cloud”
Com Fábio Kung, amanhã às 16h10
(para entender melhor esses termos e conceitos, não percam a palestra do Kung)
@sergio_caelum | Caelum | QCon São Paulo 2010
14. Infraestrutura e qualidade Google
Sobre o Google AppEngine especificamente. Temos primeiro o oferecimento da infraestrutura e
qualidade de serviços Google, capaz de escalar absurdamente. É a mesma infra e tecnologia usada
nos serviços deles.
@sergio_caelum | Caelum | QCon São Paulo 2010
15. Ambientes Java e Python
São disponibilizados dois ambientes de execução, um Python e um Java. Por oferecer Java, podemos
rodar ainda JRuby, Scala etc
@sergio_caelum | Caelum | QCon São Paulo 2010
16. Persistência com BigTable
Além da plataforma de execução, é oferecido um serviço de persistência (Datastore) usando o
famoso BigTable do Google. É um banco NoSQL, orientado a coluna, consistente e particionável (CP
do CAP).
@sergio_caelum | Caelum | QCon São Paulo 2010
17. Persistência com BigTable
Palestra “NoSQL Erros e Acertos”
Com Gleicon Moraes e Alexandre Porcelli
Amanhã às 18h10
(para entender melhor NoSQL, não percam a palestra amanhã)
@sergio_caelum | Caelum | QCon São Paulo 2010
18. Pague pelo que usa
E um recurso bem interessante é o pagamento pelo uso dos recursos, com controle de quotas e
valores bem acessíveis
@sergio_caelum | Caelum | QCon São Paulo 2010
19. Pague pelo que usa
Paga-se pelo uso de CPU, pela banda, pelos dados armazenados e o número de e-mails enviados.
Repare que existe uma quota free que é suficiente para muitos e muitos casos. E mesmo quando
você começar a pagar, é muito barato. Um centésimo de centavo por e-mail enviado; Meio centavo
por GB armazenado
Introduzido o AppEngine, queria falar alguns pontos legais e algumas dicas sobre o que
aprendemos nesse último ano
@sergio_caelum | Caelum | QCon São Paulo 2010
20. #1 Ambiente de Dev
Primeiro ponto: Ambiente de Dev
@sergio_caelum | Caelum | QCon São Paulo 2010
21. Eclipse + AppEngine SDK + Plugin
Um dos pontos fortes é você usar um ambiente conhecido. Eclipse com Java e um excelente plugin
que integra todas as APIs do SDK. Tudo de graça e facilmente instalável.
@sergio_caelum | Caelum | QCon São Paulo 2010
22. Eclipse + AppEngine SDK + Plugin
One-click deploy
E é ridiculamente fácil fazer o deploy da aplicação: só clicar no botão. Não precisa gerenciar
instâncias, alocar recursos, nada. Só apertar o botão e sua aplicação está lá, escalando
infinitamente e elasticamente.
@sergio_caelum | Caelum | QCon São Paulo 2010
23. #2 Fácil Gerenciamento
Segundo ponto: recursos para gerenciamento remoto da aplicação de modo simples
@sergio_caelum | Caelum | QCon São Paulo 2010
24. Painel de Controle
Há um completo Painel de Controle em http://appengine.google.com
@sergio_caelum | Caelum | QCon São Paulo 2010
25. Painel de Controle
Dashboard - Gráficos e informações completas sobre o uso de quota e comportamento da
aplicação. Páginas mais acessadas, incidência de erros etc
@sergio_caelum | Caelum | QCon São Paulo 2010
26. Painel de Controle
Logs completos de requests, erros e mensagens da aplicação.
Você ainda pode baixá-los offline no formato Apache e processar com qualquer log analyzer como
Analog.
@sergio_caelum | Caelum | QCon São Paulo 2010
27. Painel de Controle
Data Viewer - Observar os dados, editá-los, executar queries no DataStore.
@sergio_caelum | Caelum | QCon São Paulo 2010
28. Versões
Um recurso bem bacana do GAE é a execução de versões diferentes da aplicação simultaneamente
@sergio_caelum | Caelum | QCon São Paulo 2010
29. Versões
No momento do deploy, edita-se um XML do GAE indicando a versão.
@sergio_caelum | Caelum | QCon São Paulo 2010
30. Versões
Depois é possível acessar as versões pelo Painel de Controle. Bons usos é ter uma versão de
produção e uma de testes (PS. cuidado que o DataStore é compartilhado!). Outro uso são versões
com funções especiais, como importar ou exportar dados, ou processar alguma coisa
pontualmente.
Fazer o switch entre versões é trivial: basta marcar como Default e pronto.
No exemplo acima, temos um servidor de integração contínua colocando no ar automaticamente a
versão de testes a cada push pro repositório GIT.
@sergio_caelum | Caelum | QCon São Paulo 2010
31. Status
E, importante para confiar no serviço remoto oferecido, é transparência no momento de possíveis
falhas
@sergio_caelum | Caelum | QCon São Paulo 2010
32. Status
Transparência e visibilidade com relação ao status do sistema e dos subsistemas do AppEngine,
com histórico e relatórios detalhados de cada problema ou anomalia.
@sergio_caelum | Caelum | QCon São Paulo 2010
33. #3 Padronização
Uma das maiores preocupações ao se envolver em uma PaaS é com relação a portabilidade.
Desenvolvo pensando no AppEngine. Mas e se quiser mudar? O pessoal do Google pensou nisso e
pretende apoiar o maior número de especificações Java quanto for possível, gerando baixo
acoplamento com os serviços proprietários deles.
@sergio_caelum | Caelum | QCon São Paulo 2010
34. Servlets 2.5 e JSP 2
Especificações Java Web padrão com algumas pequenas restrições (por exemplo, ausência de
contextDestroyed). Isso permite rodar qualquer framework construído em cima do padrão, como
Struts, JSF, GWT, VRaptor, Spring MVC etc
@sergio_caelum | Caelum | QCon São Paulo 2010
35. Servlets 2.5 e JSP 2
JPA 1 e JDO 2
Implementação das especificações JPA 1 e JDO 2 via um fork do projeto DataNucleus. A ideia é
abstrair o Datastore não relacional do GAE através de uma API portável e conhecida.
@sergio_caelum | Caelum | QCon São Paulo 2010
36. Servlets 2.5 e JSP 2
JPA 1 e JDO 2
java.net
Integração remota com java.net.URL para acesso HTTP e HTTPS. Usa o serviço URLFetch do GAE por
baixo.
@sergio_caelum | Caelum | QCon São Paulo 2010
37. Servlets 2.5 e JSP 2
JPA 1 e JDO 2
java.net
JavaMail
Envio e recebimento de e-mails pela especificação JavaMail da Sun (pacote javax.mail). Mas sem
precisar se preocupar com SMTP, POP, configurações etc
@sergio_caelum | Caelum | QCon São Paulo 2010
38. Servlets 2.5 e JSP 2
JPA 1 e JDO 2
java.net
JavaMail
JCache [ JSR107 ]
Acesso a memcache distribuído através do JCache
@sergio_caelum | Caelum | QCon São Paulo 2010
39. #4 BigTable não é relacional
O quanto antes você perceber isso, melhor será pra você. Implicações:
“Usar JPA para acessar o BigTable é complicado”
“Suas aplicações não serão tão portáveis assim”
@sergio_caelum | Caelum | QCon São Paulo 2010
40. Sem funções de agregação!
count, sum, avg, max, min, group by, having, ...
As entidades salvas são meros punhados de dados, não há schema definido, não há restrições. As
agregações ficam por conta do programador.
Por exemplo, vamos implementar count(*) [parecido pra sum, avg, max, min].
@sergio_caelum | Caelum | QCon São Paulo 2010
41. Sem funções de agregação!
count, sum, avg, max, min, group by, having, ...
Produto
id nome preco
1 Chocolate 4.9
2 Macarrão 3.5
...
Imagine uma simples entidade Produto e uma tabela correspondente.
Como saber quantos produtos existem? Como saber a média de precos?
Precisamos de uma entidade auxiliar pra guardar nossas agregações...
@sergio_caelum | Caelum | QCon São Paulo 2010
42. Sem funções de agregação!
count, sum, avg, max, min, group by, having, ...
Produto AgregacoesProduto
id nome preco
id tipo coluna valor
1 Chocolate 4.9 1 count id 2
2 Macarrão 3.5 2 sum preco 8.4
...
3 avg preco 4.2
E a cada update/insert/delete de Produto, precisamos atualizar as Agregacoes correspondentes.
Pior é quando a tabela principal é muito atualizada. Haverá uma sobrecarga por exemplo na
Agregacao de counts e as operações de escrita começarão a dar timeout e você perderá as
informações. A solução é criar ShardedCounters, vários contadores diferentes, cada um contando
uma parte das entidades. Para obter o count geral você precisa pegar todos os shards e somá-los.
@sergio_caelum | Caelum | QCon São Paulo 2010
43. Transações
não são como estamos acostumados
Como o GAE tem um storage distribuído, as entidades salvas estão espalhadas pelos nós físicos do
Datastore. O GAE não permite então transações envolvendo várias máquinas diferentes.
Conseguimos usar transações se todas as entidades manipuladas nela estiverem no mesmo Entity
Group, o que garante a mesma localização física. Na hora de criar uma nova entidade, você pode
dizer quem é Parent dela e ambas estarão no mesmo grupo.
Porque então não colocamos tudo no mesmo Entity Group? Isso mataria escalabilidade, uma vez
que o Google limita a quantidade de requests que podem ser feitos a um Entity Group. E acertar a
modelagem dos Entities Groups é difícil porque se depois precisar envolver 2 groups diferentes,
não conseguiremos.
Outra característica: se houver contenção (transações manipulando mesmo dado paralelamente),
sua transação falha. O dev deve tentar executá-la novamente, normalmente com um for.
Na prática, muitas das garantias transacionais que estamos acostumados em DBs tradicionais são
agora implementadas pelo programador.
Links:
http://code.google.com/appengine/docs/java/datastore/transactions.html
http://code.google.com/p/objectify-appengine/wiki/Concepts#Transactions
http://code.google.com/appengine/articles/transaction_isolation.html
@sergio_caelum | Caelum | QCon São Paulo 2010
44. Transações
não são como estamos acostumados
Nada de Join
Não é possível fazer Joins em buscas com relacionamentos, uma vez que envolveriam várias
chamadas ao Datastore possivelmente envolvendo máquinas diferentes.
@sergio_caelum | Caelum | QCon São Paulo 2010
45. Transações
não são como estamos acostumados
Nada de Join
Código específico
- Uso da classe Key diretamente quando trabalhar com alguns relacionamentos
- Muitas anotações de “extensão” para recursos específicos, como configurar o Parent
- Variações na JPQL/JDOQL com coisas específicas do GAE, como batch reads
No fim, há muitas diferenças entre um código JPA de verdade e um código JPA rodando no GAE.
Perde-se então toda a teórica vantagem da portabilidade e chega-se a seguinte pergunta: já que
vou perder portabilidade, porque usar JPA/JDO? Porque não usar ferramentas com menos
abstrações e mais próximas do Datastore facilitando a integração com o GAE?
Links:
- Próprio pessoal do DataNucleus falando que a implementação do GAE é nojenta:
http://datanucleus.blogspot.com/2010/01/gaej-and-jdojpa.html
@sergio_caelum | Caelum | QCon São Paulo 2010
46. Datastore Low-level API
Muita gente usa então alternativas para persistência.
Primeiro a Low-level API oficial do GAE que permite acesso baixo nível a coisas do DataStore
@sergio_caelum | Caelum | QCon São Paulo 2010
47. Exemplo de código da Low-level API, mostrando uso direto de Key e Entity. Repare que não há
objetos e que podemos ter quantas propriedades quisermos em cada Entity. Inclusive Entitities
(“linhas”) do mesmo Kind (“tabela”) podem ter propriedades (“colunas”) diferentes.
Link:
http://ikaisays.com/2010/06/03/introduction-to-working-with-app-engine%E2%80%99s-low-
level-datastore-api/
@sergio_caelum | Caelum | QCon São Paulo 2010
49. Aqui, temos uma busca de uma Entity a partir da chave dela (Key)
@sergio_caelum | Caelum | QCon São Paulo 2010
50. Objectify
Como trabalhar com a Low-level API é trabalhoso, existem frameworks alternativos construídos em
cima da Low-level API.
Uma alternativa famosa é o Objectify, um framework escrito em cima da Low-level API, específico
para o GAE, muito mais rápido e com facilidades importantes.
@sergio_caelum | Caelum | QCon São Paulo 2010
51. Modelamos nossa entidade usando um subset das anotações da JPA
@sergio_caelum | Caelum | QCon São Paulo 2010
52. E aqui inserimos o objeto Noticia usando o Objectify
@sergio_caelum | Caelum | QCon São Paulo 2010
53. Exemplo de código do Objectify. Parece JPA, mas é bem mais simples. Não retorna objetos managed
por exemplo; não há dirty check etc
55. Aqui modelamos a entidade. Repare que nenhuma anotação é necessária. A chave também não fica
na classe.
@sergio_caelum | Caelum | QCon São Paulo 2010
56. Aqui inserimos usando o Twig, muito parecido com Objectify também. O store devolve a Key para
depois fazermos uma busca, por exemplo.
@sergio_caelum | Caelum | QCon São Paulo 2010
57. O Twig tem uma interface fluente para fazer buscas. Aqui estamos buscando todas as Noticias no
Datastore. Poderíamos ainda adicionar wheres e orders por exemplo.
@sergio_caelum | Caelum | QCon São Paulo 2010
58. Mas um recurso bem legal e exclusivo do Twig (e da Low-level API) é a execução assíncrona de
queries no GAE. A chamada ao returnResultsLater devolve um java.util.concurrent.Future e retorna
imediatamente.
@sergio_caelum | Caelum | QCon São Paulo 2010
59. Isso me permite executar uma outra atividade no meio e depois voltar pra pegar o resultado da
busca no meu Future
@sergio_caelum | Caelum | QCon São Paulo 2010
60. #5 DataStore não é
confiável e é lento
O DataStore é um sistema distribuído gigantesco com características peculiares e está forte
propenso a erros.
Pelo teorema CAP, o BigTable é um CP: Consistente e Particionável. Mas não está sempre disponível
para leituras e escritas.
@sergio_caelum | Caelum | QCon São Paulo 2010
61. Datastore read-only
Uma primeira situação para a qual é bom estar preparado, é quando o Datastore está em
manutenção e só oferece uma interface Read-only
@sergio_caelum | Caelum | QCon São Paulo 2010
62. Ao tentar persistir alguma coisa (com JPA, Objectify etc)...
@sergio_caelum | Caelum | QCon São Paulo 2010
63. ... o GAE lança uma Exception indicando a indisponibilidade do serviço. É bom estar preparado
@sergio_caelum | Caelum | QCon São Paulo 2010
64. Use o Memcache
O GAE oferece o memcache distribuído para sua aplicação. É bem mais rápido acessar coisas no
cache que ir no Datastore. É uma boa usar o cache sempre que possível.
http://code.google.com/appengine/docs/java/memcache/overview.html
@sergio_caelum | Caelum | QCon São Paulo 2010
65. O código para obter a instância do Cache usando JCache
@sergio_caelum | Caelum | QCon São Paulo 2010
66. Para o dev, toda a infra de cache parece um gigante HashMap. Apenas inserimos objetos associados
a chaves e depois os buscamos. Bem simples de programar
@sergio_caelum | Caelum | QCon São Paulo 2010
67. Um exemplo prático: uma busca no DAO.
@sergio_caelum | Caelum | QCon São Paulo 2010
68. Antes, vemos se não há notícia no cache. Se tiver, devolvemos ela.
Se não tiver, buscamos no datastore e inserimos no cache, disponibilizando para futuras chamadas.
Uma coisa importante é que o memcache não é um serviço de persistência. Não podemos contar
com os dados inseridos lá, eles podem sumir a qualquer momento (por falha do sistema - que não
é persistente - ou porque o GAE precisou de memória). Sua aplicação deve funcionar se o cache
estiver faltando.
@sergio_caelum | Caelum | QCon São Paulo 2010
69. Cache de páginas
Pouca gente sabe, mas existe um proxy reverso no GAE que faz cache de páginas
transparentemente pra você. Basta configurar sua página para ser cacheável
@sergio_caelum | Caelum | QCon São Paulo 2010
70. Coloque o header de Cache-control como public (nas páginas onde for possível isso) e configure o
Expires.
@sergio_caelum | Caelum | QCon São Paulo 2010
71. HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Expires: Sat, 11 Sep 2010 03:04:23 GMT
Date: Sat, 11 Sep 2010 02:49:23 GMT
Server: Google Frontend
Cache-Control: public, max-age=900
Age: 532
O GAE tem um proxy reverso que faz cache de páginas e serve páginas cacheadas da sua aplicação
transparentemente. Aqui vemos o conteúdo de um response cacheado. Repare no Server e no Age
indicando há quanto tempo a página está no cache.
No site da Caelum, economizamos várias horas de CPU cacheando páginas dessa maneira.
@sergio_caelum | Caelum | QCon São Paulo 2010
72. #6 Cold Start Hell
Um dos maiores problemas que as pessoas enfrentam no GAE é esse Cold Start.
@sergio_caelum | Caelum | QCon São Paulo 2010
73. Vamos entender como funciona o processo de inicialização e serviço de um container normal Java
@sergio_caelum | Caelum | QCon São Paulo 2010
74. contextInitialized
Deploy Startup do Contexto servlet.init()
Primeiro, após o deploy da aplicação, ela é inicializada junto com o Contexto e alguns callbacks são
chamados. (vários frameworks costumam inicializar aqui)
@sergio_caelum | Caelum | QCon São Paulo 2010
75. contextInitialized
Deploy Startup do Contexto servlet.init()
Servindo requests servlet.service()
Entra então a fase de servir os requests, quando o contexto já está quente e cada request executa
uma chamada ao método service()...
@sergio_caelum | Caelum | QCon São Paulo 2010
76. contextInitialized
Deploy Startup do Contexto servlet.init()
Servindo requests servlet.service()
servlet.destroy()
Shutdown contextDestroyed
... e, no fim, quando desligamos o contexto, os callbacks de destroy são chamados.
Mas e no AppEngine? Não existe startup nem shutdown! Tudo é request!
@sergio_caelum | Caelum | QCon São Paulo 2010
77. contextInitialized
Startup do Contexto servlet.init()
Servindo requests servlet.service()
O startup é feito no primeiro request que chega na aplicação. Esse usuário tem que esperar o
startup todo e depois a sua chamada ao service para receber a resposta. Os requests subsequentes
executam só o service rapidamente. (e note que não há shutdown!)
Mas o problema é a quantidade de vezes que o contexto é inicializado. Por ser escalável e elástico,
o GAE está o tempo todo alocando e desalocando instâncias de contextos, mudando de máquinas,
etc. Logo esse processo acontece diversas vezes por dia e vários usuários são então penalizados
pelos requests em Cold Start. Se sua aplicação é pequena então, grandes chances que o GAE
desaloque sua instância se você ficar sem acesso por poucos minutos.
Solução?
78. Startup do Contexto contextInitialized
servlet.init()
Servindo requests servlet.service()
O mais importante: diminuir o startup do contexto!
Não use muitos frameworks e ainda aqueles que demandam alta inicialização. Cuidado com fw que
fazem classpath scanning, cuidado com containers IoC que pré-inicializam um monte de coisas,
cuidado com vários frameworks diferentes.
A mudança do Datanucleus para o Objectfy, por exemplo, nos economizou vários preciosos
segundos de startup!
@sergio_caelum | Caelum | QCon São Paulo 2010
79. Startup do Contexto contextInitialized
servlet.init()
Servindo requests servlet.service()
Ping
Outra gambiarra para sistemas pequenos é pingar a aplicação de tanto em tanto tempo (2 min é
uma boa) para manter uma instância quente. Isso diminui o número de cold starts mas não os evita
completamente.
Se você tiver um pico repentino, novas instâncias vão subir em paralelo; se o GAE precisar te mudar
de máquina, uma nova instância sobe; etc.
No site da Caelum, temos entre 20 e 30 Cold Starts por dia, mesmo usando as estratégias
mencionadas.
@sergio_caelum | Caelum | QCon São Paulo 2010
80. #7 Request hard limit
O GAE é bastante limitado, como temos visto, para garantir escalabilidade e disponibilidade do
serviço. Tudo no GAE é um request (inclusive o startup do contexto) e todo request tem um limite
máximo de 30s para executar senão ele é morto. Além disso, não podemos iniciar novas Threads,
tudo deve ser executado na thread no request.
Como executar tarefas complexas então? Por exemplo acessar serviços remotos demorados? Ou
executar grandes operações batch?
Técnica importantíssima: fazer o máximo de coisas assincronamente...
@sergio_caelum | Caelum | QCon São Paulo 2010
81. relembrando...
Já vimos como o Twig permite acessar o DataStore assincronamente, liberando o request pra
processar outras coisas enquanto a operação é efetuada no DataStore.
@sergio_caelum | Caelum | QCon São Paulo 2010
82. Outro momento que podemos ser assíncronos é na integração com outros sistemas. Chamamos
uma URL que pode demorar para devolver um retorno, e podemos fazer isso de maneira assíncrona.
Aqui usamos o serviço de URLFetch do Google que me devolve um Future, como no Twig
PS. Você pode usar java.net.URLConnection mas ela não permite chamada assíncrona; só via a API
low-level do URLFetcher do GAE
@sergio_caelum | Caelum | QCon São Paulo 2010
83. Posso então processar outras coisas e voltar pra pegar a resposta depois.
@sergio_caelum | Caelum | QCon São Paulo 2010
84. Tasks
A grande estrela são as Tasks. Você pode quebrar seu problema em pequenas partes (Tasks) e
inseri-las para processamento assíncrono nas Task Queues do GAE. Mas o que são Tasks? Nada
mais que requests automáticos disparados pra você em alguma URL específica.
@sergio_caelum | Caelum | QCon São Paulo 2010
85. Enviar uma task para processamento é bem simples. É uma URL HTTP que vai ser chamada pra
você.
Escreva sua Servlet ou o que for naquela URL e pronto!
@sergio_caelum | Caelum | QCon São Paulo 2010
86. Aqui um exemplo passando um parâmetro
@sergio_caelum | Caelum | QCon São Paulo 2010
87. Aqui um outro passando um corpo completo (payload)
@sergio_caelum | Caelum | QCon São Paulo 2010
88. Estudo de caso: envio de contatos no site da Caelum!
O processo é bem simples: receber os dados, inserir no Banco e enviar e-mail. Mas precisamos
também chamar um serviço remoto de matrícula que vai devolver um ID pra gente.
A rotina síncrona é bem simples...
@sergio_caelum | Caelum | QCon São Paulo 2010
89. ... recebemos o form, chamamos o servico pra pegar o ID, persistimos e depois enviamos o e-mail.
Problemas:
- E se a chamada remota der pau?
- E se passar de 30s?
- E se o datastore estiver fora?
Solução: Tasks API!
@sergio_caelum | Caelum | QCon São Paulo 2010
90. Vamos chamar o serviço remoto usando uma Task. Vantagens:
- não bloqueia o usuário (isso pode demorar)
- a task é executada até dar certo (cuidado pra preparar o serviço pra isso; e para implementar um
algoritmo de desistência)
Mas, e se o agendamento da Task falhar? Se o Datastore estiver fora? (Tasks dependem do
datastore)
@sergio_caelum | Caelum | QCon São Paulo 2010
91. O mais importante é enviar o e-mail, mesmo que sem a integração remota! Não podemos perder
esse contato!
Ok, mas agora, como tratar a chamada remota e a persistência?
@sergio_caelum | Caelum | QCon São Paulo 2010
92. Meu controller que responde na URL da Task (aqui usando sintaxe do VRaptor)
@sergio_caelum | Caelum | QCon São Paulo 2010
93. Faço a chamada ao serviço remoto.
Sem try/catch! Se falhar, o próprio GAE reagenda a Task para execução novamente!
Mas isso pode ficar infinito, preciso de um ponto de parada...
@sergio_caelum | Caelum | QCon São Paulo 2010
94. ... se estou tentando há mais de 30min, desisto da chamada remota e envio o e-mail logo.
Preciso depois persistir e enviar o e-mail. Mas onde? Aqui mesmo? Não, assíncrono!
95. O e-mail é mais fácil porque o serviço é naturalmente assíncrono (o envio não é feito na hora, você
nunca recebe um erro de resposta).
PS. Repare aqui também que o e-mail é enviado em ambas as circunstâncias, com o serviço remoto
funcionando ou não.
@sergio_caelum | Caelum | QCon São Paulo 2010
96. Crio uma nova Task de persistência. Assim ele fica tentando automaticamente se o primeiro insert
falhar... e ainda quebra em coisas menores pra evitar o limite de 30s...
@sergio_caelum | Caelum | QCon São Paulo 2010
97. Aqui eu persisto o contato e fico tentando até dar certo. E não podemos esquecer da condição de
parada caso a persistência falhe muitas vezes.
PS. uma boa prática seria logar esses momentos que ele desiste de certa tarefa
@sergio_caelum | Caelum | QCon São Paulo 2010
98. #8 Serviços legais
Por último, uma das grandes vantagens do GAE, além da elasticidade do cloud, é a quantidade de
serviços legais já prontos para uso. Já vimos vários, vamos ver mais alguns...
@sergio_caelum | Caelum | QCon São Paulo 2010
99. Recebimento de e-mails
Tudo no AppEngine é um request! Inclusive receber emails!
Caso legal: queremos mostrar as newsletters enviadas no Site da Caelum. Ao invés de fazer um
cadastro de newsletters vamos inscrever o Site no sistema de envio de newsletter
@sergio_caelum | Caelum | QCon São Paulo 2010
100. Recebimento de e-mails
qualquercoisa@suapp.appspotmail.com
recebimento@caelumcombr.appspotmail.com
Toda aplicação ganha seu subdomínio no appspotmail.com e pode receber e-mails em diversos
endereços.
@sergio_caelum | Caelum | QCon São Paulo 2010
101. Recebimento de e-mails
Basta escrever uma Servlet respondendo na URL
/_ah/mail/recebimento@caelumcombr.appspotmail.com
....
@sergio_caelum | Caelum | QCon São Paulo 2010
102. Recebimento de e-mails
... e tratar o request como uma mensagem do JavaMail, sem segredo
@sergio_caelum | Caelum | QCon São Paulo 2010
103. Cron
Serviço de agendamento de tarefas do GAE. Como sempre, é tudo request.
Você indica a periodicidade e a URL de execução. Só.
@sergio_caelum | Caelum | QCon São Paulo 2010
104. Cron
Temos uma URL aqui que importa posts do blog wordpress da Caelum, outro que importa o
calendario.json do sistema de gerenciamento de turmas da Caelum e um terceiro que mantém a
instância ativa, pingando a cada 2 min para minimizar a possibilidade de cold start.
@sergio_caelum | Caelum | QCon São Paulo 2010
105. Autenticação Google
Há vários métodos de autenticação prontos, inclusive OpenID.
Mas um dos mais simples e efetivos é usar contas do Google! Você ganha um sistema já pronto,
confiável, seguro...
@sergio_caelum | Caelum | QCon São Paulo 2010
106. Autenticação Google
No seu web.xml, basta usar uma <security-constraint> (padrão Java EE!!) para filtrar URLs.
O role de admin só permite usuários cadastrados como admins da app a fazerem o login.
@sergio_caelum | Caelum | QCon São Paulo 2010
107. Autenticação Google
Mas podemos permitir qualquer usuário Google também, mudando o role para *
@sergio_caelum | Caelum | QCon São Paulo 2010
108. Autenticação Google
E, em Java, podemos acessar o usuário logado, pegar seu e-mail ou seu ID da Conta do Google.
@sergio_caelum | Caelum | QCon São Paulo 2010
109. BlobStore
Esse é um dos serviços mais recentes disponibilizados pelo GAE. E um dos que mais recentemente
precisamos usar no Site da Caelum. No mesmo lançamento da apostila do começo do mês que
fizemos, tivemos um problema com os downloads das apostilas. Nossos PDFs, desde muito
antigamente, ficam em um outro servidor Apache puro (sem Java, Rails etc) que apenas servia os
milhares de downloads diários.
Mas no dia do lançamento da apostila de Rails 3, nosso servidor de downloads não aguentou. E por
alguns instantes passou a negar alguns requests de download. Logo depois desse episódio,
passamos a servir os PDFs também pelo GAE, usando o novo serviço de BlobStore deles.
O Datastore normal tem restrições quanto ao tamanho das entidades (no máximo 1 MB). Para servir
arquivos grandes, eles disponibilizam o BlobStore, com ‘limit’ de 2GB no tamanho de cada Blob.
Fazer o upload é fácil...
@sergio_caelum | Caelum | QCon São Paulo 2010
110. BlobStore
Primeiro passo é um fazer um formulário que tenha um input file. A URL de upload vai ser obtida
direto do BlobStore...
@sergio_caelum | Caelum | QCon São Paulo 2010
111. BlobStore
... o parâmetro passado é a URL pra onde o BlobStore redireciona após o salvar o upload.
@sergio_caelum | Caelum | QCon São Paulo 2010
112. BlobStore
... nessa URL, podemos recuperar a Key associada a esse Blob uploadado...
@sergio_caelum | Caelum | QCon São Paulo 2010
113. BlobStore
E, por último, na Servlet de download, mandamos o BlobStore servir nosso blob (pela chave)
diretamente no response. Não precisa abrir o arquivo, buscar, carregar na memória... nada.
É simples e efetivo.
@sergio_caelum | Caelum | QCon São Paulo 2010
116. Escalabilidade, Disponibilidade
Elasticidade e baixo custo
- Elasticidade me permite atender picos de acesso e momentos de inatividade sem desperdício,
pagando (pouco) apenas pelo que uso
117. Escalabilidade, Disponibilidade
Elasticidade e baixo custo
Serviços prontos
- Serviços fantásticos e prontos como Datastore, Tasks, Memcache, Envio de e-mails, Blobstore,
Autenticação etc; e outros, como processamento de imagens, envio e recebimento de XMPP
@sergio_caelum | Caelum | QCon São Paulo 2010
118. Escalabilidade, Disponibilidade
Elasticidade e baixo custo
Serviços prontos
Limitações e lock-in
O ambiente do AppEngine é fastástico. Mudar o Caelum.com.br para lá, no começo, foi uma decisão
para possibilitar estudar o novo ambiente. Com o tempo, percebemos que foi uma das melhores
decisões arquiteturais que tomamos. As vantagens do GAE compensam muito algumas poucas
desvantagens. E, muitas vezes, o que aparenta ser uma desvantagem acaba nos forçando a
programar direito e evitar problemas futuros.
Mas temos que aprender a lidar com as limitações do ambiente, em especial o tradeoff com relação
a performance e confiabilidade. O objetivo da palestra foi mostrar o caminho das pedras para quem
pretende entrar no GAE, economizar algumas horas de estudo.
No fim, acabamos escrevendo muito código voltado pra infra do GAE o que pode trazer o vendor
lock-in.
@sergio_caelum | Caelum | QCon São Paulo 2010
119. Escalabilidade, Disponibilidade
Elasticidade e baixo custo
Serviços prontos
Limitações e lock-in
Palestra “O Impacto do Design na sua arquitetura”
Com Paulo Silveira, amanhã à 13h10
Mas evite espalhar o código específico, um bom design permite uma boa troca de arquitetura!
(não perca amanhã a palestra do Paulo Silveira sobre o assunto!)
@sergio_caelum | Caelum | QCon São Paulo 2010
120. Sérgio Lopes
sergio.lopes
@caelum.com.br
@sergio_caelum
Obrigado!
@sergio_caelum | Caelum | QCon São Paulo 2010