SlideShare une entreprise Scribd logo
1  sur  49
Télécharger pour lire hors ligne
Doing multi-criteria queries on a
Cassandra application
Ippon Technologies © 2015
Qui sommes-nous?
Jérôme Mainaud
○ Architecte Java chez Ippon Technologies
○ DataStax Solution Architect Certifié
Julien Dubois
○ 15 ans d’expérience en Java
○ Directeur de l’innovation chez Ippon Technologies
Ippon Technologies
○ Expertise Java & Big Data: consulting, formation, hébergement
○ 200 personnes
○ Paris, Bordeaux, Nantes, Richmond (USA)
Ippon Technologies © 2015
Sommaire
1. Intro
2. Stack technique
3. Configuration du cluster
4. Application d’exemple
5. Recherche multi-critère
6. Utilisation de CQL3 avec Java 8
7. Limitations
8. Résultats
Ippon Technologies © 2014
Stack technique
Ippon Technologies © 2015
Stack technique
● JHipster
○ Générateur d’applications Spring Boot + AngularJS
○ Supporte JPA, MongoDB et… Cassandra!
● Nous a permis de générer l’application très rapidement
○ Squelette d’application prêt en 5 minutes
○ Ajout de tables avec leur mapping
○ Configuration, build, gestion des logs, etc.
○ Tests Gatling prêts à l’emploi
Plus d’informations sur http://jhipster.github.io/
Ippon Technologies © 2015
Stack technique
● Spring Boot
○ Basé sur Spring
○ Convention over configuration
○ Nombreux “starters” prêts à l’emploi
● Services Web
○ CXF vs Spring MVC REST
● Cassandra
○ DataStax Enterprise
Ippon Technologies © 2015
Paramétrage du Driver
● Configuration Spring Boot
○ Nous avons réalisé notre propre configuration du DataStax Java
Driver
○ Intégration dans la configuration standard de Spring Boot, utilisant
un fichier YAML
● Intégrée dans Spring Boot 1.3
○ Ce code a été proposé à Pivotal, et intégré dans Spring Boot 1.3
● Améliorée par PR
○ JHipster a été amélioré depuis, et propose toujours une
configuration plus complète que celle de Spring Boot
Ippon Technologies © 2015
Développement des Repositories
● DataStax Java driver utilisé dans un Repository Spring
@Repository
public class UserRepository {
@Inject private Session session;
private PreparedStatement findOneByEmailStmt;
@PostConstruct
public void init() {
findOneByEmailStmt = session.prepare(
"SELECT id FROM user_by_email WHERE email = :email");
}
public Optional<User> findOneByEmail(String email) { … }
Ippon Technologies © 2014
Configuration du cluster
Ippon Technologies © 2015
Hardware
● Hébergement chez Ippon Hosting
● 8 noeuds équivalents
○ 16 Go de RAM
○ Deux disques durs SSD de 256 Go en RAID 0
● 6 noeuds pour le cluster Cassandra, 2 noeuds pour l’
application
Ippon Technologies © 2015
DataStax Enterprise
● Utilisation de DataStax Enterprise
● OpsCenter nous a été d’une très grande aide
○ Monitoring
○ Services automatisés
○ Gestion du cluster
Ippon Technologies © 2014
Application exemple
Système de gestion de factures
Ippon Technologies © 2015
Modèle conceptuel
Ippon Technologies © 2015
Modèle physique
Ippon Technologies © 2015
create table invoice (
invoice_id timeuuid,
user_id uuid static,
firstname text static,
lastname text static,
invoice_date timestamp static,
payment_date timestamp static,
total_amount decimal static,
delivery_address text static,
delivery_city text static,
delivery_zipcode text static,
item_id timeuuid,
item_label text,
item_price decimal,
item_qty int,
item_total decimal,
primary key (invoice_id, item_id)
);
Table
Ippon Technologies © 2014
Recherche multi-critère
Ippon Technologies © 2015
Recherche multi-critères
Critères obligatoires
○ User (implicite)
○ Date de la facture (plage de dates)
Critères supplémentaires
○ Nom du client
○ Prénom du client
○ Ville
○ Code postal
Ippon Technologies © 2015
Utiliser Solr ?
Ippon Technologies © 2015
Utiliser Solr ?
● Intégré dans DataStax Enterprise
● Mise à jour atomique et automatique
● Recherche documentaire
Ippon Technologies © 2015
Utiliser Solr ?
On cherche sur des colonnes statiques
Solr ne les gère pas
On cherche des partitions
Solr retourne des lignes
Ippon Technologies © 2015
Utiliser Solr ?
On cherche sur des colonnes statiques
Solr ne les gère pas
On cherche des partitions
Solr retourne des lignes
Ippon Technologies © 2015
Index secondaires ?
● Ne répondent qu’aux cas de recherche sur un seul champ
● Délicats à utiliser avec de bonnes performances
Ippon Technologies © 2015
Tables d’index
Utilisation de tables d’index
○ Clé de partition : Les critères primaire et un critère secondaire
■ user_id
■ date de facturation (tronqué à la date)
■ le critère secondaire
○ Clustering columns : l’identifiant de la facture
Ippon Technologies © 2015
Recherche
Q1
Q2
A D J M
A C J L M
A J M
Fusion applicative
en mémoire
Recherches en parallèle
Ippon Technologies © 2015
Recherche
Une page de résultat (id)
8f5b69ee-0ad0-11e5-a6c0-1697f925ec7b
8f5b6d4a-0ad0-11e5-a6c0-1697f925ec7b
8f5b6e9e-0ad0-11e5-a6c0-1697f925ec7b
b3db1a30-0ad0-11e5-a6c0-1697f925ec7b
b3db1c88-0ad0-11e5-a6c0-1697f925ec7b
b3db202a-0ad0-11e5-a6c0-1697f925ec7b
b3db219c-0ad0-11e5-a6c0-1697f925ec7b
cac5be94-0ad0-11e5-a6c0-1697f925ec7b
cac5c006-0ad0-11e5-a6c0-1697f925ec7b
cac5c150-0ad0-11e5-a6c0-1697f925ec7b
N recherches unitaires en parallèle
Ippon Technologies © 2015
Recherche
Recherche sur une plage de dates
○ boucle sur les jours en s’arrêtant
dès qu’on a une page
de résultat
Ippon Technologies © 2015
Recherche
Nombre de requêtes
○ Pour chaque jour dans la plage de dates
■ 1 requête par critère secondaire (partition by query)
○ 1 requête par élément trouvé (partition by query)
Complexité de la recherche
○ partitions by query
Exemple: 3 critères, 3 jours, 100 par pages
○ nombre de requêtes ≤ 3 × 3 + 100 = 109
Ippon Technologies © 2014
JAVA
Ippon Technologies © 2015
Index — instances
@Repository
public class InvoiceByLastNameRepository extends IndexRepository<String> {
public InvoiceByLastNameRepository() {
super("invoice_by_lastname", "lastname",
Invoice::getLastName, Criteria::getLastName);
}
}
@Repository
public class InvoiceByFirstNameRepository extends IndexRepository<String> {
public InvoiceByFirstNameRepository() {
super("invoice_by_firstname", "firstname",
Invoice::getFirstName, Criteria::getFirstName);
}
}
Ippon Technologies © 2015
Index — classe parente
public class IndexRepository<T> {
@Inject
private Session session;
private final String tableName;
private final String valueName;
private final Function<Invoice, T> valueGetter;
private final Function<Criteria, T> criteriumGetter;
private PreparedStatement insertStmt;
private PreparedStatement findStmt;
private PreparedStatement findWithOffsetStmt;
@PostConstruct
public void init() { /* initialise les PreparedStatements */ }
Ippon Technologies © 2015
Index — Écriture
@Override
public void insert(Invoice invoice) {
T value = valueGetter.apply(invoice);
if (value != null) {
session.execute(
insertStmt.bind(
invoice.getUserId(),
Dates.toDate(invoice.getInvoiceDay()),
value,
invoice.getId()));
}
}
Ippon Technologies © 2015
Index — Écriture
insertStmt = session.prepare(
QueryBuilder.insertInto(tableName)
.value("user_id", bindMarker())
.value("invoice_day", bindMarker())
.value(valueName, bindMarker())
.value("invoice_id", bindMarker())
);
public static Date toDate(LocalDate date) {
return date == null ? null :
Date.from(date.atStartOfDay().atZone(ZoneOffset.systemDefault()).toInstant());
}
Ippon Technologies © 2015
Index — Recherche
@Override
public CompletableFuture<Iterator<UUID>> find(Criteria criteria, LocalDate day, UUID offset) {
T criterium = criteriumGetter.apply(criteria);
if (criterium == null) {
return CompletableFuture.completedFuture(null);
}
BoundStatement stmt;
if (invoiceIdOffset == null) {
stmt = findStmt.bind(criteria.getUserId(), Dates.toDate(day), criterium);
} else {
stmt = findWithOffsetStmt.bind(criteria.getUserId(), Dates.toDate(day), criterium, offset);
}
return Jdk8.completableFuture(session.executeAsync(stmt))
.thenApply(rs -> Iterators.transform(rs.iterator(), row -> row.getUUID(0)));
}
Ippon Technologies © 2015
Index — Recherche
findWithOffsetStmt = session.prepare(
QueryBuilder.select()
.column("invoice_id")
.from(tableName)
.where(eq("user_id", bindMarker()))
.and(eq("invoice_day", bindMarker()))
.and(eq(valueName, bindMarker()))
.and(lte("invoice_id", bindMarker()))
);
Ippon Technologies © 2015
Index — Recherche (Guava to Java 8)
public static <T> CompletableFuture<T> completableFuture(ListenableFuture<T> guavaFuture) {
CompletableFuture<T> future = new CompletableFuture<>();
Futures.addCallback(guavaFuture, new FutureCallback<T>() {
@Override
public void onSuccess(V result) {
future.complete(result);
}
@Override
public void onFailure(Throwable t) {
future.completeExceptionally(t);
}
});
return future;
}
Ippon Technologies © 2014
JAVA
Service de recherche
Ippon Technologies © 2015
Service — Class
@Service
public class InvoiceSearchService {
@Inject
private InvoiceRepository invoiceRepository;
@Inject
private InvoiceByDayRepository byDayRepository;
@Inject
private InvoiceByLastNameRepository byLastNameRepository;
@Inject
private InvoiceByFirstNameRepository byLastNameRepository;
@Inject
private InvoiceByCityRepository byCityRepository;
@Inject
private InvoiceByZipCodeRepository byZipCodeRepository;
Ippon Technologies © 2015
Service — recherche
public ResultPage findByCriteria(Criteria criteria) {
return byDateInteval(criteria, (crit, day, offset) -> {
CompletableFuture<Iterator<UUID>> futureUuidIt;
if (crit.hasIndexedCriteria()) {
/*
* ... Recherche multi-critère à voir dans la prochaine diapo ...
*/
} else {
futureUuidIt = byDayRepository.find(crit.getUserId(), day, offset);
}
return futureUuidIt;
});
}
Ippon Technologies © 2015
Service — recherche
CompletableFuture<Iterator<UUID>>[] futures = Stream.<IndexRepository> of(
byLastNameRepository, byFirstNameRepository,
byCityRepository, byZipCodeRepository)
.map(repo -> repo.find(crit, day, offset))
.toArray(CompletableFuture[]::new);
futureUuidIt = CompletableFuture.allOf(futures).thenApply(v ->
Iterators.intersection(TimeUUIDComparator.desc,
Stream.of(futures)
.map(CompletableFuture::join)
.filter(Objects::nonNull)
.collect(Collectors.toList())));
Ippon Technologies © 2015
Service — Comparaison des UUIDs
/**
* Comparateur de TimeUUID équivalent à celui de Cassandra:
* @see org.apache.cassandra.db.marshal.TimeUUIDType#compare()
*/
public enum TimeUUIDComparator implements Comparator<UUID> {
desc {
@Override
public int compare(UUID o1, UUID o2) {
long delta = o2.timestamp() - o1.timestamp();
if (delta != 0)
return Ints.saturatedCast(delta);
return o2.compareTo(o1);
}
};
}
Ippon Technologies © 2015
Service — Boucle sur les jours
@FunctionalInterface
private static interface DayQuery {
CompletableFuture<Iterator<UUID>> find(Criteria criteria, LocalDate day, UUID invoiceIdOffset);
}
private ResultPage byDateInteval(Criteria criteria, DayQuery dayQuery) {
int limit = criteria.getLimit();
List<Invoice> resultList = new ArrayList<>(limit);
LocalDate dayOffset = criteria.getDayOffset();
UUID invoiceIdOffset = criteria.getInvoiceIdOffset();
/* ... Boucle sur les jours ; à voir dans la prochaine diapo ... */
return new ResultPage(resultList);
}
Ippon Technologies © 2015
Service — Boucle sur les jours
LocalDate day = criteria.getLastDay();
do {
Iterator<UUID> uuidIt = dayQuery.find(criteria, day, invoiceIdOffset).join();
limit -= loadInvoices(resultList, uuidIt, criteria, limit);
if (uuidIt.hasNext()) {
return new ResultPage(resultList, day, uuidIt.next());
}
day = day.minusDays(1);
invoiceIdOffset = null;
} while (!day.isBefore(criteria.getFirstDay()));
Ippon Technologies © 2015
Service — chargement des factures
private int loadInvoices(List<Invoice> resultList, Iterator<UUID> uuidIt,
Criteria criteria, int limit) {
List<CompletableFuture<Invoice>> futureList = new ArrayList<>(limit);
for (int i = 0; i < limit && uuidIt.hasNext(); ++i) {
futureList.add(invoiceRepository.findOne(uuidIt.next()));
}
futureList.stream()
.map(CompletableFuture::join)
.forEach(resultList::add);
return futureList.size();
}
Ippon Technologies © 2014
Limitations
Ippon Technologies © 2015
Limitations
La recherche ne fonctionne que sur un texte précis
○ Pas de recherche “plein texte”
○ Comme dans une base de données classique
La pagination ne donne pas le nombre total de pages de
résultats
Ce mécanisme ne peut fonctionner que s’il existe des critères
obligatoires fortement discriminants (ici: user_id et invoice_day)
Ippon Technologies © 2014
Résultats
Ippon Technologies © 2015
Résultats métier
● Gestion d’un an de données, sans limite
○ Nous comptons monter à 3 ans
○ Ancien système: limité à 3 mois
● Obtention des résultats en “temps réel”
○ Les données sont immédiatement disponibles
○ Ancien système: 24h de retard
● Coûts nettement plus bas
Ippon Technologies © 2015
Résultats techniques
● Les tests Gatling ont montré que nous pouvions tenir
5000 utilisateurs concurrents
○ Sur des requêtes complexes, avec multiples critères et pagination
● Nous avons aussi démontré que le cluster était scalable
linéairement
○ En termes de volumétrie: ajout de nouveaux disques (passage en
JBOD)
○ En termes de performance: ajout de nouveaux noeuds à chaud
Ippon Technologies © 2014
Merci à tous!

Contenu connexe

Tendances

Quoi de neuf pour JHipster en 2016
Quoi de neuf pour JHipster en 2016Quoi de neuf pour JHipster en 2016
Quoi de neuf pour JHipster en 2016Ippon
 
Meet up paris 13 of jun 2017
Meet up paris 13 of jun 2017Meet up paris 13 of jun 2017
Meet up paris 13 of jun 2017Jasmine Conseil
 
Au secours, mon chef m'a demandé de passer au DevOps
Au secours, mon chef m'a demandé de passer au DevOpsAu secours, mon chef m'a demandé de passer au DevOps
Au secours, mon chef m'a demandé de passer au DevOpsantony_guilloteau
 
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et ...
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et  ...Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et  ...
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et ...Jasmine Conseil
 
NightClazz Build Tools & Continuous Delivery Avancé
NightClazz Build Tools & Continuous Delivery AvancéNightClazz Build Tools & Continuous Delivery Avancé
NightClazz Build Tools & Continuous Delivery AvancéZenika
 
Présentation Rex GWT 2.0
Présentation Rex GWT 2.0Présentation Rex GWT 2.0
Présentation Rex GWT 2.0Ippon
 
Presentation du socle technique Java open source Scub Foundation
Presentation du socle technique Java open source Scub FoundationPresentation du socle technique Java open source Scub Foundation
Presentation du socle technique Java open source Scub FoundationStéphane Traumat
 
20180628 skill value_masterclass_reactnative - v1.3
20180628 skill value_masterclass_reactnative - v1.320180628 skill value_masterclass_reactnative - v1.3
20180628 skill value_masterclass_reactnative - v1.3Benoit Fillon
 
Hibernate vs le_cloud_computing
Hibernate vs le_cloud_computingHibernate vs le_cloud_computing
Hibernate vs le_cloud_computingIppon
 
[Oldies] Club client D2SI : DevOps
[Oldies] Club client D2SI : DevOps [Oldies] Club client D2SI : DevOps
[Oldies] Club client D2SI : DevOps Devoteam Revolve
 
Introduction au DevOps @SfPot 2014
Introduction au DevOps @SfPot 2014Introduction au DevOps @SfPot 2014
Introduction au DevOps @SfPot 2014Jonathan Martin
 
Devops Introduction au mouvement
Devops Introduction au mouvementDevops Introduction au mouvement
Devops Introduction au mouvementUlrich VACHON
 
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011DevOps - Retour d'expérience - MarsJug du 29 Juin 2011
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011Henri Gomez
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mareValtech
 
DevOps, quel futur pour les Ops ?
DevOps, quel futur pour les Ops ?DevOps, quel futur pour les Ops ?
DevOps, quel futur pour les Ops ?Ludovic Piot
 
Industrialisation PHP - Canal+
Industrialisation PHP - Canal+Industrialisation PHP - Canal+
Industrialisation PHP - Canal+ekino
 
Scub Foundation, usine logicielle Java libre
Scub Foundation, usine logicielle Java libreScub Foundation, usine logicielle Java libre
Scub Foundation, usine logicielle Java libreStéphane Traumat
 

Tendances (20)

Quoi de neuf pour JHipster en 2016
Quoi de neuf pour JHipster en 2016Quoi de neuf pour JHipster en 2016
Quoi de neuf pour JHipster en 2016
 
Meet up paris 13 of jun 2017
Meet up paris 13 of jun 2017Meet up paris 13 of jun 2017
Meet up paris 13 of jun 2017
 
Au secours, mon chef m'a demandé de passer au DevOps
Au secours, mon chef m'a demandé de passer au DevOpsAu secours, mon chef m'a demandé de passer au DevOps
Au secours, mon chef m'a demandé de passer au DevOps
 
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et ...
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et  ...Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et  ...
Livraison en continue avec l'outillage devops - Jenkins, Ansible, Docker et ...
 
NightClazz Build Tools & Continuous Delivery Avancé
NightClazz Build Tools & Continuous Delivery AvancéNightClazz Build Tools & Continuous Delivery Avancé
NightClazz Build Tools & Continuous Delivery Avancé
 
Présentation Rex GWT 2.0
Présentation Rex GWT 2.0Présentation Rex GWT 2.0
Présentation Rex GWT 2.0
 
Presentation du socle technique Java open source Scub Foundation
Presentation du socle technique Java open source Scub FoundationPresentation du socle technique Java open source Scub Foundation
Presentation du socle technique Java open source Scub Foundation
 
20180628 skill value_masterclass_reactnative - v1.3
20180628 skill value_masterclass_reactnative - v1.320180628 skill value_masterclass_reactnative - v1.3
20180628 skill value_masterclass_reactnative - v1.3
 
The DevOps Wonder @ PHPTour Lyon 2014
The DevOps Wonder @ PHPTour Lyon 2014The DevOps Wonder @ PHPTour Lyon 2014
The DevOps Wonder @ PHPTour Lyon 2014
 
Hibernate vs le_cloud_computing
Hibernate vs le_cloud_computingHibernate vs le_cloud_computing
Hibernate vs le_cloud_computing
 
[Oldies] Club client D2SI : DevOps
[Oldies] Club client D2SI : DevOps [Oldies] Club client D2SI : DevOps
[Oldies] Club client D2SI : DevOps
 
Introduction au DevOps @SfPot 2014
Introduction au DevOps @SfPot 2014Introduction au DevOps @SfPot 2014
Introduction au DevOps @SfPot 2014
 
Devops Introduction au mouvement
Devops Introduction au mouvementDevops Introduction au mouvement
Devops Introduction au mouvement
 
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011DevOps - Retour d'expérience - MarsJug du 29 Juin 2011
DevOps - Retour d'expérience - MarsJug du 29 Juin 2011
 
Introduction à Angular 2
Introduction à Angular 2Introduction à Angular 2
Introduction à Angular 2
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
DevOps, quel futur pour les Ops ?
DevOps, quel futur pour les Ops ?DevOps, quel futur pour les Ops ?
DevOps, quel futur pour les Ops ?
 
Usine Logicielle 2013
Usine Logicielle 2013Usine Logicielle 2013
Usine Logicielle 2013
 
Industrialisation PHP - Canal+
Industrialisation PHP - Canal+Industrialisation PHP - Canal+
Industrialisation PHP - Canal+
 
Scub Foundation, usine logicielle Java libre
Scub Foundation, usine logicielle Java libreScub Foundation, usine logicielle Java libre
Scub Foundation, usine logicielle Java libre
 

Similaire à Requêtes multi-critères avec Cassandra

Quelles stratégies de Recherche avec Cassandra ?
Quelles stratégies de Recherche avec Cassandra ?Quelles stratégies de Recherche avec Cassandra ?
Quelles stratégies de Recherche avec Cassandra ?Victor Coustenoble
 
29/06/17 Matinale Python
29/06/17 Matinale Python29/06/17 Matinale Python
29/06/17 Matinale PythonSoft Computing
 
Monitoring d'applications/environnements PHP : APM et Pinba
Monitoring d'applications/environnements PHP : APM et PinbaMonitoring d'applications/environnements PHP : APM et Pinba
Monitoring d'applications/environnements PHP : APM et PinbaIdaf_1er
 
Saas Libre
Saas LibreSaas Libre
Saas Libregrolland
 
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365 Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365 Tenedis
 
From Idea to the Cloud, a JHipster Story
From Idea to the Cloud, a JHipster StoryFrom Idea to the Cloud, a JHipster Story
From Idea to the Cloud, a JHipster StorySteve Houël
 
20171122 01 - REX : Intégration et déploiement continu chez Engie
20171122 01 - REX : Intégration et déploiement continu chez Engie20171122 01 - REX : Intégration et déploiement continu chez Engie
20171122 01 - REX : Intégration et déploiement continu chez EngieLeClubQualiteLogicielle
 
PyConFR - testons en python
PyConFR - testons en pythonPyConFR - testons en python
PyConFR - testons en pythongburet
 
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...IoT Tunisia
 
La Duck Conf - Continuous Security : Secure a DevOps World!
La Duck Conf - Continuous Security : Secure a DevOps World!La Duck Conf - Continuous Security : Secure a DevOps World!
La Duck Conf - Continuous Security : Secure a DevOps World!OCTO Technology
 
Cas d'étude - Zabbix Toulouse #1 - ZUG
Cas d'étude - Zabbix Toulouse #1 - ZUGCas d'étude - Zabbix Toulouse #1 - ZUG
Cas d'étude - Zabbix Toulouse #1 - ZUGZabbix User Group
 
GDG Rennes - Bootcamp Initiation Android - Théorie
GDG Rennes - Bootcamp Initiation Android -  ThéorieGDG Rennes - Bootcamp Initiation Android -  Théorie
GDG Rennes - Bootcamp Initiation Android - ThéorieHoracio Gonzalez
 
Présentation soutenance
Présentation soutenancePrésentation soutenance
Présentation soutenanceshurongliu
 
Ms Experiences 16 - Analyze and Improve your workflows
Ms Experiences 16 - Analyze and Improve your workflowsMs Experiences 16 - Analyze and Improve your workflows
Ms Experiences 16 - Analyze and Improve your workflowsAlexandre Joly
 
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal Thiery
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal ThieryMonitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal Thiery
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal ThieryParis Container Day
 
Cours Devops Sparks.pptx.pdf
Cours Devops Sparks.pptx.pdfCours Devops Sparks.pptx.pdf
Cours Devops Sparks.pptx.pdfboulonvert
 
Université de la performance - Devoxx France
Université de la performance - Devoxx FranceUniversité de la performance - Devoxx France
Université de la performance - Devoxx FranceMarc Bojoly
 
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex Microsoft Technet France
 
Evaluer et justifier le crédit d'impôt recherche
Evaluer et justifier le crédit d'impôt rechercheEvaluer et justifier le crédit d'impôt recherche
Evaluer et justifier le crédit d'impôt rechercheNetPME
 

Similaire à Requêtes multi-critères avec Cassandra (20)

Quelles stratégies de Recherche avec Cassandra ?
Quelles stratégies de Recherche avec Cassandra ?Quelles stratégies de Recherche avec Cassandra ?
Quelles stratégies de Recherche avec Cassandra ?
 
29/06/17 Matinale Python
29/06/17 Matinale Python29/06/17 Matinale Python
29/06/17 Matinale Python
 
Monitoring d'applications/environnements PHP : APM et Pinba
Monitoring d'applications/environnements PHP : APM et PinbaMonitoring d'applications/environnements PHP : APM et Pinba
Monitoring d'applications/environnements PHP : APM et Pinba
 
Saas Libre
Saas LibreSaas Libre
Saas Libre
 
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365 Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365
Webinar Tenedis & Riverbed : Métrologie & Diagnostic Office 365
 
From Idea to the Cloud, a JHipster Story
From Idea to the Cloud, a JHipster StoryFrom Idea to the Cloud, a JHipster Story
From Idea to the Cloud, a JHipster Story
 
20171122 01 - REX : Intégration et déploiement continu chez Engie
20171122 01 - REX : Intégration et déploiement continu chez Engie20171122 01 - REX : Intégration et déploiement continu chez Engie
20171122 01 - REX : Intégration et déploiement continu chez Engie
 
PyConFR - testons en python
PyConFR - testons en pythonPyConFR - testons en python
PyConFR - testons en python
 
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...
Iot tunisia forum 2017 le duo gagnant io t et big data un véritable levier de...
 
La Duck Conf - Continuous Security : Secure a DevOps World!
La Duck Conf - Continuous Security : Secure a DevOps World!La Duck Conf - Continuous Security : Secure a DevOps World!
La Duck Conf - Continuous Security : Secure a DevOps World!
 
Perf university
Perf universityPerf university
Perf university
 
Cas d'étude - Zabbix Toulouse #1 - ZUG
Cas d'étude - Zabbix Toulouse #1 - ZUGCas d'étude - Zabbix Toulouse #1 - ZUG
Cas d'étude - Zabbix Toulouse #1 - ZUG
 
GDG Rennes - Bootcamp Initiation Android - Théorie
GDG Rennes - Bootcamp Initiation Android -  ThéorieGDG Rennes - Bootcamp Initiation Android -  Théorie
GDG Rennes - Bootcamp Initiation Android - Théorie
 
Présentation soutenance
Présentation soutenancePrésentation soutenance
Présentation soutenance
 
Ms Experiences 16 - Analyze and Improve your workflows
Ms Experiences 16 - Analyze and Improve your workflowsMs Experiences 16 - Analyze and Improve your workflows
Ms Experiences 16 - Analyze and Improve your workflows
 
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal Thiery
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal ThieryMonitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal Thiery
Monitoring de conteneurs en production - Jonathan Raffre & Jean-Pascal Thiery
 
Cours Devops Sparks.pptx.pdf
Cours Devops Sparks.pptx.pdfCours Devops Sparks.pptx.pdf
Cours Devops Sparks.pptx.pdf
 
Université de la performance - Devoxx France
Université de la performance - Devoxx FranceUniversité de la performance - Devoxx France
Université de la performance - Devoxx France
 
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex
Automatisez, visualisez et améliorez vos processus d’entreprise avec Nintex
 
Evaluer et justifier le crédit d'impôt recherche
Evaluer et justifier le crédit d'impôt rechercheEvaluer et justifier le crédit d'impôt recherche
Evaluer et justifier le crédit d'impôt recherche
 

Plus de Julien Dubois

Accessibility in the UK
Accessibility in the UKAccessibility in the UK
Accessibility in the UKJulien Dubois
 
Java on Azure "Back to Basics" series - databases introduction
Java on Azure "Back to Basics" series - databases introductionJava on Azure "Back to Basics" series - databases introduction
Java on Azure "Back to Basics" series - databases introductionJulien Dubois
 
JHipster Code 2020 keynote
JHipster Code 2020 keynoteJHipster Code 2020 keynote
JHipster Code 2020 keynoteJulien Dubois
 
Running Spring Boot microservices in the cloud
Running Spring Boot microservices in the cloudRunning Spring Boot microservices in the cloud
Running Spring Boot microservices in the cloudJulien Dubois
 
JHipster Conf 2019 English keynote
JHipster Conf 2019 English keynoteJHipster Conf 2019 English keynote
JHipster Conf 2019 English keynoteJulien Dubois
 
JHipster Conf 2019 French keynote
JHipster Conf 2019 French keynoteJHipster Conf 2019 French keynote
JHipster Conf 2019 French keynoteJulien Dubois
 
Créer et développer une communauté Open Source
Créer et développer une communauté Open SourceCréer et développer une communauté Open Source
Créer et développer une communauté Open SourceJulien Dubois
 
JHipster Conf 2018 Quiz
JHipster Conf 2018 QuizJHipster Conf 2018 Quiz
JHipster Conf 2018 QuizJulien Dubois
 
Devoxx Belgium 2017 - easy microservices with JHipster
Devoxx Belgium 2017 - easy microservices with JHipsterDevoxx Belgium 2017 - easy microservices with JHipster
Devoxx Belgium 2017 - easy microservices with JHipsterJulien Dubois
 
JHipster overview and roadmap (August 2017)
JHipster overview and roadmap (August 2017)JHipster overview and roadmap (August 2017)
JHipster overview and roadmap (August 2017)Julien Dubois
 
Devoxx : being productive with JHipster
Devoxx : being productive with JHipsterDevoxx : being productive with JHipster
Devoxx : being productive with JHipsterJulien Dubois
 
JHipster à Devoxx 2015
JHipster à Devoxx 2015JHipster à Devoxx 2015
JHipster à Devoxx 2015Julien Dubois
 
Développer et déployer dans le cloud
Développer et déployer dans le cloudDévelopper et déployer dans le cloud
Développer et déployer dans le cloudJulien Dubois
 
JHipster for Spring Boot webinar
JHipster for Spring Boot webinarJHipster for Spring Boot webinar
JHipster for Spring Boot webinarJulien Dubois
 
Gérer son environnement de développement avec Docker
Gérer son environnement de développement avec DockerGérer son environnement de développement avec Docker
Gérer son environnement de développement avec DockerJulien Dubois
 
Performance tuning the Spring Pet Clinic sample application
Performance tuning the Spring Pet Clinic sample applicationPerformance tuning the Spring Pet Clinic sample application
Performance tuning the Spring Pet Clinic sample applicationJulien Dubois
 
HTML5, Spring, NoSQL et mobilité
HTML5, Spring, NoSQL et mobilitéHTML5, Spring, NoSQL et mobilité
HTML5, Spring, NoSQL et mobilitéJulien Dubois
 

Plus de Julien Dubois (20)

Accessibility in the UK
Accessibility in the UKAccessibility in the UK
Accessibility in the UK
 
Java on Azure "Back to Basics" series - databases introduction
Java on Azure "Back to Basics" series - databases introductionJava on Azure "Back to Basics" series - databases introduction
Java on Azure "Back to Basics" series - databases introduction
 
JHipster Code 2020 keynote
JHipster Code 2020 keynoteJHipster Code 2020 keynote
JHipster Code 2020 keynote
 
Running Spring Boot microservices in the cloud
Running Spring Boot microservices in the cloudRunning Spring Boot microservices in the cloud
Running Spring Boot microservices in the cloud
 
Spring on Azure
Spring on AzureSpring on Azure
Spring on Azure
 
JHipster Conf 2019 English keynote
JHipster Conf 2019 English keynoteJHipster Conf 2019 English keynote
JHipster Conf 2019 English keynote
 
JHipster Conf 2019 French keynote
JHipster Conf 2019 French keynoteJHipster Conf 2019 French keynote
JHipster Conf 2019 French keynote
 
Créer et développer une communauté Open Source
Créer et développer une communauté Open SourceCréer et développer une communauté Open Source
Créer et développer une communauté Open Source
 
JHipster Conf 2018 Quiz
JHipster Conf 2018 QuizJHipster Conf 2018 Quiz
JHipster Conf 2018 Quiz
 
Devoxx Belgium 2017 - easy microservices with JHipster
Devoxx Belgium 2017 - easy microservices with JHipsterDevoxx Belgium 2017 - easy microservices with JHipster
Devoxx Belgium 2017 - easy microservices with JHipster
 
JHipster overview and roadmap (August 2017)
JHipster overview and roadmap (August 2017)JHipster overview and roadmap (August 2017)
JHipster overview and roadmap (August 2017)
 
Devoxx : being productive with JHipster
Devoxx : being productive with JHipsterDevoxx : being productive with JHipster
Devoxx : being productive with JHipster
 
JHipster overview
JHipster overviewJHipster overview
JHipster overview
 
JHipster à Devoxx 2015
JHipster à Devoxx 2015JHipster à Devoxx 2015
JHipster à Devoxx 2015
 
Développer et déployer dans le cloud
Développer et déployer dans le cloudDévelopper et déployer dans le cloud
Développer et déployer dans le cloud
 
JHipster for Spring Boot webinar
JHipster for Spring Boot webinarJHipster for Spring Boot webinar
JHipster for Spring Boot webinar
 
Gérer son environnement de développement avec Docker
Gérer son environnement de développement avec DockerGérer son environnement de développement avec Docker
Gérer son environnement de développement avec Docker
 
Performance tuning the Spring Pet Clinic sample application
Performance tuning the Spring Pet Clinic sample applicationPerformance tuning the Spring Pet Clinic sample application
Performance tuning the Spring Pet Clinic sample application
 
De Devoxx au CAC40
De Devoxx au CAC40De Devoxx au CAC40
De Devoxx au CAC40
 
HTML5, Spring, NoSQL et mobilité
HTML5, Spring, NoSQL et mobilitéHTML5, Spring, NoSQL et mobilité
HTML5, Spring, NoSQL et mobilité
 

Requêtes multi-critères avec Cassandra

  • 1. Doing multi-criteria queries on a Cassandra application
  • 2. Ippon Technologies © 2015 Qui sommes-nous? Jérôme Mainaud ○ Architecte Java chez Ippon Technologies ○ DataStax Solution Architect Certifié Julien Dubois ○ 15 ans d’expérience en Java ○ Directeur de l’innovation chez Ippon Technologies Ippon Technologies ○ Expertise Java & Big Data: consulting, formation, hébergement ○ 200 personnes ○ Paris, Bordeaux, Nantes, Richmond (USA)
  • 3. Ippon Technologies © 2015 Sommaire 1. Intro 2. Stack technique 3. Configuration du cluster 4. Application d’exemple 5. Recherche multi-critère 6. Utilisation de CQL3 avec Java 8 7. Limitations 8. Résultats
  • 4. Ippon Technologies © 2014 Stack technique
  • 5. Ippon Technologies © 2015 Stack technique ● JHipster ○ Générateur d’applications Spring Boot + AngularJS ○ Supporte JPA, MongoDB et… Cassandra! ● Nous a permis de générer l’application très rapidement ○ Squelette d’application prêt en 5 minutes ○ Ajout de tables avec leur mapping ○ Configuration, build, gestion des logs, etc. ○ Tests Gatling prêts à l’emploi Plus d’informations sur http://jhipster.github.io/
  • 6. Ippon Technologies © 2015 Stack technique ● Spring Boot ○ Basé sur Spring ○ Convention over configuration ○ Nombreux “starters” prêts à l’emploi ● Services Web ○ CXF vs Spring MVC REST ● Cassandra ○ DataStax Enterprise
  • 7. Ippon Technologies © 2015 Paramétrage du Driver ● Configuration Spring Boot ○ Nous avons réalisé notre propre configuration du DataStax Java Driver ○ Intégration dans la configuration standard de Spring Boot, utilisant un fichier YAML ● Intégrée dans Spring Boot 1.3 ○ Ce code a été proposé à Pivotal, et intégré dans Spring Boot 1.3 ● Améliorée par PR ○ JHipster a été amélioré depuis, et propose toujours une configuration plus complète que celle de Spring Boot
  • 8. Ippon Technologies © 2015 Développement des Repositories ● DataStax Java driver utilisé dans un Repository Spring @Repository public class UserRepository { @Inject private Session session; private PreparedStatement findOneByEmailStmt; @PostConstruct public void init() { findOneByEmailStmt = session.prepare( "SELECT id FROM user_by_email WHERE email = :email"); } public Optional<User> findOneByEmail(String email) { … }
  • 9. Ippon Technologies © 2014 Configuration du cluster
  • 10. Ippon Technologies © 2015 Hardware ● Hébergement chez Ippon Hosting ● 8 noeuds équivalents ○ 16 Go de RAM ○ Deux disques durs SSD de 256 Go en RAID 0 ● 6 noeuds pour le cluster Cassandra, 2 noeuds pour l’ application
  • 11. Ippon Technologies © 2015 DataStax Enterprise ● Utilisation de DataStax Enterprise ● OpsCenter nous a été d’une très grande aide ○ Monitoring ○ Services automatisés ○ Gestion du cluster
  • 12. Ippon Technologies © 2014 Application exemple Système de gestion de factures
  • 13. Ippon Technologies © 2015 Modèle conceptuel
  • 14. Ippon Technologies © 2015 Modèle physique
  • 15. Ippon Technologies © 2015 create table invoice ( invoice_id timeuuid, user_id uuid static, firstname text static, lastname text static, invoice_date timestamp static, payment_date timestamp static, total_amount decimal static, delivery_address text static, delivery_city text static, delivery_zipcode text static, item_id timeuuid, item_label text, item_price decimal, item_qty int, item_total decimal, primary key (invoice_id, item_id) ); Table
  • 16. Ippon Technologies © 2014 Recherche multi-critère
  • 17. Ippon Technologies © 2015 Recherche multi-critères Critères obligatoires ○ User (implicite) ○ Date de la facture (plage de dates) Critères supplémentaires ○ Nom du client ○ Prénom du client ○ Ville ○ Code postal
  • 18. Ippon Technologies © 2015 Utiliser Solr ?
  • 19. Ippon Technologies © 2015 Utiliser Solr ? ● Intégré dans DataStax Enterprise ● Mise à jour atomique et automatique ● Recherche documentaire
  • 20. Ippon Technologies © 2015 Utiliser Solr ? On cherche sur des colonnes statiques Solr ne les gère pas On cherche des partitions Solr retourne des lignes
  • 21. Ippon Technologies © 2015 Utiliser Solr ? On cherche sur des colonnes statiques Solr ne les gère pas On cherche des partitions Solr retourne des lignes
  • 22. Ippon Technologies © 2015 Index secondaires ? ● Ne répondent qu’aux cas de recherche sur un seul champ ● Délicats à utiliser avec de bonnes performances
  • 23. Ippon Technologies © 2015 Tables d’index Utilisation de tables d’index ○ Clé de partition : Les critères primaire et un critère secondaire ■ user_id ■ date de facturation (tronqué à la date) ■ le critère secondaire ○ Clustering columns : l’identifiant de la facture
  • 24. Ippon Technologies © 2015 Recherche Q1 Q2 A D J M A C J L M A J M Fusion applicative en mémoire Recherches en parallèle
  • 25. Ippon Technologies © 2015 Recherche Une page de résultat (id) 8f5b69ee-0ad0-11e5-a6c0-1697f925ec7b 8f5b6d4a-0ad0-11e5-a6c0-1697f925ec7b 8f5b6e9e-0ad0-11e5-a6c0-1697f925ec7b b3db1a30-0ad0-11e5-a6c0-1697f925ec7b b3db1c88-0ad0-11e5-a6c0-1697f925ec7b b3db202a-0ad0-11e5-a6c0-1697f925ec7b b3db219c-0ad0-11e5-a6c0-1697f925ec7b cac5be94-0ad0-11e5-a6c0-1697f925ec7b cac5c006-0ad0-11e5-a6c0-1697f925ec7b cac5c150-0ad0-11e5-a6c0-1697f925ec7b N recherches unitaires en parallèle
  • 26. Ippon Technologies © 2015 Recherche Recherche sur une plage de dates ○ boucle sur les jours en s’arrêtant dès qu’on a une page de résultat
  • 27. Ippon Technologies © 2015 Recherche Nombre de requêtes ○ Pour chaque jour dans la plage de dates ■ 1 requête par critère secondaire (partition by query) ○ 1 requête par élément trouvé (partition by query) Complexité de la recherche ○ partitions by query Exemple: 3 critères, 3 jours, 100 par pages ○ nombre de requêtes ≤ 3 × 3 + 100 = 109
  • 29. Ippon Technologies © 2015 Index — instances @Repository public class InvoiceByLastNameRepository extends IndexRepository<String> { public InvoiceByLastNameRepository() { super("invoice_by_lastname", "lastname", Invoice::getLastName, Criteria::getLastName); } } @Repository public class InvoiceByFirstNameRepository extends IndexRepository<String> { public InvoiceByFirstNameRepository() { super("invoice_by_firstname", "firstname", Invoice::getFirstName, Criteria::getFirstName); } }
  • 30. Ippon Technologies © 2015 Index — classe parente public class IndexRepository<T> { @Inject private Session session; private final String tableName; private final String valueName; private final Function<Invoice, T> valueGetter; private final Function<Criteria, T> criteriumGetter; private PreparedStatement insertStmt; private PreparedStatement findStmt; private PreparedStatement findWithOffsetStmt; @PostConstruct public void init() { /* initialise les PreparedStatements */ }
  • 31. Ippon Technologies © 2015 Index — Écriture @Override public void insert(Invoice invoice) { T value = valueGetter.apply(invoice); if (value != null) { session.execute( insertStmt.bind( invoice.getUserId(), Dates.toDate(invoice.getInvoiceDay()), value, invoice.getId())); } }
  • 32. Ippon Technologies © 2015 Index — Écriture insertStmt = session.prepare( QueryBuilder.insertInto(tableName) .value("user_id", bindMarker()) .value("invoice_day", bindMarker()) .value(valueName, bindMarker()) .value("invoice_id", bindMarker()) ); public static Date toDate(LocalDate date) { return date == null ? null : Date.from(date.atStartOfDay().atZone(ZoneOffset.systemDefault()).toInstant()); }
  • 33. Ippon Technologies © 2015 Index — Recherche @Override public CompletableFuture<Iterator<UUID>> find(Criteria criteria, LocalDate day, UUID offset) { T criterium = criteriumGetter.apply(criteria); if (criterium == null) { return CompletableFuture.completedFuture(null); } BoundStatement stmt; if (invoiceIdOffset == null) { stmt = findStmt.bind(criteria.getUserId(), Dates.toDate(day), criterium); } else { stmt = findWithOffsetStmt.bind(criteria.getUserId(), Dates.toDate(day), criterium, offset); } return Jdk8.completableFuture(session.executeAsync(stmt)) .thenApply(rs -> Iterators.transform(rs.iterator(), row -> row.getUUID(0))); }
  • 34. Ippon Technologies © 2015 Index — Recherche findWithOffsetStmt = session.prepare( QueryBuilder.select() .column("invoice_id") .from(tableName) .where(eq("user_id", bindMarker())) .and(eq("invoice_day", bindMarker())) .and(eq(valueName, bindMarker())) .and(lte("invoice_id", bindMarker())) );
  • 35. Ippon Technologies © 2015 Index — Recherche (Guava to Java 8) public static <T> CompletableFuture<T> completableFuture(ListenableFuture<T> guavaFuture) { CompletableFuture<T> future = new CompletableFuture<>(); Futures.addCallback(guavaFuture, new FutureCallback<T>() { @Override public void onSuccess(V result) { future.complete(result); } @Override public void onFailure(Throwable t) { future.completeExceptionally(t); } }); return future; }
  • 36. Ippon Technologies © 2014 JAVA Service de recherche
  • 37. Ippon Technologies © 2015 Service — Class @Service public class InvoiceSearchService { @Inject private InvoiceRepository invoiceRepository; @Inject private InvoiceByDayRepository byDayRepository; @Inject private InvoiceByLastNameRepository byLastNameRepository; @Inject private InvoiceByFirstNameRepository byLastNameRepository; @Inject private InvoiceByCityRepository byCityRepository; @Inject private InvoiceByZipCodeRepository byZipCodeRepository;
  • 38. Ippon Technologies © 2015 Service — recherche public ResultPage findByCriteria(Criteria criteria) { return byDateInteval(criteria, (crit, day, offset) -> { CompletableFuture<Iterator<UUID>> futureUuidIt; if (crit.hasIndexedCriteria()) { /* * ... Recherche multi-critère à voir dans la prochaine diapo ... */ } else { futureUuidIt = byDayRepository.find(crit.getUserId(), day, offset); } return futureUuidIt; }); }
  • 39. Ippon Technologies © 2015 Service — recherche CompletableFuture<Iterator<UUID>>[] futures = Stream.<IndexRepository> of( byLastNameRepository, byFirstNameRepository, byCityRepository, byZipCodeRepository) .map(repo -> repo.find(crit, day, offset)) .toArray(CompletableFuture[]::new); futureUuidIt = CompletableFuture.allOf(futures).thenApply(v -> Iterators.intersection(TimeUUIDComparator.desc, Stream.of(futures) .map(CompletableFuture::join) .filter(Objects::nonNull) .collect(Collectors.toList())));
  • 40. Ippon Technologies © 2015 Service — Comparaison des UUIDs /** * Comparateur de TimeUUID équivalent à celui de Cassandra: * @see org.apache.cassandra.db.marshal.TimeUUIDType#compare() */ public enum TimeUUIDComparator implements Comparator<UUID> { desc { @Override public int compare(UUID o1, UUID o2) { long delta = o2.timestamp() - o1.timestamp(); if (delta != 0) return Ints.saturatedCast(delta); return o2.compareTo(o1); } }; }
  • 41. Ippon Technologies © 2015 Service — Boucle sur les jours @FunctionalInterface private static interface DayQuery { CompletableFuture<Iterator<UUID>> find(Criteria criteria, LocalDate day, UUID invoiceIdOffset); } private ResultPage byDateInteval(Criteria criteria, DayQuery dayQuery) { int limit = criteria.getLimit(); List<Invoice> resultList = new ArrayList<>(limit); LocalDate dayOffset = criteria.getDayOffset(); UUID invoiceIdOffset = criteria.getInvoiceIdOffset(); /* ... Boucle sur les jours ; à voir dans la prochaine diapo ... */ return new ResultPage(resultList); }
  • 42. Ippon Technologies © 2015 Service — Boucle sur les jours LocalDate day = criteria.getLastDay(); do { Iterator<UUID> uuidIt = dayQuery.find(criteria, day, invoiceIdOffset).join(); limit -= loadInvoices(resultList, uuidIt, criteria, limit); if (uuidIt.hasNext()) { return new ResultPage(resultList, day, uuidIt.next()); } day = day.minusDays(1); invoiceIdOffset = null; } while (!day.isBefore(criteria.getFirstDay()));
  • 43. Ippon Technologies © 2015 Service — chargement des factures private int loadInvoices(List<Invoice> resultList, Iterator<UUID> uuidIt, Criteria criteria, int limit) { List<CompletableFuture<Invoice>> futureList = new ArrayList<>(limit); for (int i = 0; i < limit && uuidIt.hasNext(); ++i) { futureList.add(invoiceRepository.findOne(uuidIt.next())); } futureList.stream() .map(CompletableFuture::join) .forEach(resultList::add); return futureList.size(); }
  • 44. Ippon Technologies © 2014 Limitations
  • 45. Ippon Technologies © 2015 Limitations La recherche ne fonctionne que sur un texte précis ○ Pas de recherche “plein texte” ○ Comme dans une base de données classique La pagination ne donne pas le nombre total de pages de résultats Ce mécanisme ne peut fonctionner que s’il existe des critères obligatoires fortement discriminants (ici: user_id et invoice_day)
  • 46. Ippon Technologies © 2014 Résultats
  • 47. Ippon Technologies © 2015 Résultats métier ● Gestion d’un an de données, sans limite ○ Nous comptons monter à 3 ans ○ Ancien système: limité à 3 mois ● Obtention des résultats en “temps réel” ○ Les données sont immédiatement disponibles ○ Ancien système: 24h de retard ● Coûts nettement plus bas
  • 48. Ippon Technologies © 2015 Résultats techniques ● Les tests Gatling ont montré que nous pouvions tenir 5000 utilisateurs concurrents ○ Sur des requêtes complexes, avec multiples critères et pagination ● Nous avons aussi démontré que le cluster était scalable linéairement ○ En termes de volumétrie: ajout de nouveaux disques (passage en JBOD) ○ En termes de performance: ajout de nouveaux noeuds à chaud
  • 49. Ippon Technologies © 2014 Merci à tous!