Upload
abdelhakim-rhanizar
View
2.193
Download
0
Embed Size (px)
DESCRIPTION
Développer une application sur le Cloud avec Google App Engine Formation animée par Rhanizar Abdelhakim
Citation preview
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
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!• [email protected] -> 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("[email protected]", "Example.com Admin")); msg.addRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]", "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 [email protected] @a_rhanizar