Cassandra techniques de modelisation avancee

Preview:

DESCRIPTION

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

Citation preview

@doanduyhai #C*ModelisationAvancee

Cassandra

Techniques de modélisation avancée

@doanduyhai #C*ModelisationAvancee

DuyHai DOAN

Le jour: + + conseil

Le soir: Cassandra + Achilles

@doanduyhai doanduyhai@gmail.com doanduyhai

Développeur Freelance Java/Cassandra

@doanduyhai #C*ModelisationAvancee

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

3

@doanduyhai #C*ModelisationAvancee

Agenda

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

@doanduyhai #C*ModelisationAvancee

MODÈLE DE DONNÉES

Concepts Accès aux données

Le type « composite »

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

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

Vue logique

SortedMap<tokenp,…>

9

@doanduyhai #C*ModelisationAvancee

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

SortedMap<#col,cellule>>

Vue logique

Unicité

Tri

SortedMap<tokenp,…>

10

@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

@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

@doanduyhai #C*ModelisationAvancee

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

13

@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

@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

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « stockage_physique »

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

#Colonne en multiple composants

type1:type2:type3 tri successif par composant

Type « composite »

20

@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

@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

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « hygrometrie »

@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

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

ARCHITECTURE TECHNIQUE

Système de fichiers Chemin de lecture/écriture

Compaction

@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

@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

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Chemin d’écriture Mémoire

Disque2

Commit log1

Disque 1

. . .

1

Commit log2

Commit logn

36

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Chemin de lecture

Mémoire Off-Heap

Disque

Row Cache

Mémoire JVM Heap

1

42

SELECT * FROM users WHERE partition =…

@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 =…

@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 =…

@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 =…

@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 =…

@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 =…

@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 =…

@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

@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

@doanduyhai #C*ModelisationAvancee

Suppression de données SSTables immutables

pas de suppression physique

Suppression logique

écrire une colonne tombstone

51

@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

@doanduyhai #C*ModelisationAvancee

Compaction Beaucoup de SSTables

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

53

@doanduyhai #C*ModelisationAvancee

Compaction Beaucoup de SSTables

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

Purge des colonnes tombstone

54

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

CQL3 EN DÉTAIL

CQL3 stockage physique Détails d’implémentation

Collections & Maps

@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

@doanduyhai #C*ModelisationAvancee

Démo

cassandra-cli : « users »

@doanduyhai #C*ModelisationAvancee

Colonne marqueur

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

60

@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

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

@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

@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

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

Pourquoi CQL3 ? Retour du schéma (schemaless)

72

@doanduyhai #C*ModelisationAvancee

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

73

@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

@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

@doanduyhai #C*ModelisationAvancee

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

76

@doanduyhai #C*ModelisationAvancee

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

77

@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

@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

@doanduyhai #C*ModelisationAvancee

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

80

@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

@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

@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

@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

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

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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

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

Unicité

90

@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

@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’

@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

@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

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Append1 REFERENCE TIME

Liste prepend/append

95

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Prepend2

-xxxxxxx

Append1

now()

REFERENCE TIME

96

Liste prepend/append

@doanduyhai #C*ModelisationAvancee

Collection & Map

1262304000000 01/01/2012 1383084226280

Append3 Prepend2

-xxxxxxx

Append1

now()

REFERENCE TIME

97

Liste prepend/append

@doanduyhai #C*ModelisationAvancee

Chargement

complet taille recommandée ≈ [100-1000]

Collection & Map

98

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@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

@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

@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

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Gérer la mutabilité

110

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

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

BDD, test d’acceptance tests unitaires

117

@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

@doanduyhai #C*ModelisationAvancee

TODO

approche query-first

Bonnes pratiques

119

@doanduyhai #C*ModelisationAvancee

TODO

approche query-first TDD & BDD compromis fonctionnels CQRS

Bonnes pratiques

120

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

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

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

PRIMARY KEY(partition, clustering1,clustering2);

127

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

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee 135

Comment ça marche ? → multiget !

La clause « IN »

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

@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

@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

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh: « metrics_annee », « metrics_mois »

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Wide rows et « bucketing » Pré-requis

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

144

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh : « abonnes_telecom », « abonnes_telecom_par_localite »

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

TECHNIQUES DE MODÉLISATION EXOTIQUES

Time To Live FTW Timestamp, WTF ?

C.A.S. distribué

@doanduyhai #C*ModelisationAvancee

Time To Live En bref

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

153

@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

@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

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

@doanduyhai #C*ModelisationAvancee

Time To Live Rate limiting

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

157

@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

@doanduyhai #C*ModelisationAvancee

Démo

Rate Limiting

Source: bit.ly/1noCqY1

@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

@doanduyhai #C*ModelisationAvancee

Démo

Timestamp Barrière d’écriture

Source: bit.ly/1noCqY1

@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

@doanduyhai #C*ModelisationAvancee

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

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

163

@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

@doanduyhai #C*ModelisationAvancee

Démo

cqlsh : « lock »

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

LES ANTI-PATTERNS

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

Read-before-write Row cache

@doanduyhai #C*ModelisationAvancee

Queues Implémentation naïve

a b c d e

Queue FIFO C*

a b c d e

168

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Queues Queue FIFO consommée

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

172

@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

@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

@doanduyhai #C*ModelisationAvancee

Queues: solutions Utiliser JMS

best tool for the job !!!!

175

@doanduyhai #C*ModelisationAvancee

Queues: solutions Utiliser JMS

best tool for the job !!!!

Besoin de distribution ?

Apache Kafka

176

@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

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple sources sn

ordonner les sources: s1, s2 … sn

178

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Multiple consommateurs cn

idem

182

@doanduyhai #C*ModelisationAvancee

Queues: accès concurrents Rollback

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

183

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

@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

@doanduyhai #C*ModelisationAvancee

Détection de présence/d’absence

186

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Row cache Use-cases

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

192

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

LES INDEX SECONDAIRES

Implémentation Use-cases recommandés

Retour d’expérience

@doanduyhai #C*ModelisationAvancee

Implémentation Naïve

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

196

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Use-cases recommandés Bon candidats

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

202

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

Q & R

@doanduyhai #C*ModelisationAvancee

<FUTUR> C*

Requêtes inter-clustering Colonnes statiques

User defined type

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@doanduyhai #C*ModelisationAvancee

User defined type (2.1) Limitations

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

223

@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

@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

@doanduyhai #C*ModelisationAvancee

MERCI !

@doanduyhai doanduyhai@gmail.com doanduyhai