Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MongoDB chez illicotravel.pdf

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for mongodb mongodb
June 22, 2012
650

MongoDB chez illicotravel.pdf

Avatar for mongodb

mongodb

June 22, 2012
Tweet

Transcript

  1.  Illicotravel, c’est:  Un des plus gros comparateurs de

    voyages en France  450 000 VU/mois  30 millions de CA généré pour les partenaires  Bcp de développements internes ▪ Langage de script outillé fait maison ▪ Propre framework de composants JavaScript sur Mootools  Approx. 10 Go de données
  2.  Nous vivons dans un monde hautement abstrait et confortable

     POO  Les Objets se baladent sur le réseau en XML ou en JSON  Une grosse partie de notre travail consiste à rester dans ce monde parfait  Nous utilisons des librairies JavaScript qui nous affranchissent des soucis des navigateurs  Nous pouvons changer de serveur d’appli, nos servlets tournerons toujours  Nous nettoyons les données externes (les fichiers XML des voyagistes, les captures HTML des offres, …)
  3. public PreparedStatement createPreparedStatement(Connection con) throws SQLException { String sql =

    "INSERT INTO vacation" + " (sourceId, creationDate, advertiserName, idFromAdvertiser, vacationType, title, extraInfo, shortDescription, longDescription, continentCode, countryCode, city, dayCount, nightCount, hotelName, smallImageUrl, bigImageUrl, detailUrl)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); ps.setString(1, vacation.getSourceId()); ps.setTimestamp(2, toTimestamp(vacation.getCreationDate())); ps.setString(3, vacation.getAdvertiserName()); ps.setString(4, vacation.getIdFromAdvertiser()); ps.setString(5, vacation.getVacationType()); ps.setString(6, vacation.getTitle()); ps.setString(7, vacation.getExtraInfo()); ps.setString(8, vacation.getShortDescription()); ps.setString(9, vacation.getLongDescription()); ps.setString(10, vacation.getContinentCode()); ps.setString(11, vacation.getCountry().getCode()); ps.setString(12, vacation.getCity()); ps.setInt(13, vacation.getDayCount()); ps.setInt(14, vacation.getNightCount()); ps.setString(15, vacation.getHotelName()); ps.setString(16, vacation.getSmallImageUrl()); ps.setString(17, vacation.getBigImageUrl()); ps.setString(18, vacation.getDetailUrl()); return ps; }
  4.  Le monde SQL fourni des outils pour résoudre ces

    problèmes  ORM: Hibernate  Clustering ▪ MySQL Cluster ▪ Driver JDBC virtuel (Continuent)…  Loin du produit « évident » qu’on s'imagine pouvoir coder soi-même (avec du temps)
  5.  Ancienne architecture (simplifiée) Front (Java) Front (Java) MySQL DAO

    (PHP) Load balancer (Apache) Cherchez l’erreur JSON/HTTP
  6.  En gros, le choix était entre Cassandra et MongoDB

     Cassandra: trop bas niveau  Une HashMap distribuée  Les index sont à gérer soi-même (en tout cas à l’époque). Et surtout…
  7. <vol> prix, voyagiste, … <allers></allers> <retours></retours> </vol> <hotel> voyagiste, description,

    … <photos></photos> <prix par type de chambre> </prix par type de chambre> </hotel> <sejour> voyagiste, description, … <prix par date et ville de départ> </ prix par date et ville de départ > </sejour> Et surtout…
  8.  Expérience personnelle  tout va bien (on parlera des

    gros Map/Reduce plus loin)  nous sommes en 1.8  2 révolutions en parallèle  NOSQL  RAM (OVH: 109,99 €/mois pour Xeon i7 – 24 Go)
  9.  Verbosité en Java (petite structure)  Verbosité en Java

    (grosse structure)  Morphia et concurrence  Index  Grosses requêtes  Map/Reduce
  10. JavaScript Object literal: var index = { city: 1, date:

    1, price: 1} Custom class héritant de BasicDBObject DBObject index = new DBO("city", 1, "date", 1, "price", 1); Java Driver: DBObject index= new BasicDBObject(); index.put("city", 1); index.put("date", 1); index.put("price", 1) Java Driver + Google Guava DBObject index = new BasicDBObject(ImmutableMap.of( "city", 1, "date", 1, "price", 1));
  11. Objet Car (location de voiture) Avec DBO (custom DBObject): DBObject

    index = new DBO( "brand", car.getBrand(), "model", car.getModel(), "gear", car.getGear(), "image", car.getImageUrl(), "price", car.getPrice(), …);
  12. Solution évidente: Morphia (ODM) Quelques annotations + getMorphia().toDBObject(car) Puis…la version

    stockée commence à changer . les dates deviennent des string . des champs en plus, des champs en moins Que faire ?
  13.  On passe Morphia et on modifie le résultat ?

     On utilise notre custom DBO ? Et la lecture ? Les structures stockées sont...autre chose => On crée des classes représentant les données stockées. Eg: CarInDb
  14. Problème:  Vision simpliste: "j'ai un Objet, je le lis

    en 1 ligne, je le modifie et je le sauve en 1 ligne"  Et si...2 users le font en même temps, le 2e peut écraser les modifs du 1er Solution:  Morphia uniquement en lecture  écriture fine utilisant $inc, $set, $push, ...
  15. Problème: 1. les champs requêtés peuvent être très variables 2.

    L’ordre d’un index est important (MongoVUE anyone?), mais surtout: on ne peut pas sauter un champs
  16. Solution: date city depCity | depCountry | airline price ...

    L'idéal On fait attention MongoUtils.index(col, "date", "city", "depCity" , "price"); MongoUtils.index(col, "date", "city" , "depCountry" , "price"); MongoUtils.index(col, "date", "city", "depCity" , "airline", "price"); MongoUtils.index(col, "date", "city" , "depCountry", "airline", "price");
  17.  problème: gros scan de la collection => requête longue

     eg: prix min des séjours par pays (30 sec)  Solutions: 1. background cache (code maison pour ehcache) 2. pattern: profiter du nombre élevé de requêtes en découpant une grosse requête en pls petites => bien gérer ses Randoms
  18.  abstraction séduisante  puissance réelle  mais...  pas

    si instinctif que ça: ▪ SELECT min(price) FROM flights GROUP BY departure, arrival devient ▪ db.coll.group( { key: { departure:true, arrival:true }, reduce: function(obj,prev) { if(out.price > doc.price) { out.price = doc.price; }, });  pour un min, on n'a pas accès à l'objet associé  on se retrouve à générer du texte  perf. JS, non multi-core
  19. l'idéal serait:  comme en JavaScript forEach / map /

    filter  comme en Java 8 avec les lambdas => framework d'aggrégation  language d'expression très limité, mais pas de JavaScript