226
@doanduyhai #C*ModelisationAvancee Cassandra Techniques de modélisation avancée

Cassandra techniques de modelisation avancee

Embed Size (px)

DESCRIPTION

DevoxxFR2014 Université sur les techniques de modélisation avancée dans Cassandra

Citation preview

Page 1: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Cassandra

Techniques de modélisation avancée

Page 2: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

DuyHai DOAN

Le jour: + + conseil

Le soir: Cassandra + Achilles

@doanduyhai [email protected] doanduyhai

Développeur Freelance Java/Cassandra

Page 3: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Agenda Modèle de données Architecture technique CQL3 en détail Techniques de modélisation de base

3

Page 4: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Agenda

Techniques de modélisation avancée Modélisations exotiques Les anti-patterns Les index secondaires <Futur> C* 4

Page 5: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

MODÈLE DE DONNÉES

Concepts Accès aux données

Le type « composite »

Page 6: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Table/Column Family Stockage physique

ligne physique = partition

clé de partition (#partition)

clé de colonne (#colonne)

cellule

#partition1 #col1 #col2 #col3 #col4

cellule1 cellule2 cellule3 cellule4

#partition2 #col1 #col2 #col3

cellule1 cellule2 cellule3

#partition3 #col1 #col2

cellule1 cellule2

#partition4 #col1 #col2 #col3 #col4 …

cellule1 cellule2 cellule3 cellule4 …

6

Page 7: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Keyspace Ensemble de column family (table)

Keyspace system metadata sur les keyspaces et tables

Keyspace system_auth authentification & contrôle d’accès

Cassandra Keyspace Table 1 n 1 n

7

Page 8: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Distribution Aléatoire: hash de #partition → token = hash(#p) Hash: [0, 2127-1] Chaque nœud: 1/8

8

n1

n2

n3

n4

n5

n6

n7

n8

Page 9: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Table ≈ Map<#p,SortedMap<#col,cellule>>

Vue logique

SortedMap<tokenp,…>

9

Page 10: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Table ≈ Map<#p,SortedMap<#col,cellule>>

SortedMap<#col,cellule>>

Vue logique

Unicité

Tri

SortedMap<tokenp,…>

10

Page 11: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Vue logique Map<#p,SortedMap<#col,cellule>> → cellule par (#partition + #colonne) très rapide

#partition1 #col1 #col2 #col3 #col4 …

cellule1 cellule2 cellule3 cellule4 …

11

Page 12: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Vue logique Map<#p,SortedMap<#col,cellule>> → plage de #colonnes (triées) par #partition très rapide

#partition1 #col1 #col2 #col3 #col4 …

cellule1 cellule2 cellule3 cellule4 …

12

Page 13: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Vue logique Map<#p,SortedMap<#col,cellule>> → plage de partitions par #partition très lent

13

Page 14: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Vue logique Map<#p,SortedMap<#col,cellule>> Cellules vides Données possible dans #colonne

limite: 64K

#partition1 #col1 #col2 #col3 #col4

Ø Ø Ø Ø

14

Page 15: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Types Supportés

int, long, string, float, double, byte (blob) uuid, time uuid timestamp counter

#partition, #colonne & cellule Tri sur #colonne: ordre naturel du type

15

Page 16: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « stockage_physique »

Page 17: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Insertion

Chargement simple

Slice query

Accès aux données

17

INSERT INTO xxx(partition,colonne,cellule) VALUES(#p,#col,valeur)

SELECT cellule FROM xxx WHERE partition = #p AND colonne = #col

SELECT * FROM xxx WHERE partition = #p AND colonne ≥ #c1 AND colonne ≤ #c2 LIMIT n

Page 18: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Slice query

#partition = superhéros catwoman ≤ #col ≤ superman décroissant n = 3

Accès aux données

superhéros batman catwoman flash green lantern superman

Ø Ø Ø Ø Ø

3

18

Page 19: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Multiget slice query

slice query pour un ensemble de {#p1, #p2,…} donné équivalent à

→ #p1, entre: c1et c2 && → #p2, entre: c1et c2 && …

avantage / inconvénient

Accès aux données

19

Page 20: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

#Colonne en multiple composants

type1:type2:type3 tri successif par composant

Type « composite »

20

Page 21: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

#Colonne en multiple composants

type1:type2:type3 tri successif par composant

Map<#partition, SortedMap<#comp1,< SortedMap<#comp2,< … SortedMap<#compn,Cellule>…>

Type « composite »

21

Page 22: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Exemple: table hygrometrie #partition → ville #colonne → LongType:UTF8Type

LongType: date de mesure en Unix time UTF8Type: type de mesure

celulle → DoubleType

Map<ville,SortedMap<dateUnix,SortedMap<type,valeur>>>

Type « composite »

22

Page 23: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « hygrometrie »

Page 24: Cassandra techniques de modelisation avancee

@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

Page 25: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Slice query avec « composite » Requêtes

relevé par ville et type #p = Paris, #comp2 = temperature

Map<ville,SortedMap<date,SortedMap<type,valeur>>>

25

Page 26: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 27: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

ARCHITECTURE TECHNIQUE

Système de fichiers Chemin de lecture/écriture

Compaction

Page 28: Cassandra techniques de modelisation avancee

@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 2 SStable 1 Commit log 2

Commit logn

Key Index Sample

Compression offset

Bloom Filter

Key Index Sample

Compression offset

Bloom Filter

28

Page 29: Cassandra techniques de modelisation avancee

@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

Page 30: Cassandra techniques de modelisation avancee

@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

Page 31: Cassandra techniques de modelisation avancee

@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

Page 32: Cassandra techniques de modelisation avancee

@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.db SStable

Key Index Sample

Page 33: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Format des fichiers

1 0 0 1 0 0 1 0 0 0

« foo »

h1 h2 h3

33

*-Filter.db Bloom Filter

Page 34: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Format des fichiers

1 0 0 1* 0 0 1 0 1 1

« foo » « bar »

h1 h2 h3

34

*-Filter.db Bloom Filter

Page 35: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Format des fichiers

1 0 0 1* 0 0 1 0 1 1

h1 h2 h3

« qux » ?

« foo » « bar »

35

*-Filter.db Bloom Filter

Page 36: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture Mémoire

Disque2

Commit log1

Disque 1

. . .

1

Commit log2

Commit logn

36

Page 37: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture Mémoire

Disque2

Commit log1

Disque 1

. . .

MemTable Column Family 1

. . .

1

2

Commit log2

Commit logn

MemTable Column Family 2

MemTable Column Family n

37

Page 38: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture

Column Family1

Mémoire

Disque2

Commit log1

SStable 1

Disque 1

. . .

Column Family2

SStable 1

Column Family3

SStable 1

1

3 Commit log2

Commit logn

38

Page 39: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture

Column Family1

Mémoire

Disque2

Commit log1

SStable 1

Disque 1

. . .

Column Family2

SStable 1

Column Family3

SStable 1

1

3 Commit log2

Commit logn

39

MemTable Column Family 1

. . . 2 MemTable

Column Family 2

MemTable Column Family n

Page 40: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture

Column Family1

Mémoire

Disque2

Commit log1

SStable 1

Disque 1

. . . SStable 2

Column Family2

SStable 1

SStable 2

Column Family3

SStable 1

1

3 Commit log2

Commit logn

40

Page 41: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture

Column Family1

Mémoire

Disque2

Commit log1

SStable 1

Disque 1

. . . SStable 2

SStable 3

Column Family2

SStable 1

SStable 2

SStable 3

SStable 4 SStable 5

Column Family3

SStable 1

1

3

Immutables

Commit log2

Commit logn

41

Page 42: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

1

42

SELECT * FROM users WHERE partition =…

Page 43: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter 1 2

43

SELECT * FROM users WHERE partition =…

Page 44: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

1 2

3

44

SELECT * FROM users WHERE partition =…

Page 45: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

Key Index Sample 4

1 2

3

45

SELECT * FROM users WHERE partition =…

Page 46: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

Compression offset

Key Index Sample 4

5

1 2

3

46

SELECT * FROM users WHERE partition =…

Page 47: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

SStable 1

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

Compression offset

Key Index Sample 4

5

1

Column Family User

2

6

3

47

SELECT * FROM users WHERE partition =…

Page 48: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

Compression offset

Key Index Sample 4

5

Memtable

1 2

7

3

SStable 1

Column Family User

6

48

SELECT * FROM users WHERE partition =…

Page 49: Cassandra techniques de modelisation avancee

@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 2 SStable 1 Commit log 2

Commit logn

Key Index Sample

Compression offset

Bloom Filter

Key Index Sample

Compression offset

Bloom Filter

49

Page 50: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Gestion de conflits Données provenant de plusieurs SSTables

merge-sort en mémoire utilise timestamp → last-write win

SStable 1

Pk = xxx Col1,val11,time1 Col2,val21,time1

SStable 2

Pk = xxx Col1,val12,time2 Col3,val31,time3

SStable 3

Pk = xxx Col2,val22,time4 Col4,val41,time4

Pk = xxx Col1, val12,time2 Col2, val22,time4 Col3,val31,time3 Col4,val41,time4

50

Page 51: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Suppression de données SSTables immutables

pas de suppression physique

Suppression logique

écrire une colonne tombstone

51

Page 52: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Suppression de données SSTables immutables

pas de suppression physique

Suppression logique

écrire une colonne tombstone

A la lecture

comparaison timestamp tombstone + timestamp données

52

Page 53: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Compaction Beaucoup de SSTables

beaucoup d’accès disque → lent fragmentation des données

53

Page 54: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Compaction Beaucoup de SSTables

beaucoup d’accès disque → lent fragmentation des données

Purge des colonnes tombstone

54

Page 55: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Compaction Beaucoup de SSTables

beaucoup d’accès disque → lent fragmentation des données

Purge des colonnes tombstone Type de compaction

SizeTieredCompaction

LeveledCompaction

55

Page 56: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 57: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

CQL3 EN DÉTAIL

CQL3 stockage physique Détails d’implémentation

Collections & Maps

Page 58: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables simples Schéma CQL3

CREATE TABLE users ( id bigint PRIMARY KEY, nom text, age int);

Stockage physique

#partition : LongType

#colonne: CompositeType(UTF8Type) cellule: ByteType

58

Page 59: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « users »

Page 60: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonne marqueur

RowKey: 10 => (column=, value=, timestamp=…) => (column=age, value=00000023, timestamp=…) => (column=nom, value=4a6f686e20444f45, timestamp=…)

60

Page 61: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonne marqueur

INSERT INTO USERS(id) VALUES(12)

RowKey: 10 => (column=, value=, timestamp=…) => (column=age, value=00000023, timestamp=…) => (column=nom, value=4a6f686e20444f45, timestamp=…)

RowKey: 10 => (column=, value=, timestamp=…)

61

Page 62: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées) Schéma CQL3

62

CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur text, contenu text, PRIMARY KEY (article_id, date_creation));

Page 63: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées)

CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur text, contenu text, PRIMARY KEY (article_id, date_creation));

#partition (1er)

#col d’agrégation/clustering (2ème … )

Schéma CQL3

63

Page 64: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées) Stockage physique

#partition : IntType #colonne: CompositeType(DateType,UTF8Type) cellule: ByteType

Map<article_id, SortedMap<date_creation, SortedMap<nom_colonne,cellule>>>

64

Page 65: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées) #partition : IntType #colonne: CompositeType(DateType,UTF8Type) cellule: ByteType

CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur text, contenu text, PRIMARY KEY (article_id, date_creation));

Map<article_id, SortedMap<date_creation, SortedMap<nom_colonne,cellule>>>

65

Page 66: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées)

article_id | date_creation | auteur | contenu ----------------+-----------------------------------+--------------------+-------------------------------- 1 | 2014-04-16 10:00:00| Dupond| Cet article est génial 1 | 2014-04-16 10:01:00| Martin| Très bon article

CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur text, contenu text, PRIMARY KEY (article_id, date_creation));

Map<article_id, SortedMap<date_creation, SortedMap<nom_colonne,cellule>>>

66

Page 67: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées)

RowKey: 1 => (column=2014-04-16 10:00:00+0100:, value=,…) => (column=2014-04-16 10:00:00+0100:auteur, value=‘Dupond’, …) => (column=2014-04-16 10:00:00+0100:contenu, value=‘Cet article est génial’,…) => (column=2014-04-16 10:01:00+0100:, value=,…) => (column=2014-04-16 10:01:00+0100:auteur, value=‘Martin’, …) => (column=2014-04-16 10:01:00+0100:contenu, value=‘Très bon article’,…)

CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur text, contenu text, PRIMARY KEY (article_id, date_creation));

Map<article_id, SortedMap<date_creation, SortedMap<nom_colonne,cellule>>>

67

Page 68: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées) #partition : UTF8Type #colonne: CompositeType(UTF8Type,IntType,UTF8Type) cellule: ByteType

Map<operateur, SortedMap<ville, SortedMap<date, SortedMap<nom_colonne,cellule>>>>

CREATE TABLE qualite_reseau ( operateur text, ville text, date int, // format YYYYmmDDhh qualite double, PRIMARY KEY (operateur,ville,date));

68

Page 69: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées)

operateur | ville | date | qualité ----------------+----------+---------------------+------ Orange | Lyon | 2014041612 | 0.93 Orange | Paris | 2014041612 | 0.89 Orange | Paris | 2014041613 | 0.91 SFR | Lyon | 2014041612 | 0.88 SFR | Paris | 2014041612 | 0.78 SFR | Paris | 2014041615 | 0.93

CREATE TABLE qualite_reseau ( operateur text, ville text, date int, // format YYYYmmDDhh qualite double, PRIMARY KEY (operateur,ville,date));

Map<operateur, SortedMap<ville, SortedMap<date, SortedMap<nom_colonne,cellule>>>>

69

Page 70: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Tables « clustered » (agrégées) CREATE TABLE qualite_reseau ( operateur text, ville text, date int, // format YYYYmmDDhh qualite double, PRIMARY KEY (operateur,ville,date));

RowKey: Orange => (column=Lyon:2014041612:qualite, value=0.93, timestamp=…) => (column=Paris:2014041612:qualite, value=0.89, timestamp=…) => (column=Paris:2014041613:qualite, value=0.91, timestamp=…) ------------------- RowKey: SFR => (column=Lyon:2014041612:qualite, value=0.88, timestamp=…) => (column=Paris:2014041612:qualite, value=0.78, timestamp=…) => (column=Paris:2014041615:qualite, value=0.93, timestamp=…)

Map<operateur, SortedMap<ville, SortedMap<date, SortedMap<nom_colonne,cellule>>>>

70

Page 71: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 72: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Pourquoi CQL3 ? Retour du schéma (schemaless)

72

Page 73: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Pourquoi CQL3 ? Retour du schéma (schemaless) Découpler vue logique/stockage physique

73

Page 74: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Pourquoi CQL3 ? Retour du schéma (schemaless) Découpler vue logique/stockage physique API/requête plus familière & facile à prendre en main

74

Page 75: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Pourquoi CQL3 ? Retour du schéma (schemaless) Découpler vue logique/stockage physique API/requête plus familière & facile à prendre en main Pensez aux ops !!!!

75

Page 76: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

La clause « WHERE » S’applique aux clés des SortedMap (unicité)

76

Page 77: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

La clause « WHERE » S’applique aux clés des SortedMap (unicité) Autorise des recherches par plage (tri)

77

Page 78: Cassandra techniques de modelisation avancee

@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

Page 79: Cassandra techniques de modelisation avancee

@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

Page 80: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détails d’implémentation Pourquoi ne pas tout stocker dans les #colonnes ?

80

Page 81: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détails d’implémentation Pourquoi ne pas tout stocker dans les #colonnes ?

RowKey: SFR => (column=Lyon:2013110512:qualite, value=0.88)

RowKey: SFR => (column=Lyon:2013110512:qualite:0.88, value=)

81

Page 82: Cassandra techniques de modelisation avancee

@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

Page 83: Cassandra techniques de modelisation avancee

@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

Page 84: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détails d’implémentation Eager fetching par slice query

CREATE TABLE fichiers ( user_id bigint, file_id timeuuid, nom text, payload blob, taille int, PRIMARY KEY(user_id, file_id));

84

Page 85: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détails d’implémentation Eager fetching par slice query

85

SELECT nom, taille FROM file WHERE user_id = 10 ORDER BY file_id DESC;

Page 86: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détails d’implémentation Eager fetching par slice query

10 uuid1: uuid1:nom uuid1:payload uuid1:taille uuid2: … Ø video.mp4 xxxxxxxxxxxx 9Mb Ø

86

SELECT nom, taille FROM file WHERE user_id = 10 ORDER BY file_id DESC;

Page 87: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map CREATE TABLE collections_maps ( id int PRIMARY KEY, amis list<text>, suiveurs set<text>, adresse map<text,text>) ;

INSERT INTO collections_maps(id,amis,suiveurs, adresse) VALUES(10,[‘Dupond’,’Martin’],{‘Jean’,’Jacques’},{‘pays’:’FR’,’ville’:’Paris’});

87

Page 88: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map RowKey: 10 => (column=, value=, timestamp=…) => (column=amis:’uuid1’, value=‘Dupond’, timestamp=…) => (column=amis:’uuid2’, value=‘Martin’, timestamp=…) => (column=adresse:’pays’, value=‘FR’, timestamp=…) => (column=adresse:’ville’, value=‘Paris’, timestamp=…) => (column=suiveurs:’Jean’, value=, timestamp=…) => (column=suiveurs:’Jacques’, value=, timestamp=…)

88

Page 89: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Liste: => (column=amis:’uuid1’, value=‘Dupond’, timestamp=…) => (column=amis:’uuid2’, value=‘Martin’, timestamp=…) SortedMap<nom_de_colonne,SortedMap<uuid, valeur>>

Ordre

89

Page 90: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Set: => (column=suiveurs:’Jean’, value=, timestamp=…) => (column=suiveurs:’Jacques’, value=, timestamp=…) SortedMap<nom_de_colonne,SortedMap<valeur,Ø>>

Unicité

90

Page 91: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Map: => (column=adresse:’pays’, value=‘FR’, timestamp=…) => (column=adresse:’ville’, value=‘Paris’, timestamp=…) SortedMap<nom_de_colonne,SortedMap<clé,valeur>>

91

Page 92: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Set & Map

insertion et suppression d’élément(s)

92

UPDATE xxx SET suiveurs = suiveurs + {‘Pierre’}

UPDATE xxx SET adresse = adresse + {‘rue’ : ’rue de la paix’}

UPDATE xxx SET adresse[‘ville’] = ’Lyon’

Page 93: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Liste

ajout d’élément(s) en tête/en queue

93

UPDATE xxx SET amis = amis + [‘Pierre’]

UPDATE xxx SET amis = [‘Pierre’] + amis

Page 94: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map Liste

ajout d’élément(s) en tête/en queue

modification/suppression d’élément à l’index i

insertion d’élément à l’index i

94

UPDATE xxx SET amis = amis + [‘Pierre’]

UPDATE xxx SET amis = [‘Pierre’] + amis

UPDATE xxx SET amis[1] = ‘Paul’

UPDATE xxx SET amis[1] = null

Page 95: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Append1 REFERENCE TIME

Liste prepend/append

95

Page 96: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Prepend2

-xxxxxxx

Append1

now()

REFERENCE TIME

96

Liste prepend/append

Page 97: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Append3 Prepend2

-xxxxxxx

Append1

now()

REFERENCE TIME

97

Liste prepend/append

Page 98: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chargement

complet taille recommandée ≈ [100-1000]

Collection & Map

98

Page 99: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Chargement

complet taille recommandée ≈ [100-1000]

Index secondaire possible (C* 2.1) Requête avec ‘CONTAINS’ (C* 2.1)

SELECT … FROM collections_maps WHERE amis CONTAINS ‘Marc’

Collection & Map

99

Page 100: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 101: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

TECHNIQUES DE MODÉLISATION DE BASE

De SQL vers Cassandra Dé-normalisation et compromis

Gérer la mutabilité Pièges & bonnes pratiques

Page 102: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-1, n-1

normalisé

De SQL à Cassandra

CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_id uuid, contenu text, PRIMARY KEY(article_id, date_creation));

Personne

1

écrit

N

Commentaire

102

Page 103: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-1, n-1

dé-normalisé

De SQL à Cassandra

CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_data text, //JSON ? contenu text, PRIMARY KEY(article_id, date_creation));

1

écrit

N

Commentaire

Personne

103

Page 104: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-n, n-n

normalisé

De SQL à Cassandra

CREATE TABLE amis ( user_id uuid, ami_id uuid, PRIMARY KEY(user_id, ami_id)) ;

Personne N

est ami avec

N

104

Page 105: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-n, n-n

dé-normalisé

De SQL à Cassandra

CREATE TABLE amis ( user_id uuid, ami_id uuid, ami_data text, // JSON ? PRIMARY KEY(user_id, ami_id)) ;

Personne N

est ami avec

N

105

Page 106: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-1, n-1

compact

avantages/inconvénients

Type de dé-normalisation

CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_data text, //JSON ? contenu text, PRIMARY KEY(article_id, date_creation));

106

Page 107: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

1-1, n-1

éclaté

avantages/inconvénients

Type de dé-normalisation

CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_id uuid, auteur_nom text, auteur_bio text, … contenu text, PRIMARY KEY(article_id, date_creation));

107

Page 108: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

n-1, n-n

compact avec collections & maps

égalité code vs égalité C* !!!

Type de dé-normalisation

CREATE TABLE amis ( user_id uuid, amis set<text>, // JSON ? PRIMARY KEY(user_id)) ;

108

Page 109: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

n-1, n-n

éclaté avec table « clustered »

Type de dé-normalisation

CREATE TABLE amis ( user_id uuid, ami_id uuid, ami_nom text, ami_bio text, … PRIMARY KEY(user_id, ami_id)) ;

109

Page 110: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Gérer la mutabilité

110

Page 111: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

L’éliminer

Gérer la mutabilité

CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_id uuid, auteur_login text, auteur_bio text, auteur_localisation text, … contenu text, PRIMARY KEY(article_id, date_creation));

111

Page 112: Cassandra techniques de modelisation avancee

@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)) ;

112

* Command Query Responsability Segregation

Page 113: Cassandra techniques de modelisation avancee

@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

Page 114: Cassandra techniques de modelisation avancee

@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

Page 115: Cassandra techniques de modelisation avancee

@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

Page 116: Cassandra techniques de modelisation avancee

@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

Page 117: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Les pièges de la dé-normalisation Se couvrir fonctionnellement !!!

BDD, test d’acceptance tests unitaires

117

Page 118: Cassandra techniques de modelisation avancee

@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

Page 119: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

TODO

approche query-first

Bonnes pratiques

119

Page 120: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

TODO

approche query-first TDD & BDD compromis fonctionnels CQRS

Bonnes pratiques

120

Page 121: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 122: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Page 123: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

TECHNIQUES DE MODÉLISATION AVANCÉE

Types de clés Ordre d’agrégation

La clause IN Wide row et « bucketing »

Le type counter

Page 124: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés de partition Clé de partition simple

CREATE TABLE xxx ( partition uuid, clustering1 uuid, clustering2 uuid, …., PRIMARY KEY(partition, clustering1,clustering2));

124

Page 125: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés de partition Clé de partition « composite »

CREATE TABLE xxx ( partition1 uuid, partition2 text, clustering1 uuid, clustering2 uuid, ….,

PRIMARY KEY((partition1, partition2), clustering1, clustering2));

#partition: CompositeType(UUIDType,UTF8Type) #colonne: CompositeType(UUIDType,UUIDType) cellule: ByteType

125

Page 126: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés de partition Clé de partition « composite »

CREATE TABLE xxx ( partition1 uuid, partition2 text, clustering1 uuid, clustering2 uuid, ….,

PRIMARY KEY((partition1, partition2), clustering1, clustering2));

126

Page 127: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés d’agrégation Pseudo « GROUP BY » Map<partition,

SortedMap<clustering1, SortedMap<clustering2,cellule>>>

PRIMARY KEY(partition, clustering1,clustering2);

127

Page 128: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés d’agrégation Unicité par tuple

128

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, commentaire text,

PRIMARY KEY(film_id, note));

Page 129: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Clés d’agrégation Unicité par tuple

129

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, commentaire text,

PRIMARY KEY(film_id, note)); 1 note/film

Page 130: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, commentaire text, PRIMARY KEY(film_id, note, user_id));

Clés d’agrégation Unicité par tuple

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, commentaire text,

PRIMARY KEY(film_id, note)); 1 note/film

1 note/user

130

Page 131: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Ordre d’agrégation Tri descendant naturel

CREATE TABLE timeline ( user_id uuid, tweet_id timeuuid, tweet text, PRIMARY KEY (user_id, tweet_id)) WITH CLUSTERING ORDER (tweet_id DESC);

131

Page 132: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Ordre d’agrégation Tri descendant naturel

peu efficace, raison ? → scan en arrière

10 uuid1 uuid2 … uuid98 uuid99 uuid100 … … … … … … 33 uuid1 uuid2 … uuid51 uuid52

… … … … … … … …

132

Page 133: Cassandra techniques de modelisation avancee

@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

Page 134: Cassandra techniques de modelisation avancee

@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

Page 135: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee 135

Comment ça marche ? → multiget !

La clause « IN »

Page 136: Cassandra techniques de modelisation avancee

@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, …)

Page 137: Cassandra techniques de modelisation avancee

@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

Page 138: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Wide rows et « bucketing » Bucketing

découper une ligne physique sur plusieurs partitions répartit la charge attention aux requêtes!

138

Page 139: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh: « metrics_annee », « metrics_mois »

Page 140: Cassandra techniques de modelisation avancee

@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

Page 141: Cassandra techniques de modelisation avancee

@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

Page 142: Cassandra techniques de modelisation avancee

@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

Page 143: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

2014-02-01 00:00:00 … 2014-02-10

23:59:59 …

0.24 … 0.23 …

Wide rows et « bucketing » Requêtes inter-partition

CPU:201401 2014-01-01

00:00:00 2014-01-01

00:00:10 … 2014-01-25 00:00:00 … 2014-01-31

23:59:59 0.24 0.23 … 0.27 … 0.25

25 Jan. – 31Jan.

01 Fev. – 10 Fev.

143

CPU:201402

Page 144: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Wide rows et « bucketing » Pré-requis

valeur de #col de croissance monotone entre les partitions date/timeuuid bons candidats

144

Page 145: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Wide rows et « bucketing » Contre-exemple

CPU:2013 01 02 03 04 05 06 07 08 09 10 11 12 0.75 0.71 0.68 0.79 0.69 0.73 0.75 0.77 0.83 0.78 0.79 0.88

CPU:2014 01 02 03 04 05 06 07 08 09 10 11 12 0.71 0.72 0.67 0.80 0.71 0.75 0.74 0.76 0.81 0.79 0.83 0.87

SELECT moyenne FROM metrics_annee WHERE type = ‘CPU’ AND annee IN (2013, 2014) AND mois ≥ 11AND mois ≤ 02;

145

Page 146: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 147: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Le type counter Fonctionnement

seulement incrément/décrément suppression possible ne jamais réutiliser un compteur supprimé

Limitations

non idempotent pas 100% précis (ok pour analytics)

147

Page 148: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Les patterns avec counter / vote

naïve: incr/decr 1 seul compteur version duale: pour/contre infos étendues

total: pour + contre ratio: pour/(pour + contre)

CREATE TABLE popularite ( article_id uuid PRIMARY KEY pour counter, contre counter) ;

148

Page 149: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Les patterns avec counter Système de rating

CREATE TABLE film_rating ( film_id uuid PRIMARY KEY une_etoile counter, deux_etoiles counter, trois_etoiles counter, quatre_etoiles counter, cinq_etoiles counter) ;

149

Page 150: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh : « abonnes_telecom », « abonnes_telecom_par_localite »

Page 151: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 152: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

TECHNIQUES DE MODÉLISATION EXOTIQUES

Time To Live FTW Timestamp, WTF ?

C.A.S. distribué

Page 153: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live En bref

données volatiles/temporaires seulement sur colonnes résolution en seconde expiré côté serveur

153

Page 154: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live Jetons de sécurité

CREATE TABLE oauth_tokens( token uuid PRIMARY KEY, user_id int, permissions set<text>) ;

154

Page 155: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live Jetons de sécurité Jetons à usage unique

CREATE TABLE oauth_tokens( token uuid PRIMARY KEY, user_id int, permissions set<text>) ;

CREATE TABLE code_de_validation( code_de_validation text PRIMARY KEY, email text) ;

155

Page 156: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live Fonction ttl() dans CQL3

156

SELECT ttl(code_de_validation) FROM code_de_validation WHERE code_de_validation=‘sdfkl0rf’;

Page 157: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live Rate limiting

CREATE TABLE rate_limiting ( user_id int, tentative uuid, PRIMARY KEY (user_id, tentative)) ;

157

Page 158: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Time To Live Rate limiting

CREATE TABLE rate_limiting ( user_id int, tentative uuid, PRIMARY KEY (user_id, tentative)) ;

SELECT COUNT(*) FROM rate_limiting WHERE user_id =10

158

Page 159: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

Rate Limiting

Source: bit.ly/1noCqY1

Page 160: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Timestamp En bref

automatique sur chaque colonne insérée valeur modifiable par client résolution en micro-seconde utilisé pour résolution de conflit

160

Page 161: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

Timestamp Barrière d’écriture

Source: bit.ly/1noCqY1

Page 162: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

C.A.S. distribué Lightweight transaction

depuis C* 2.0 implémentation de Paxos très coûteux (3 aller/retours) ! utile pour 1% use-cases

162

Page 163: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

C.A.S. distribué Contrainte d’intégrité

UPDATE abonnes SET preferences=… WHERE identifiant=… IF compte_valide=true

163

Page 164: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

C.A.S. distribué Contrainte d’intégrité Contrainte d’unicité

UPDATE abonnes SET preferences=… WHERE identifiant=… IF compte_valide=true

INSERT INTO abonnes(…) VALUES(…) IF NOT EXISTS

164

Page 165: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh : « lock »

Page 166: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 167: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

LES ANTI-PATTERNS

Queues et suppression Détection de présence/d’absence

Read-before-write Row cache

Page 168: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Implémentation naïve

a b c d e

Queue FIFO C*

a b c d e

168

Page 169: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Implémentation naïve

a b c d e

b c d e

Queue FIFO C*

a b c d e

a b c d e a

169

Page 170: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Implémentation naïve

a b c d e

Queue FIFO C*

a b c d e

a b c d e a

b c d e f a b c d e a f

170

b c d e

Page 171: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Implémentation naïve

a b c d e

Queue FIFO C*

a b c d e

a b c d e a

b c d e f a b c d e a f

c d e f a b c d e a f b

171

b c d e

Page 172: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Queue FIFO consommée

a b c d e a f b c d e f

172

Page 173: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Queue FIFO consommée

Queue avec rollback

a b c d e a f b c d e f

a a a a a a a a a a … a

173

Page 174: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues Queue FIFO consommée

Queue avec rollback Limite 100K tombstones → leveled compaction ≈ Partition trop large!

a b c d e a f b c d e f

a a a a a a a a a a … a

174

Page 175: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: solutions Utiliser JMS

best tool for the job !!!!

175

Page 176: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: solutions Utiliser JMS

best tool for the job !!!!

Besoin de distribution ?

Apache Kafka

176

Page 177: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: solutions Bucketing & croissance monotone

10 000 éléments/bucket

#p:#bucket1 #t1 #t2 #t3 … #t10000

m1 m2 m3 … m10000

#p:#bucket2 #t100001 #t10002 #t10003 … #t20000

m100001 m10002 m10003 … m20000

#p:#bucket3 #t200001 #t20002 #t20003 … #t30000

m200001 m20002 m20003 … m30000

177

Page 178: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple sources sn

ordonner les sources: s1, s2 … sn

178

Page 179: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple sources sn

ordonner les sources: s1, s2 … sn round-robin sur les #bucket, pour sm : #bucket%n = m%n

179

Page 180: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple sources sn

ordonner les sources: s1, s2 … sn round-robin sur les #bucket, pour sm : #bucket%n = m%n bucket suivant si #élément = 10 000

180

Page 181: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Exemple n = 3

s1 #bucket = {1, 4, 7…}, s2 #bucket = {2, 5, 8…}, s3 #bucket = {3, 6, 9…}

181

#p:#bucket1 … … … … … … … … … …

#p:#bucket2 … … … … … … … … … …

#p:#bucket3 … … … … … … … … … …

#p:#bucket4 … … … … … … … … … …

#p:#bucket5 … … … … … … … … … …

s1

s1

s2

s2

s3

Page 182: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple consommateurs cn

idem

182

Page 183: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Rollback

pas de suppression !!! cm remet messages dans #bucketm+? futur → comptage faussé pour cm+?

183

Page 184: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Rollback

pas de suppression !!! cm remet messages dans #bucketm+? futur → comptage faussé pour cm+?

184

#p:#bucketm … … … … … … … … … …

#p:#bucketm+1 … … … … … … … … … …

#p:#bucketm+2 … … … … … … … … … … … … … … … …

#p:#bucketm+3 … … … … … … … … … …

Page 185: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Solution rollback

compteur d’éléments supplémentaires pour messages rollbackés complexité technique

185

#p:#bucketm … … … … … … … … … …

#p:#bucketm+1 … … … … … … … … … …

#p:#bucketm+2 … … … … … … … … … … … … … … … …

#p:#bucketm+3 … … … … … … … … … …

+3

Page 186: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détection de présence/d’absence

186

Page 187: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détection de présence/d’absence Jetons de sécurité

Vérification

CREATE TABLE user_tokens ( user_id int, token uuid, PRIMARY KEY(user_id, token)) ;

SELECT count(*) FROM user_tokens WHERE user_id =… AND token =…

187

Page 188: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Détection de présence/d’absence Chemin de lecture

Bloom filter en mémoire partition key cache en mémoire accès disque SSTable

188

Page 189: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache

Compression offset

Key Index Sample 4

5

Memtable

1 2

7

3

SStable 1

Column Family User

6

Détection de présence/d’absence SELECT count(*) FROM user_tokens WHERE user_id =… AND token =…

189

Page 190: Cassandra techniques de modelisation avancee

@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

Page 191: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

Bloom Filter

Partition Key Cache Memtable

1 2

4

3

Détection de présence/d’absence SELECT count(*) FROM user_tokens WHERE user_id =… AND token =…

191

Page 192: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Row cache Use-cases

données référentielles taille raisonnable partitions accédées très fréquemment

192

Page 193: Cassandra techniques de modelisation avancee

@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

Page 194: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 195: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

LES INDEX SECONDAIRES

Implémentation Use-cases recommandés

Retour d’expérience

Page 196: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Implémentation Naïve

CREATE TABLE user_par_pays ( pays text, user_id int, PRIMARY KEY(pays, user_id)) ;

196

Page 197: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Implémentation Naïve Problèmes

197 partitions max → wide rows distribution pays non uniforme → hot-spots m.a.j. non atomique bucketing non adapté

CREATE TABLE user_par_pays ( pays text, user_id int, PRIMARY KEY(pays, user_id)) ;

197

Page 198: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

11:Martin, 85:Sophie, 57:Smith

Implémentation Distribuée

10, Dupond, FR 11, Martin, FR 85, Sophie, FR 25, John, US 74, Helen, US 57, Smith, UK 18, Heinrich, DE

n4

n3

n2

10:Dupond, 25:John,

18:Heinrich

n1

74:Helen

FR → {10} US → {25} DE → {18}

FR → {11,85} UK → {57}

US → {74}

198

Page 199: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

11:Martin, 85:Sophie, 57:Smith

Implémentation Conséquences bénéfiques

meilleure distribution, hot-spots même distribution que données

n4

n3

n2

n1

10:Dupond, 25:John,

18:Heinrich 74:Helen

FR → {10} US → {25} DE → {18}

FR → {11,85} UK → {57}

US → {74}

199

Page 200: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

11:Martin, 85:Sophie, 57:Smith

Implémentation Conséquences fâcheuses

lecture index → scan de N/R nœuds !!! N = #nœuds R = replication factor

n4

n3

n2

n1

10:Dupond, 25:John,

18:Heinrich 74:Helen

FR → {10} US → {25} DE → {18}

FR → {11,85} UK → {57}

US → {74}

200

N = 4,R = 2

Page 201: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

11:Martin, 85:Sophie, 57:Smith

Implémentation Mais pourquoi ???

range scan pour lire les données …de toute façon

n4

n3

n2

n1

DE → {18}

US → {25,74}

FR → {10,11,85} UK → {57}

10:Dupond, 25:John,

18:Heinrich 74:Helen

201

Page 202: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Use-cases recommandés Bon candidats

peu de valeurs indexées # (mais assez quand même)

202

Page 203: Cassandra techniques de modelisation avancee

@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

Page 204: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Retour d’expérience Queue pour état d’avancement

états : { ‘TODO’, ‘IN PROGRESS’, ‘PROCESSED’, ‘DONE’} colonne : item_id/état index secondaire sur état

204

Page 205: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Retour d’expérience Queue pour état d’avancement

états : { ‘TODO’, ‘IN PROGRESS’, ‘PROCESSED’} colonne : item_id/état index secondaire sur état

Transition

prendre 1000 items avec état ‘TODO’ m.a.j. de l’état en ‘IN PROGRESS’ traiter les items mettre les 1000 états en ‘PROCESSED’ si erreur, remettre état en ‘TODO’

205

Page 206: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Retour d’expérience Solution

utiliser JMS pour queue queue avec wide row, bucketing & accès concurrent compteur pour messages réinjectés enlever index secondaires

206

Page 207: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Q & R

Page 208: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

<FUTUR> C*

Requêtes inter-clustering Colonnes statiques

User defined type

Page 209: Cassandra techniques de modelisation avancee

@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

Page 210: Cassandra techniques de modelisation avancee

@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

Page 211: Cassandra techniques de modelisation avancee

@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

Page 212: Cassandra techniques de modelisation avancee

@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

Page 213: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Requêtes inter-clustering (2.0.6) Nouvelle syntaxe

SELECT * FROM notes_film WHERE film_id=.. AND (note,user_id) > (1,49) LIMIT 10

213

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

Page 214: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) CREATE TABLE notes_film (

film_id uuid, note uuid, user_id int, commentaire text, PRIMARY KEY(film_id, note, user_id));

CREATE TABLE films ( film_id uuid, titre text, synopsis text, acteurs_id set<int>, acteurs set<text> PRIMARY KEY(film_id));

214

Page 215: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) Afficher le film et les notes

1 requête pour film 1 requête pour notes

215

Page 216: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) Objectif: 1 seule requête Solution naïve

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, titre text, synopsis text, acteurs_id set<int>, acteurs set<text>, commentaire text, PRIMARY KEY(film_id, note, user_id));

216

Page 217: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) RowKey: 98bc1cec-4c4b-468b-a20e-2af142a26c97 => (column=1:10:, value=, …) => (column=1:10:titre, value=…) => (column=1:10:synopsis, value=…) => (column=1:10:acteurs_ids, value=…) => (column=1:10:acteurs, value=…) => (column=1:10:commentaire, value=‘Quel navet! Passez votre chemin, vous …’, …) => (column=1:23:, value=, …) => (column=1:23:titre, value=…) => (column=1:23:synopsis, value=…) => (column=1:23:acteurs_ids, value=…) => (column=1:23:acteurs, value=…) => (column=1:23:commentaire, value=‘Un film à regarder avec le cerveau débranché’, …)

217

Page 218: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) Avec colonnes statiques

CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, titre text static, synopsis text static, acteurs_id set<int> static, acteurs set<text> static, commentaire text, PRIMARY KEY(film_id, note, user_id));

218

Page 219: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

Colonnes statiques (2.0.6) RowKey: 98bc1cec-4c4b-468b-a20e-2af142a26c97 => (column=:null:null:titre, value=…) => (column=:null:null:synopsis, value=…) => (column=:null:null:acteurs_ids, value=…) => (column=:null:null:acteurs, value=…) => (column=1:10:, value=, …) => (column=1:10:commentaire, value=‘Quel navet! Passez votre chemin, vous …’, …) => (column=1:23:, value=, …) => (column=1:23:commentaire, value=‘Un film à regarder avec le cerveau débranché’, …)

219

Page 220: Cassandra techniques de modelisation avancee

@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

Page 221: Cassandra techniques de modelisation avancee

@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

Page 222: Cassandra techniques de modelisation avancee

@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

Page 223: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

User defined type (2.1) Limitations

modifications non atomiques lecture eager ALTER TYPE ADD, ALTER TYPE RENAME

223

Page 224: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

User defined type (2.1) Sélection possible sur les champs internes UDT ≈ blob

SELECT auteur.nom, auteur.adresse, contenu FROM commentaires …

224

Page 225: Cassandra techniques de modelisation avancee

@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

Page 226: Cassandra techniques de modelisation avancee

@doanduyhai #C*ModelisationAvancee

MERCI !

@doanduyhai [email protected] doanduyhai