Formation Google App Engine

Post on 21-May-2015

2.193 views 0 download

description

Développer une application sur le Cloud avec Google App Engine Formation animée par Rhanizar Abdelhakim

Transcript of Formation Google App Engine

Google App Engine Formation pratique

Février, 2013

Formation animée par: RHANIZAR Abdelhakim

Objectifs de la formation

• Se familiariser avec les services de GAE et son DataStore• Savoir les contraintes liées au développement sur GAE• Développer et déployer en Live des applications Web sur

l’infrastructure GAE• Avoir suffisamment de connaissance pour passer à la vitesse

supérieure

2

Sommaire

I. Présentation générale

II. Services offerts par GAE

III. Persistance dans GAE

IV. Web services Rest dans GAE

* Code Lab après chaque partie

3

A propos de moi

• RHANIZAR Abdelhakim• Ingénieur d’état en informatique• Spécialiste du Cloud Computing & RIA

4

a.rhanizar@gmail.com

@a_rhanizar

Première partie

GAE: Présentation générale

5

Google App Engine

• Plateforme (PaaS) pour développer et déployer des applications Web sur l’infrastructure de Google

• Support des RunTime Java (JRuby, Groovy, Scala...), Python et Go• Réutilisation de la plupart des API -Java- standards (Servlet/JSP ,

Mail, JPA, JDO..) et des frameworks populaires (Struts 2, Spring MVC, …)

• Quotas gratuits puis Pay-As-You-Go

6

GAE: Avantages

• Infrastructure haut de gamme de Google• Flexibilité/Scalabilité automatique• Réduction du Time to marquet• Plus d’agilité• Quota gratuit généreux• Pay per Use• 99.95 SLA

7

Etat de santé de GAE

• http://code.google.com/status/appengine -> A suivre!• google-appengine-downtime-notify@googlegroups.com -> A adhérer!

8

GAE: Architecture et fonctionnement

9

RPC calls

Services Cluster 2

Services Cluster 1MemCache Task Queue

MemCache

MemCacheTask Queue

MemCache

Frontend 1

Frontend 2

Backend 1

Backend 2

Frontend 1

Frontend 2

Backend 1

Backend 2

Backend N

Sandbox

• Environnement qui isole l’exécution des applications GAE et facilite leur sclabilité pour Google

• Plusieurs restrictions imposées sur les threads• Une application GAE ne peut pas:

Ecrire dans un fichier système (java.io.FileWriter) Accéder à un fichier qui n’a pas créé Communiquer avec l’extérieur sans passer par les API de GAE

(Sockets, HttpClient) Faire des appels système (java.lang.System)

• Liste des classes Java autorisées: https://developers.google.com/appengine/docs/java/jrewhitelist

10

Frontend Vs Backend instances11

Fonctionnalité Frontend Backend

Limites 60 sec maxi par requête HTTP10 min maxi par tâche/job

100 API call simultanés par requête HTTP24h maxi / job

CPU Flexible, facturé à l’usage Configurable 400 MHz – 4.8 GHz

Mémoire 128 Mb Configurable 128 Mb – 1 Gb

Volatilité Instances volatiles/dynamiques

Configurable ( Résident + dynamique )

Accessibilité Instance anonyme Accessible via une URLhttp://instance.backend_name.your_app_id.appspot.com

Scalabilité Automatique (GAE Scheduler) Configurable

Requêtes simultanées

Off par défaut, 10 maxi Oui, le nombre de requêtes maxi est configurable

Prix des instances Backend

Classe RAM CPUTarif horaire d’une instance

Tarif mensuel d’une instance

B1 128MB 600MHz $0.08 $57.60

B2 (Par défaut) 256MB 1.2GHz $0.16 $115.20

B4 512MB 2.4GHz $0.32 $230.40

B8 1024MB

4.8GHz $0.64 $460.80

12

Avez-vous vraiment besoin d’utiliser des instances Backend?

Bonne pratique: Exécuter les traitements lourds dans des tâches (queue) -> 10 min/tâche au lieu de 1min/requête!

Le scheduler GAE

• C’est un service qui décide comment traiter une requête d’un utilisateur:1. La faire servir par une instance Idle

2. Lancer une nouvelle instance pour la servir

3. Attendre la libération d’une instance existante

13

Client 1

Client 2

Client 3

Scheduler

Requête HTTP R1

Requête HTTP R3

Requête HTTP R2

Instances occupées

R2 R1

Requête HTTP R3

File d’attente

Instances fraîchesUne application non optimisée -> temps d’attente important-> UX dégradée + argent dépensé dans le CPU

GAE: Dashboard d’administration14

Code Lab N1

Pré-requis: • Eclipse JEE Edition• JDK 6• SDK GAE pour Java• Version JEE de Eclipse• Google plugin pour Eclipse• Un compte Gmail• Un téléphone mobile

Objectifs:• Créer votre première application sur GAE• Déploiement en Live• Comprendre le cycle de développement sur GAE• Se familiariser avec la console d’administration

• Instructions dans le fichier lab1.pdf

15

Deuxième partie

GAE: Services

16

Services dans GAE

• GAE offre une variété de services qui augmentent la productivité• La plupart de ces services respectent les standards Java

17

Services Clés18

String key = ‘email’;   User user =null;

    // Using the synchronous cache    MemcacheService syncCache = MemcacheServiceFactory.getMemcacheService();     user = (User) syncCache.get(key); // read from cache    if (user == null) {      // get user from other source (Date Store)      // ........      syncCache.put(key, user, Expiration.byDeltaSeconds(60)); // populate cache    }

MemCache

• Cache distribué pour stocker les données• Deux modes d’écriture: synchrone et asynchrone• Mémoire volatile• Taille maximale de 1Mb par objet stocké

19

Bonne pratique: 1- Memcache est un service à utiliser sans modération afin de soulager le DateStore2- Faire des insertions en Batch -> cache.putAll(values)

Files d’attente: Task Queue

• Effectuer un traitement en tâche de fond en dehors des requêtes des utilisateurs

• Organiser le travail en petites unités discrètes appelées tâches• Ces tâches sont mises dans une ou plusieurs files d'attente• Elles sont exécutées lorsque les ressources système le permettent

20

Caractéristiques Push Queue Pull Queue

Scalabilité Automatique par GAE A votre charge(workers backend)

Gestion des tâches Automatique A votre charge(suppression,…etc)

Accès par les tiers non Oui (Rest API)

Quota: Taille maxi / tâcheNombre max de queues activesTaux d’exécution maxi

100 Kb10 Free, 100 app payante500/sec/queue

1 Mb10 Free, 100 app payantePersonnalisable

<queue-entries>  <queue>    <name>queue_name</name>    <rate>1/s</rate> <bucket-size>40</bucket-size>    <max-concurrent-requests>10</max-concurrent-requests>    <retry-parameters>      <task-retry-limit>7</task-retry-limit>      <task-age-limit>2h</task-age-limit>    </retry-parameters>  </queue>

Push Queues en pratique

• WEB-INF/queue.xml

21

import com.google.appengine.api.taskqueue.Queue;import com.google.appengine.api.taskqueue.QueueFactory;import static com.google.appengine.api.taskqueue.TaskOptions.Builder.*;

// ...    Queue queue = QueueFactory.getQueue("queue_name");    queue.add(withUrl("/worker").param("key", key));

try {            URL url = new URL("http://www.example.com/atom.xml");            BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));            String line;            while ((line = reader.readLine()) != null) {                // ...            }            reader.close();

        } catch (Exception e) {            // ...        }

Url Fetch

• API pour communiquer avec d’autres applications ou accéder à d’autres ressources sur le Web

• Support du protocole HTTP (POST, GET, PUT,…)• Appels en synchrone et asynchrone

22

Restriction Quantité

taille d'une requête 1 Mo

taille d'une réponse 1 Mo

Pour savoir plus sur les quotas du service Url Fetchhttps://developers.google.com/appengine/docs/quotas#UrlFetch

Blobstore

• Service capable de servir et recevoir des fichiers importants souvent via un formulaire d’upload

• Possibilité d’écrire dynamiquement des blobs• Intégration native avec l’API de conversion

23

BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

public void doGet(HttpServletRequest req, HttpServletResponse res)    throws IOException {        BlobKey blobKey = new BlobKey(req.getParameter("blob-key")); // servir un fichier blob        blobstoreService.serve(blobKey, res);    }}

Restriction Quantité

Taille d'un Blob 32 Mo

Taille totale des blobs 5 Gb

Properties props = new Properties();        Session session = Session.getDefaultInstance(props, null);        String msgBody = "...";            Message msg = new MimeMessage(session);            msg.setFrom(new InternetAddress("admin@example.com", "Example.com Admin"));            msg.addRecipient(Message.RecipientType.TO, new InternetAddress("user@example.com", "Mr. User"));            msg.setSubject("Your Example.com account has been activated");            msg.setText(msgBody);            Transport.send(msg);

Mail API

• Envoyer des email au nom de l’administrateur• Recevoir des emails dans l’application

24

Ressource Daily Limit Maximum Rate

Mail API Calls 100 calls 32 calls/minute

Messages Sent 100 messages 8 messages/minute

Admins Emailed 5,000 mails 24 mails/minute

Message Body Data Sent 60 MB 340 KB/minute

Attachments Sent 2,000 attachments 8 attachments/minute

Attachment Data Sent 100 MB 10 MB/minute

<cronentries>  <cron>    <url>/recache</url>    <description>Repopulate the cache every 2 minutes</description>    <schedule>every 2 minutes</schedule>  </cron>  <cron>    <url>/weeklyreport</url>    <description>Mail out a weekly report</description>    <schedule>every monday 08:30</schedule>    <timezone>America/New_York</timezone>  </cron></cronentries>

Tâches planifiées (cron)

• Configurer des tâches planifiées qui s'exécutent à des heures définies ou à intervalles réguliers

• Très utile pour l’envoi des rapports, rafraichir des éléments dans le cache ..etc

25

AppStats

• Maitriser l’utilisation des Services GAE• Optimiser les requêtes internes et externes

26

Code Lab N2

Objectifs:• Initiation à l’utilisation des services clés de GAE• Savoir optimiser son code grâce à AppStats• Maitriser le temps d’exécution des requêtes (Backend performance)

• Instructions dans le fichier lab2.pdf

27

Troisième partie

GAE: Persistance des données

28

Options offertes

• App Engine DataStore• Google Cloud SQL• Google Cloud Storage• Garder vos données chez vous!

29

App Engine Datastore

• Base de données non relationnelle de type clé – valeur basée sur BigTable

• Architecture distribuée• Scalabilité et réplication automatique• Beaucoup de différences avec les RDBMS traditionnels:

– Pas de schéma– Requêtes pré-indexées– Pas de d’opération Join– Pas de fonctions d’agrégation

• Accès via:– Standards Java: JDO/JPA, Hibernate– Low-level API– Librairies tierces: Objectify, Twig,..

30

GAE Datastore: vocabulaire

• Entity: Objet contenant des données stockées dans le datastore– Deux entités du même type peuvent avoir des propriétés différentes– Une application GAE ne peut accéder qu’aux entités qu’elle a créé

• Key: Propriété qui identifie une entité dans le datastore– Une entité est identifiable par trois propriétés:

• Kind: type de l’entité (nom de la classe)• Id: identifiant de l’entité• Parent: Option pour définir l’emplacement de stockage d’une entité dans le

datastore– Une entité sans parent est dite entité root

• Entity group: Une entité, ses parents et ses fils (ancestor path) appartiennent à la même entity group

• Index: Propriété qui permet d’exécuter une requête sur le datastore• Transaction: Une opération, ou un ensemble d’opérations

atomiques -> indivisibles

31

Gestion d’accès32

Datastore 1App 1

App 2

App 3

Remote API

Accès direct

Accès direct

Version1.0.6

Version1.0

VersionTest

Autres limitations

• On ne peut pas exécuter une requête sur une propriété non indexée• Un index met du temps pour être disponible (mis à jour)• Le parent d’une entité est permanent• Les requêtes sont limitées à un seul groupe d’entité (Entity group)• Un seul filtre d’inégalité est autorisé

33

Resource Free Default Daily LimitBilling Enabled Default Limit

Stored Data 1 GB Note: Not a daily limit but a total limit.

1 GB free; no maximum

Number of Indexes 200 Note: Not a daily limit but a total limit.

200

Write Operations 50,000 Unlimited

Read Operations 50,000 Unlimited

Maximum entity size 1 Mb 1Mb

Maximum transaction size 10 Mb 10Mb

Objectify

• Bibliothèque qui vous permet de persister des objets Java en toute simplicité

• Forte abstraction des API du Datastore• Quatre opérations basiques GET, PUT, DELETE, QUERY• Annotations Java• Système de cache qui se base sur le service MemCache & sessions

34

public class Car{    @Id Long id;    @Unindexed String prop;    int color;    @Transient String doNotPersist;

    private Car() {} // mandatory no-arg constructor        public Car(String prop, int color) {        this. prop = prop;        this.color = color;    }}

Objectify en pratique35

// Vous devez enregistrer vos entités ClassObjectifyService.register(Car.class);ObjectifyService.register(Motorcycle.class);

Objectify ofy = ObjectifyService.begin();

// Simple createCar porsche = new Car("2FAST", "red");ofy.put(porsche);assert porsche.id != null;    // id was autogenerated

// Get it backCar fetched1 = ofy.get(new Key<Car>(Car.class, porsche.id));Car fetched2 = ofy.get(Car.class, porsche.id);    // equivalent, more convenientassert areEqual(porsche, fetched1, fetched2);

// Change some data and write itporsche.color = "blue";ofy.put(porsche);

// Delete itofy.delete(porsche);

Objectify: opérations en batch36

Objectify ofy = ObjectifyService.begin();

// CreateCar porsche = new Car("2FAST", "red");Car unimog = new Car("2SLOW", "green");Car tesla = new Car("2NEW", "blue");ofy.put(tesla, unimog, porsche);    //varargs; Car[] and Iterable<Car> also work

// More convenient shorthand, note the return typeMap<Long, Car> fetched = ofy.get(Car.class, new Long[] { porsche.id, unimog.id, tesla.id });

// Delete the dataofy.delete(fetched.values());

// You can delete by key without loading the objectsofy.delete(    new Key<Car>(Car.class, porsche.id),    new Key<Car>(Car.class, unimog.id),    new Key<Car>(Car.class, tesla.id));

Objectify: les requêtes37

Objectify ofy = ObjectifyService.begin();

Car car = ofy.query(Car.class).filter("prop", "123456789").get();

// The Query itself is IterableQuery<Car> q = ofy.query(Car.class).filter("prop >", "123456789").order("-prop");for (Car car: q) {    System.out.println(car.toString());}

// You can query for just keys, which will return Key objects much more efficiently than fetching whole objectsIterable<Key<Car>> allKeys = ofy.query(Car.class).fetchKeys();

// Useful for deleting itemsofy.delete(allKeys);

Objectify: Polymorphisme

• L’entité root doit porter l’annotation @Entity• Les classes polymorphes doivent porter l’annotation @Subclass• Une modification dans la hiérarchie des classes nécessite une mise

à jour des index

38

@Entitypublic class Animal {    @Id Long id;    String name;}        @Subclasspublic class Mammal extends Animal {    boolean longHair;}        @Subclasspublic class Cat extends Mammal {    boolean hypoallergenic;}

Objectify: Polymorphisme - suite39

Objectify ofy = ObjectifyService.begin();

Animal annie = new Animal();annie.name = "Annie";ofy.put(annie);

Mammal mam = new Mammal();mam.name = "Mam";m.longHair = true;ofy.put(mam);

Cat minou= new Cat(); minou.name = "Minou"; minou.longHair = true; ofy.put(minou);

// This will return the CatAnimal fetched = ofy.get(Animal.class, minou.id);

// This query will produce three objects, the Animal, Mammal, and CatQuery<Animal> all = ofy.query(Animal.class);

// This query will produce the Mammal and CatQuery<Mammal> mammals = ofy.query(Mammal.class);

Les transactions

• Une transaction peut manipuler des données de différents Entity Group

• 5 Entity Group maxi

40

Objectify ofy = ObjectifyService.beginTransaction();  // instead of begin()try{    ClubMembers cm = ofy.get(ClubMembers.class, "k123");    cm.incrementByOne();    ofy.put(cm);

    ofy.getTxn().commit();}finally{    if (ofy.getTxn().isActive())        ofy.getTxn().rollback();}

Les relations entre le objets

• Relation Parent– Les classes Person et Car appartiennent au même Entity Group– Modifier le owner créera une nouvelle entité mais ne supprimera pas l’ancienne!– La relation parent est permanente

41

public class Person {    @Id Long id;    String name;}

public class Car {    @Id Long id;    @Parent Key<Person> owner;    String color;}

Objectify ofy = ObjectifyService.begin();

Key<Person> owner = new Key<Person>(Person.class, somePersonId);Car someCar = ofy.get(new Key<Car>(owner, Car.class, someCarId));

Relation Single-Value

• Dans une relation single-value, une clé une propriété comme les autres propriétés de l’entité

- One to one - Many to One

42

public class Person {    @Id String name;    Key<Person> significantOther;}Objectify ofy = ObjectifyService.begin();Person bob = ofy.get(Person, "bob");Person bobswife = ofy.get(bob.significantOther);

public class Employee{    @Id String name;    Key<Employee> manager;}

Objectify ofy = ObjectifyService.begin();Employee bob = ofy.get(Employee.class, "bob");Employee fred = ofy.get(bob.manager);

Iterable<Employee> subordinates = ofy.query(Employee.class).filter("manager", fred);

Relation Multi-value

• Le Datastore peut aussi persister des collections et des tableaux• 5000 sous entités au maximum• Chaque get() ou put() chargera/mettra à jour les clés de toutes les

sous entités (performance)

43

public class Employee{    @Id String name;    Key<Employee>[] subordinates;}

Objectify ofy = ObjectifyService.begin();

// should contain FredIterable<Employee> managers = ofy.query(Employee.class).filter("subordinates", bob);

Statistiques sur vos données44

Accès dynamique en java: https://developers.google.com/appengine/docs/java/datastore/stats

Code Lab N3

Objectifs:

• Initiation à la persistance des données dans le Datastore de GAE grâce à la bibliothèque Objectify

• Inspecter les interactions avec le Datastore grâce au service AppStats

• Instructions dans le fichier lab3.pdf

45

Quatrième partie

Webservices Rest

46

Restlet

• Framework Java pour développer des API REST réutilisables sur d’autres plateformes (Android, GWT,…)

• Support de plusieurs représentations (XML,JSON,JAXB,…)• Fonctionnalités avancées pour le rooting et la sécurité• Négociation de contenu

47

Exemple d’une application Restlet48

Webservices Rest - Démo

49

Code Lab N4

Objectifs:• Initiation aux développement des API REST avec le framework Restlet

• Instructions dans le fichier lab4.pdf

50

Merci de votre attentionQuestions & Réponses

RHANIZAR Abdelhakim a.rhanizar@gmail.com @a_rhanizar