24. @doanduyhai#C*ModelisationAvancee
Slice query avec « composite »
Requêtes
relevé par ville, date et type
#p = Paris, #comp1 = date1, #comp2 = temperature
relevés par ville et date
#p = Paris, #comp1 = date1
relevés par ville et tranche de dates
#p = Paris, #comp1 ≥ date1 & #comp1 ≤ date2
24
28. @doanduyhai#C*ModelisationAvancee
Mémoire
Off-Heap
Disque
Column Family User
Row Cache
Mémoire
JVM Heap
Partition Key Cache
Commit log1
…
Key Index Sample
Compression
offset
Bloom Filter
SStable 3
Système de fichiers
SStable 2SStable 1
Commit log 2
Commit logn
Key Index Sample
Compression
offset
Bloom Filter
Key Index Sample
Compression
offset
Bloom Filter
28
29. @doanduyhai#C*ModelisationAvancee
Système de fichiers
Format
<keyspace>-<column family>-<version>-<génération>-<composant>.db
SSTables
test-user-ic-1-Data.db → snapshot d’une SSTable à un instant t
Méta-données
test-user-ic-1-CompressionInfo.db → offset des données compressées
test-user-ic-1-CRC.db → CRC des données non compressées
29
30. @doanduyhai#C*ModelisationAvancee
Système de fichiers
Format
<keyspace>-<column family>-<version>-<génération>-<composant>.db
Méta-données
test-user-ic-1-Filter.db → filtre de Bloom
test-user-ic-1-Index.db → index des offset de #partition dans le SSTable
test-user-ic-1-Statistics.db → statistiques
test-user-ic-1-Summary.db → échantillon des offsets de #partition
test-user-ic-1-TOC.txt
30
31. @doanduyhai#C*ModelisationAvancee
Format des fichiers
#p (user001)
Longueur ligne
Index de colonne *
Tombstone
Nb de colonnes
Colonne1/Cellule1
….
ColonneN/CelluleN
#p (user350)
Longueur ligne
Index de colonne *
Tombstone
Nb de colonnes
Colonne1/Cellule1
….
ColonneN/CelluleN
#Partition Offset … Index de colonne *
user001 0x0 …
premier: xxx
dernier: yyy
offset: 0x3
…
user002 0x153 …
premier: xxx
dernier: yyy
offset: 0x156
…
user350 0x5464321 …
premier: xxx
dernier: yyy
offset: 0x5464310
…
*-Index.db
*-Data.db
31
SStable
Partition Key Cache
32. @doanduyhai#C*ModelisationAvancee
Format des fichiers
Echantillon Offset
user001 0x0
user128 0x4500
user256 0x851513
user350 0x5464321
*-Summary.db
#p (user001)
Longueur ligne
Index de colonne *
Tombstone
Nb de colonnes
Colonne1/Cellule1
….
ColonneN/CelluleN
#p (user350)
Longueur ligne
Index de colonne *
Tombstone
Nb de colonnes
Colonne1/Cellule1
….
ColonneN/CelluleN
32
*-Data.dbSStable
Key Index Sample
78. @doanduyhai#C*ModelisationAvancee
La clause « WHERE »
S’applique aux clés des SortedMap (unicité)
Autorise des recherches par plage (tri)
Ordre des clés très important!!!!
SELECT * FROM qualite_reseau WHERE operateur = ‘ORANGE’ AND ville =
‘Paris’ AND date ≥ 2014041619 AND date ≤ 2014041621
SELECT * FROM qualite_reseau WHERE operateur = ‘ORANGE’ AND date ≥
2014041619 AND date ≤ 2014041621
78
79. @doanduyhai#C*ModelisationAvancee
Les méta-données de CQL3
Noms des colonnes « clustered » dans les tables ?
key_aliases | key_validator | column_aliases | comparator
--------------------+----------------------+--------------------------+-------------------------------------------------------------------------------
["operateur"] | UTF8Type | ["ville","date"] | CompositeType(UTF8Type,Int32Type,UTF8Type)
SELECT key_aliases,key_validator,column_aliases,comparator
FROM system.schema_columnfamilies
WHERE keyspace_name=‘xxx'
AND columnfamily_name=‘qualite_reseau’
79
82. @doanduyhai#C*ModelisationAvancee
Détails d’implémentation
Pourquoi ne pas tout stocker dans les #colonnes ?
limite des 64K pour les #colonnes
colonnes counter, type spécial
RowKey: SFR
=> (column=Lyon:2013110512:qualite, value=0.88)
RowKey: SFR
=> (column=Lyon:2013110512:qualite:0.88, value=)
82
83. @doanduyhai#C*ModelisationAvancee
Détails d’implémentation
Pourquoi ne pas tout stocker dans les #colonnes ?
limite des 64K pour les #colonnes
colonnes counter, type spécial → counter colonne d’agrégation
RowKey: SFR
=> (column=Lyon:2013110512:qualite, value=0.88)
RowKey: SFR
=> (column=Lyon:2013110512:qualite:0.88, value=)
83
113. @doanduyhai#C*ModelisationAvancee
Approche CQRS*
Gérer la mutabilité
CREATE TABLE amis (
user_id uuid,
ami_id uuid,
ami_nom text,
ami_bio text,
…
PRIMARY KEY(user_id, ami_id)) ;
Process M.A.J de
la bio des users
113
* Command Query Responsability Segregation
114. @doanduyhai#C*ModelisationAvancee
Les pièges de la dé-normalisation
Ne pas assez dé-normaliser
problème du N+1 select/read-before-write
100 commentaires → 101 selects
CREATE TABLE commentaires (
article_id uuid, date_creation timestamp,
auteur_id uuid,
contenu text,
PRIMARY KEY(article_id, date_creation));
114
115. @doanduyhai#C*ModelisationAvancee
Les pièges de la dé-normalisation
Compromis fonctionnels !
pagination par 10 commentaires
max 11 selects
CREATE TABLE commentaires (
article_id uuid, date_creation timestamp,
auteur_id uuid,
contenu text,
PRIMARY KEY(article_id, date_creation));
115
116. @doanduyhai#C*ModelisationAvancee
Les pièges de la dé-normalisation
Trop dé-normaliser
intégrité des données
mises à jour complexes
batchs de correction de données …. cauchemardesques
116
118. @doanduyhai#C*ModelisationAvancee
Les pièges de la dé-normalisation
Given 2 users Foo and Bar
When Foo adds Bar as friend
Then Foo friends list should display Bar’s details
Given 2 users Foo and Bar
When Foo adds Bar as friend
And Bar changes his bio
Then Foo should see new Bar’s bio in his friends list
Given 2 users Foo and Bar
When Foo adds Bar as friend
And Bar deletes his account
Then Foo should not see Bar in his friend list
118
133. @doanduyhai#C*ModelisationAvancee 133
Sur clé de partition « composite »
CREATE TABLE xxx (
partition1 uuid, partition2 text, …. PRIMARY KEY((partition1, partition2));
SELECT * FROM xxx WHERE partition1 = #p1 AND partition2 IN (#p21, #p22, …)
La clause « IN »
SELECT * FROM xxx WHERE partition1 IN (#p11, #p12, …) AND partition2 = #p2
134. @doanduyhai#C*ModelisationAvancee 134
Sur clé d’agrégation
CREATE TABLE xxx (partition uuid, clustering1 uuid, clustering2 uuid,
clustering3 uuid …., PRIMARY KEY(partition, clustering1, clustering2, clustering3));
La clause « IN »
SELECT … WHERE clustering1 = #c1 AND clustering2 IN (#c21, #c22, …)
SELECT … WHERE clustering1 = #c1 AND clustering2 = #c2 AND clustering3 IN (#c31, #c32, …)
SELECT … WHERE clustering1 = #c1 AND clustering2 IN (#c21, #c22, …) AND clustering3 = #c3
136. @doanduyhai#C*ModelisationAvancee 136
Comment ça marche ? → multiget !
Combinaison linéaire
(#p1, #p21) && (#p1, #p22)
La clause « IN »
SELECT * FROM xxx WHERE partition1 = #p1 AND partition2 IN (#p21, #p22, …)
137. @doanduyhai#C*ModelisationAvancee
Wide rows et « bucketing »
Lignes trop larges
limite physique 2.109
hot-spots si nb #partition « nb #col
réparation coûteuse → 1colonne diffère, toute la ligne réparée
137
140. @doanduyhai#C*ModelisationAvancee
Wide rows et « bucketing »
Requêtes inter-partition
toutes les métriques CPU entre 25 Janvier et 10 Février ?
CREATE TABLE metrics_mois (
type text, mois int,
date timestamp,
valeur double,
PRIMARY KEY ((type, mois), date)) ;
140
141. @doanduyhai#C*ModelisationAvancee
Wide rows et « bucketing »
Requêtes inter-partition
toutes les métriques CPU entre 25 Janvier et 10 Février ?
CREATE TABLE metrics_mois (
type text, mois int,
date timestamp,
valeur double,
PRIMARY KEY ((type, mois), date)) ;
SELECT * FROM metrics_mois
WHERE type = ‘CPU’
AND mois IN (201401, 201402)
AND date>=‘2014-01-25 00:00:00+0100’
AND date<=‘2014-02-10 00:00:00+0100’;
141
142. @doanduyhai#C*ModelisationAvancee
Wide rows et « bucketing »
Implémentation par multiget
SELECT * FROM metrics_mois
WHERE type = ‘CPU’
AND mois = 201401
AND date>=‘2014-01-25 00:00:00+0100’
AND date<=‘2014-02-10 00:00:00+0100’
&&
SELECT * FROM metrics_mois
WHERE type = ‘CPU’
AND mois = 201402
AND date>=‘2014-01-25 00:00:00+0100’
AND date<=‘2014-02-10 00:00:00+0100’
142
190. @doanduyhai#C*ModelisationAvancee
Détection de présence/d’absence
Nouvelle modélisation
Nouveau chemin de lecture
Bloom filter en mémoire
partition key cache en mémoire
accès disque SSTable en cas de faux positif
CREATE TABLE user_token (
user_id int,
token uuid,
PRIMARY KEY((user_id, token))) ;
190
193. @doanduyhai#C*ModelisationAvancee
Row cache
Use-cases
données référentielles
taille raisonnable
partitions accédées très fréquemment
Important
monitoring nécessaire du hit rate & de la taille des données !!!
coût de la sérialisation/dé-sérialisation (off-heap)
193
203. @doanduyhai#C*ModelisationAvancee
Use-cases recommandés
Bon candidats
peu de valeurs indexées # (mais assez quand même)
Mauvais candidats
très peu de valeurs indexées # (index d’un booléen )
beaucoup de valeurs indexées # (index sur email )
m.a.j./suppression fréquentes
très gros cluster
203
209. @doanduyhai#C*ModelisationAvancee
Requêtes inter-clustering (2.0.6)
Données
CREATE TABLE notes_film (
film_id uuid, note uuid, user_id int, commentaire text,
PRIMARY KEY(film_id, note, user_id));
Note User_id Commentaire
1 10 Bla bla bla
… … …
1 49 Bla bla bla
1 82 Bla bla bla
2 13 Bla bla bla
2 54 Bla bla bla
3 15 Bla bla bla
11 notes de valeur 1
209
210. @doanduyhai#C*ModelisationAvancee
Requêtes inter-clustering (2.0.6)
Pagination par 10
user_id 10 à 49
SELECT * FROM notes_film WHERE film_id=.. AND note=1 LIMIT 10
210
Note User_id Commentaire
1 10 Bla bla bla
… … …
1 49 Bla bla bla
1 82 Bla bla bla
2 13 Bla bla bla
2 54 Bla bla bla
3 15 Bla bla bla
11 notes de valeur 1
211. @doanduyhai#C*ModelisationAvancee
Requêtes inter-clustering (2.0.6)
Deuxième page
user_id 82
SELECT * FROM notes_film WHERE film_id=.. AND note=1 AND user_id>49 LIMIT 10
211
Note User_id Commentaire
1 10 Bla bla bla
… … …
1 49 Bla bla bla
1 82 Bla bla bla
2 13 Bla bla bla
2 54 Bla bla bla
3 15 Bla bla bla
11 notes de valeur 1
212. @doanduyhai#C*ModelisationAvancee
Requêtes inter-clustering (2.0.6)
Solution naïve (à la SQL)
SELECT * FROM notes_film WHERE film_id=.. AND note≥1 AND user_id>49 LIMIT 10
212
Note User_id Commentaire
1 10 Bla bla bla
… … …
1 49 Bla bla bla
1 82 Bla bla bla
2 13 Bla bla bla
2 54 Bla bla bla
3 15 Bla bla bla
220. @doanduyhai#C*ModelisationAvancee
User defined type (2.1)
CREATE TABLE commentaires (
article_id int,
date_creation timestamp,
auteur user,
contenu text,
PRIMARY KEY (article_id, date_creation));
CREATE TYPE user (
id int,
nom text,
adresse text,
bio text);
220
221. @doanduyhai#C*ModelisationAvancee
User defined type (2.1)
Syntaxe
INSERT INTO commentaires(article_id,date_creation,auteur,contenu)
VALUES( 10,
2014-04-16 10:00:00+0100,
{
id: 156,
nom: ‘Pierre DUPOND’,
adresse: ‘12 rue de la Paix 75016 PARIS’,
bio: ‘Je suis un habitant du 16ème…’
},
‘Cet article a trop de fautes d’orthographe…’);
221
222. @doanduyhai#C*ModelisationAvancee
User defined type (2.1)
Imbrication arbitraire
CREATE TYPE user (
id int,
nom text,
adresse location,
bio text);
CREATE TYPE location (
numero int,
voie text,
code_postal int,
ville text);
222
225. @doanduyhai#C*ModelisationAvancee
User defined type (2.1)
Colonnes d’agrégation (clustering)
tri → ordre du type des champs déclarés
Collections & Maps
unicité → comparaison des champs déclarés dans l’ordre
225