5
30 : : www.mundoj.com.br : : no Google App Engine Escreva aplicações Java para o serviço de Cloud Computing da Google Pedro Mariano ([email protected]): é técnologo em Análise e Desenvolvimento de Software pela FIAP, possui a certificação SCJP 6. Trabalha como consultor e desenvolvedor pela Caelum com linguagens como Ruby e Java. Atualmente, o Cloud Computing é um dos assuntos mais comentados na área de TI. Assunto este que já é realidade no mercado: diversas empresas, como Amazon, RackSpace e Microsoft, já possuem soluções de infraestrutura em cloud. A Google também entrou neste mercado e já oferece um ambiente de Cloud Computing no qual os desenvolvedores podem colocar suas aplicações: o Google App Engine. Este artigo aborda exemplos práticos de uma aplicação Java com VRaptor 3 construída para o AppEngine. Cloud Computing — normalmente traduzido para o português como Computação nas Nuvens — está em grande ascendência. Esse crescimento é impulsionado pela necessidade de se ter sistemas escaláveis, com alta disponi- bilidade e altamente performáticos. Mas um fator que tem sido frequentemente destacado como motivação para adoção de solu- ções de cloud é a forte redução no custo de manutenção da parte de infraestrutura das aplicações. Como as tarefas de infraestrutura são realizadas pelo provedor do serviço, a equipe de desenvolvimento pode se focar apenas em criar a aplicação que, idealmente, irá escalar automaticamente, seguindo a demanda. Na maioria das vezes, a tarifação destes serviços é feita de forma a cobrar pela quantidade de recursos consumidos, tais como espaço de armazenamento e tempo de processamento. o Google AppEngine, com exemplos de uso dos recursos providos pelo serviço. Java Pedro Matiello ([email protected]): trabalha como consultor e desenvolvedor pela Caelum e é aluno do curso de Bacharelado em Ciência da Computação no IME-USP.

Java no Google App Engine · exemplos práticos de uma aplicação Java com VRaptor 3 construída ... bastante concisa e fácil de trabalhar, ... da aplicação no appengine-web.xml

  • Upload
    hakhanh

  • View
    216

  • Download
    0

Embed Size (px)

Citation preview

30

: : www.mundoj.com.br : :

no Google App EngineEscreva aplicações Java para o serviço de Cloud Computing da Google

Pedro Mariano ([email protected]): é técnologo em Análise e Desenvolvimento de Software pela FIAP, possui a certificação SCJP 6. Trabalha como consultor e desenvolvedor pela Caelum com linguagens como Ruby e Java.

Atualmente, o Cloud Computing é um dos assuntos mais comentados na área de TI. Assunto este que já é realidade no mercado: diversas empresas, como Amazon, RackSpace e Microsoft, já possuem soluções de infraestrutura em cloud. A Google também entrou neste mercado e já oferece um ambiente de Cloud Computing no qual os desenvolvedores podem colocar suas aplicações: o Google App Engine. Este artigo aborda exemplos práticos de uma aplicação Java com VRaptor 3 construída para o AppEngine.

Cloud Computing — normalmente traduzido para o português como Computação nas Nuvens — está em grande ascendência. Esse crescimento é impulsionado

pela necessidade de se ter sistemas escaláveis, com alta disponi-bilidade e altamente performáticos. Mas um fator que tem sido frequentemente destacado como motivação para adoção de solu-ções de cloud é a forte redução no custo de manutenção da parte de infraestrutura das aplicações.

Como as tarefas de infraestrutura são realizadas pelo provedor do serviço, a equipe de desenvolvimento pode se focar apenas em criar a aplicação que, idealmente, irá escalar automaticamente, seguindo a demanda. Na maioria das vezes, a tarifação destes serviços é feita de forma a cobrar pela quantidade de recursos consumidos, tais como espaço de armazenamento e tempo de processamento.

o Google AppEngine, com exemplos de uso dos recursos providos pelo serviço.

JavaPedro Matiello ([email protected]): trabalha como consultor e desenvolvedor pela Caelum e é aluno do curso de Bacharelado em Ciência da Computação no IME-USP.

31

Google App Engine

A Google também decidiu oferecer um serviço de Cloud Compu-ting, denominado Google App Engine (GAE). Mesmo estando em fase beta, diversas empresas, como a BestBuy com o seu produto GiftTag, estão utilizando o GAE.

Diferentemente de muitos de seus concorrentes, a Google oferece um plano inicial gratuito, que é suficiente para aplicações e sites de pequeno e talvez até de médio porte (permite-se, por exemplo, até 1.300.000 requisições gratuitas ao banco, por dia). Aplicações consumindo recursos além dos estipulados neste plano são tarifa-das de forma proporcional ao que foi consumido além dos limites da cota gratuita.

Atualmente, o GAE suporta duas linguagens de programação: Java e Python, e ambas com algumas restrições quanto ao que se pode fazer no ambiente. Em grande parte dos casos, o próprio GAE oferece uma alternativa através de uma API proprietária, que é bastante concisa e fácil de trabalhar, mas que prende a aplicação ao serviço (o chamado vendor lock-in).

App Engine além do Python e Java

Apesar de o GAE oficialmente oferecer suporte apenas para Java e Python, é possível também criar aplicações Ruby, Scala e JavaScript. Com Ruby, é necessário que você utilize o JRuby e com JavaScript o Rhyno. De uma forma geral, o GAE oferece

Devido à grande popularidade do framework Rails, correm ru-mores de que a Google estaria interessada em oferecer suporte nativo para a linguagem Ruby.

Esta API exclusiva do App Engine oferece acesso aos serviços do GAE disponíveis para realizar tarefas comuns e nem tão comuns, tais como envio de e-mails, persistência de dados, execução as-síncrona (tasks) e agendada (cron). Neste artigo são abordados alguns desses serviços, dando detalhes de seu uso e algumas dicas.

Nossa experiência com o GAE

Em 2009, completamos a migração do nosso site [1] para o App

que oferece uma configuração específica para rodar no GAE, feita para contornar as restrições do ambiente de execução do serviço.

Após todos estes meses, podemos dizer que a experiência é bas-tante satisfatória. Dentre as vantagens do serviço, destacamos sua escalabilidade, que nos permitiu aguentar picos de acesso ao site da Caelum sem comprometer o desempenho e a disponibilidade do site. A interface administrativa do App Engine também se mos-trou muito conveniente, permitindo analisar os logs e relatórios de desempenho do site de forma bastante simples.

Outro recurso muito útil do GAE é o sistema de versionamento das aplicações: é possível ter versões diferentes de sua aplicação instaladas e rodando concorrentemente. Desta forma, podemos testar novas versões do site no ambiente de produção sem com-

prometê-lo, e só fazer a troca quando estiver tudo como espera-mos. Trata-se de uma estratégia de deploy contínuo [2] como a apresentada por Martin Fowler [3].

GAE e o VRaptor 3

Por causa da grande quantidade de componentes restritos, muitos fra-

Ele oferece um download específico pronto para todos os desenvolve-dores interessados em utilizar o framework no cloud da Google. Este é

feito para ser usado como ponto de partida de novos projetos.

Para começar, instale o plugin do App Engine [4] no Eclipse, baixe e importe o projeto vraptor-blank-project-gae, ajuste o classpath de acor-do com a versão do SDK do GAE (que acompanha o plugin) e o nome da aplicação no appengine-web.xml. Feito isso, podemos começar a

fazer deploy a qualquer momento clicando com o botão direito sobre o projeto no Eclipse e escolhendo Deploy to App Engine dentro do submenu Google.

possui um método que disponibiliza a mensagem "olá mundo" para a view.

Para Saber Mais

Na edição 38 da Revista MundoJ você pode conferir um tuto-

@Resourcepublic class IndexController { @Path(“/”) public String index() { return “ola mundo”; }}

...<body>${string}</body>...

Persistência

O App Engine oferece como mecanismo de persistência um banco de dados (Datastore) orientado a documentos que tem como base o Big-Table. Trata-se de um banco proprietário e desenvolvido pela própria

32

: : www.mundoj.com.br : :

Listagem 3. Entidade Carro.

Listagem 5. Método para buscar todos os carros.

Listagem 6. Método para buscar todos os carros de uma cor.

Listagem 7. Método para buscar todos os carros de uma cor.

Listagem 8. Método que busca os dois últimos carros cadastrados de determinada cor..

Listagem 4. DAO para entidade Carro como componente

class Carro { @Id private Long id; private String cor; private String placa; private boolean licenciado; // getters e setters ...}

@Componentpublic List<Carro> buscaTodos() { return datastore.query(Carro.class).list();}

public List<Carro> buscaDaCor(String cor){ return datastore.query(Carro.class).filter(“cor”, cor).list();}

public Carro buscaComPlaca(String placa){ return datastore.query(Carro.class).filter(“placa”, placa).get();}

public List<Carro> ultimosDoisCarrosCadastradosDaCor(String cor){//o método order por padrão é crescente caso você queira que seja // decrescente utilize//o carácter - na frente do atributo datastore.query(Carro.class) .filter(“cor”, cor) .order(“-id”) .limit(2) .list();}

@Componentclass CarroDAO { ObjectifyService datastore; static { ObjectifyService.register(Carro.class); } public CarroDAO() { datastore = ObjectifyService.begin(); } public void salva(Carro carro) { datastore.put(carro); } public Carro busca(Long id) { return datastore.get(Carro.class, id); } public void deleta(Carro carro) { datastore.delete(carro); }}

Google, com foco em alto desempenho e escalabilidade.

O Google App Engine oferece três formas diferentes de acessar o Datas-tore: uma API de baixo nível (não muito utilizada por ser complexa), o JDO (Java Data Objects) e a JPA (Java Persistence API). Estas duas últimas são APIs mais simples e familiares aos desenvolvedores Java, mas também não foram projetadas para o Datastore e suas característi-cas incomuns, mas sim para modelos mais tradicionais de persistência. Além disso, as entidades, sempre que criadas ou modificadas, precisam passar por um processo de pós-compilação um tanto inconveniente. Para contornar as dificuldades de usar o JDO ou a JPA no GAE, novos projetos open source surgiram com APIs alternativas de persistência levando em conta peculiaridades do Datastore. Dentre elas, destacam-se o Twig, o SimpleDS e o Objectify.

Nós optamos pelo Objectify por sua simplicidade e boa documen-tação. Esta API se define como uma camada fina sobre o Datastore, respeitando suas características estruturais, mas de uma forma mais usável pelos programadores.Para começar, definimos uma entidade. No Objectify, as entidades são POJOs acrescidos de um identificador que deve ser um Long ou uma String anotado com @Id. A Listagem 3 apresenta um exemplo simples de entidade. A Listagem 4 apresenta um DAO para esta classe, que a registra no Objectify e realiza operações de escrita e leitura.

Além destas três operações (get, put, delete), uma quarta é su-portada pelo Objectify: query. Através de uma interface fluente, pode-se realizar consultas ao datastore em busca de entidades que satisfaçam determinados critérios.

A Listagem 5 apresenta um método que devolve todas as entida-des do tipo Carro armazenadas no banco da aplicação.

A Listagem 6 apresenta um método que devolve todos os carros de uma determinada cor, e a Listagem 7 apresenta um método que busca um Carro através de sua placa.

O Objectify ainda disponibiliza outros métodos para refinar as

mais complexa na Listagem 8, que utiliza métodos combinados para gerar uma consulta mais refinada.

O Objectify também possibilita que você crie relacionamentos dos tipos One-to-Many e Many-to-One. Na Listagem 9 pode-se ver um exemplo no qual mapeamos a classe Carro com a classe Motorista, dizendo que um Carro possui um motorista.

33

Listagem 9. Entidade Carro com o atributo Motorista com o relacionamento Many-to-One.

Listagem 10. Entidade Carro com o atributo Motoristas definindo um relacionamento One-To-Many.

-ção é verificar se a placa passada está licenciada.

Listagem 12. Colocando na fila de tarefas a execução da verificação de determinada placa.

class Carro { @Id private Long id; private String cor; private String placa; private String licenciado; Key<Motorista> motorista; // getters e setters ...}

class Carro { @Id private Long id; private String cor; private String placa; private String licenciado; Key<Motorista>[] motoristas; // getters e setters ...}

@Resourcepublic class CarroController { @Path(value=”/verificaPlaca/”) public void verificaPlaca(String placa) { boolean estaLicenciado = new VerificadorDePlaca().verificaPlaca(placa);//atualiza localmente o status do carro. Carro carro = carroDAO.buscaComPlaca(placa); carro.setLicenciado(estaLicenciado); carroDAO.salva(carro) }}

Queue queue = QueueFactory.getDefaultQueue();queue.add(url(“/verificaPlaca”).param(“placa”,”ABC7887”));

Perceba que o atributo motorista é do tipo Key. Isso é necessário, pois o objectify não faz relacionamentos “managed” como a JPA ou o JDO, portanto, ele armazena os dados do relacionamento nessa classe genérica chamada Key.

one-to-many em que um carro possui um ou mais motoristas. Perceba que a única diferença é que o atributo motoristas é um array de Keys.

Quando estiver utilizando o Datastore tenha em mente que, por ele não ser um banco de dados relacional, possui algumas limi-tações. Relacionamentos many-to-many, consultas polimórficas e com agregações (sum, avg, max etc.) não são suportadas. Estas características são comuns em bancos não-relacionais, como o BigTable, que trocam parte das funcionalidades para obter maior desempenho e escalabilidade.

Frameworks como o Twig oferecem uma forma mais natural de fazer relacionamentos sem a necessidade de se utilizar uma classe específica, que no caso do objectify é a Key. Porém, o Twig ainda possui alguns bugs e por isso não o escolhemos.

Além disso, é bastante comum, e até indicado, que se tenham resul-tados do BigTable. Para isso, podemos usar o serviço de memcache do GAE. Além de aumentar a performance, é também uma questão de disponibilidade, já que o BigTable pode apresentar downtimes.

Tasks

Outro recurso importante do GAE é a possibilidade de criar tarefas (Tasks) e inseri-las em uma fila (criada por você ou então o padrão que o Google oferece). Esta fila é gerenciada pelo próprio App Engine, que

irá detectar novas inserções e executá-las sempre que houver recursos disponíveis para tal.

Trata-se de um mecanismo de execução assíncrona: embora uma carga de trabalho seja iniciada por uma requisição, sua execução ocorre fora desta requisição. A motivação natural para o uso deste mecanismo é a execução de tarefas que não exigem uma resposta imediata para o cliente ou que podem consumir excessivamente os recursos do sistema se realizadas de forma desordenada.

Uma tarefa, aqui, é entendida como um método que realiza algum trabalho acrescido dos dados relevantes para sua execução. O método é endereçado por uma URL e os dados são passados como parâmetros de requisição. Quando uma tarefa é selecionada para a execução, o GAE realiza uma requisição HTTP para a URL especificada com os parâmetros dados.

-tor 3 com um método para verificar o licenciamento de uma placa. Esse método será chamado de forma assíncrona pela tasks API, como demonstrado no exemplo da Listagem 12. No nosso cenário vamos as-

do governo que, ocasionalmente, pode não estar acessível. Caso o siste-ma esteja inacessível, a Tasks API irá tentar de novo até que o processo seja feito com sucesso. Esse exemplo ilustra uma das vantagens de se utilizar a API de Tasks, garantindo que seu processo será executado.

A criação de tarefas corresponde, na prática, à inserção de URIs numa fila. A execução de uma tarefa, portanto, corresponde a rea-lizar uma requisição para a URI associada. Esta requisição, por sua vez, deve ter como resposta um código de retorno HTTP — 200 (OK) em caso de sucesso, e qualquer outro valor em caso de falha. Caso a resposta indique a ocorrência de um erro no processamen-to, a tarefa será reinserida na fila para ser processada novamente. É possível também limitar o número de tentativas através da criação de outra fila e da adição do header HTTP X-AppEngine-TaskRetryCount com o número máximo de tentativas.

34

: : www.mundoj.com.br : :

Limitações e cuidados

Além da execução assíncrona e da persistência, o App Engine ofe-rece outros serviços que podem ser úteis ou mesmo essenciais para algumas aplicações web.

-mente, usado para acelerar o acesso a objetos do Datastore.

outros hosts na web.

-namento etc.).

Ao utilizar qualquer serviço do GAE, informe-se a respeito do limite para uso gratuito do mesmo e das taxas aplicáveis para uso além deste limite. Além disso, alguns serviços estão em fase beta e o Goo-gle não garante total disponibilidade e/ou estabilidade do mesmo.

Para garantir a segurança e a escalabilidade do serviço, o App Engi-ne impõe algumas restrições sobre as aplicações nele hospedadas. Para começar, dentre as classes do JRE, apenas um subconjunto é suportado [6]. Também não é permitida a criação de threads, arquivos ou sockets, mas estas restrições podem ser, em muitos casos, contornadas pela API de Tasks, pelo Datastore, e pelas APIs de Email e HTTP específicas do GAE.

As views e JSP exigem um cuidado a mais: o suporte a Expression Language vem desativado por padrão e não pode ser habilitado globalmente. Neste caso, é preciso adicionar a linha abaixo em todo arquivo JSP que faz uso de EL:

<%@ page isELIgnored="false" %>

Por fim, outro detalhe que merece bastante atenção é o tempo de inicialização das instâncias (conhecido como cold start). Quando sua aplicação é chamada pela primeira vez, uma instância é criada e executada por um dos servidores da nuvem. Este processo é lento, podendo consumir vários segundos, dependendo tanto da disponibilidade de recursos no GAE naquele momento como do tamanho da aplicação e das bibliotecas e frameworks usados. Os acessos seguintes são respondidos com baixa latência, mas, após um período de inatividade, as instâncias são destruídas, exigindo que todo o lento processo de inicialização seja refeito pelo serviço em um próximo acesso. Para evitar isso, a prática mais comum tem sido usar o agendador de tarefas do próprio App Engine para visitar alguma página do site a cada minuto, mantendo assim uma instância da aplicação sempre ativa. A Google diz estar estudando outra forma de contornar o problema.

Considerações finais

A solução de Cloud Computing da Google certamente tem atra-ído grande atenção. Por um baixo custo, é possível obter, com este serviço, um alto nível de segurança e escalabilidade, além de

ferramentas e serviços que facilitam a vida do desenvolvedor e aumentam a produtividade da equipe.

As limitações, contudo, são uma realidade, e adaptações tanto no modo de programar quanto na forma de estruturar sua aplicação deverão ser consideradas ao se desenvolver aplicações para o GAE. A situação em vista é, claramente, uma troca: disponibili-dade, confiabilidade e segurança são obtidas a custo de alguma flexibilidade. Outras plataformas, como serviço (PaaS), estão apa-recendo para a plataforma Java, e algumas com menos restrições:

Force [7], que estará disponível em alguns meses.

A Caelum, como anteriormente mencionado, utiliza o GAE em seu site. A experiência tem se mostrado cada vez mais compensa-dora e satisfatória. A curva inicial de aprendizado e de adaptação pode ser transposta sem maiores problemas e o investimento inicial é pago rapidamente com menores custos de administração do servidor e pela proteção contra picos de acesso.

A Google melhora o App Engine constantemente e, mensalmente, novas versões do kit de desenvolvimento são lançadas. Se você é um programador interessado em criar aplicações escaláveis gas-tando pouco ou nada com infraestrutura, realmente vale a pena

App Engine for Business

Recentemente, a Google anunciou uma nova versão do GAE com o foco em aplicações “enterprise”. De acordo com a Goo-gle, a intenção é continuar oferecendo serviços do nível do Google App Engine, acrescido de suporte e de alguns serviços como o suporte a incluindo um banco de dados relacional e SSL.

O App Engine for Business [8] é oferecido a um preço de 8 dólares por usuário além das taxas de consumo.

Referências