Cassandra techniques de modelisation avancee

2,339 views
2,190 views

Published on

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

Published in: Engineering
1 Comment
9 Likes
Statistics
Notes
No Downloads
Views
Total views
2,339
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
99
Comments
1
Likes
9
Embeds 0
No embeds

No notes for slide

Cassandra techniques de modelisation avancee

  1. 1. @doanduyhai#C*ModelisationAvancee Cassandra Techniques de modélisation avancée
  2. 2. @doanduyhai#C*ModelisationAvancee DuyHai DOAN Le jour: + + conseil Le soir: Cassandra + Achilles @doanduyhai doanduyhai@gmail.com doanduyhai Développeur Freelance Java/Cassandra
  3. 3. @doanduyhai#C*ModelisationAvancee Agenda Modèle de données Architecture technique CQL3 en détail Techniques de modélisation de base 3
  4. 4. @doanduyhai#C*ModelisationAvancee Agenda Techniques de modélisation avancée Modélisations exotiques Les anti-patterns Les index secondaires <Futur> C* 4
  5. 5. @doanduyhai#C*ModelisationAvancee MODÈLE DE DONNÉES Concepts Accès aux données Le type « composite »
  6. 6. @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
  7. 7. @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
  8. 8. @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
  9. 9. @doanduyhai#C*ModelisationAvancee Table ≈ Map<#p,SortedMap<#col,cellule>> Vue logique SortedMap<tokenp,…> 9
  10. 10. @doanduyhai#C*ModelisationAvancee Table ≈ Map<#p,SortedMap<#col,cellule>> SortedMap<#col,cellule>> Vue logique Unicité Tri SortedMap<tokenp,…> 10
  11. 11. @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
  12. 12. @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
  13. 13. @doanduyhai#C*ModelisationAvancee Vue logique Map<#p,SortedMap<#col,cellule>> → plage de partitions par #partition très lent    13
  14. 14. @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
  15. 15. @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
  16. 16. @doanduyhai#C*ModelisationAvancee Démo cassandra-cli : « stockage_physique »
  17. 17. @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
  18. 18. @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
  19. 19. @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
  20. 20. @doanduyhai#C*ModelisationAvancee #Colonne en multiple composants  type1:type2:type3  tri successif par composant Type « composite » 20
  21. 21. @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
  22. 22. @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
  23. 23. @doanduyhai#C*ModelisationAvancee Démo cassandra-cli : « hygrometrie »
  24. 24. @doanduyhai#C*ModelisationAvancee Slice query avec « composite » Requêtes  relevé par ville, date et type #p = Paris, #comp1 = date1, #comp2 = temperature  relevés par ville et date #p = Paris, #comp1 = date1  relevés par ville et tranche de dates #p = Paris, #comp1 ≥ date1 & #comp1 ≤ date2 24
  25. 25. @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
  26. 26. @doanduyhai#C*ModelisationAvancee Q & R  
  27. 27. @doanduyhai#C*ModelisationAvancee ARCHITECTURE TECHNIQUE Système de fichiers Chemin de lecture/écriture Compaction
  28. 28. @doanduyhai#C*ModelisationAvancee Mémoire Off-Heap Disque Column Family User Row Cache Mémoire JVM Heap Partition Key Cache Commit log1 … Key Index Sample Compression offset Bloom Filter SStable 3 Système de fichiers SStable 2SStable 1 Commit log 2 Commit logn Key Index Sample Compression offset Bloom Filter Key Index Sample Compression offset Bloom Filter 28
  29. 29. @doanduyhai#C*ModelisationAvancee Système de fichiers Format  <keyspace>-<column family>-<version>-<génération>-<composant>.db SSTables test-user-ic-1-Data.db → snapshot d’une SSTable à un instant t Méta-données test-user-ic-1-CompressionInfo.db → offset des données compressées test-user-ic-1-CRC.db → CRC des données non compressées 29
  30. 30. @doanduyhai#C*ModelisationAvancee Système de fichiers Format  <keyspace>-<column family>-<version>-<génération>-<composant>.db Méta-données test-user-ic-1-Filter.db → filtre de Bloom test-user-ic-1-Index.db → index des offset de #partition dans le SSTable test-user-ic-1-Statistics.db → statistiques test-user-ic-1-Summary.db → échantillon des offsets de #partition test-user-ic-1-TOC.txt 30
  31. 31. @doanduyhai#C*ModelisationAvancee Format des fichiers #p (user001) Longueur ligne Index de colonne * Tombstone Nb de colonnes Colonne1/Cellule1 …. ColonneN/CelluleN #p (user350) Longueur ligne Index de colonne * Tombstone Nb de colonnes Colonne1/Cellule1 …. ColonneN/CelluleN #Partition Offset … Index de colonne * user001 0x0 … premier: xxx dernier: yyy offset: 0x3 … user002 0x153 … premier: xxx dernier: yyy offset: 0x156 … user350 0x5464321 … premier: xxx dernier: yyy offset: 0x5464310 … *-Index.db *-Data.db 31 SStable Partition Key Cache
  32. 32. @doanduyhai#C*ModelisationAvancee Format des fichiers Echantillon Offset user001 0x0 user128 0x4500 user256 0x851513 user350 0x5464321 *-Summary.db #p (user001) Longueur ligne Index de colonne * Tombstone Nb de colonnes Colonne1/Cellule1 …. ColonneN/CelluleN #p (user350) Longueur ligne Index de colonne * Tombstone Nb de colonnes Colonne1/Cellule1 …. ColonneN/CelluleN 32 *-Data.dbSStable Key Index Sample
  33. 33. @doanduyhai#C*ModelisationAvancee Format des fichiers 1 0 0 1 0 0 1 0 0 0 « foo » h1 h2 h3 33 *-Filter.dbBloom Filter
  34. 34. @doanduyhai#C*ModelisationAvancee Format des fichiers 1 0 0 1* 0 0 1 0 1 1 « foo » « bar » h1 h2 h3 34 *-Filter.dbBloom Filter
  35. 35. @doanduyhai#C*ModelisationAvancee Format des fichiers 1 0 0 1* 0 0 1 0 1 1 h1 h2 h3 « qux » ? « foo » « bar » 35 *-Filter.dbBloom Filter
  36. 36. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Mémoire Disque2 Commit log1 Disque1 . . . 1 Commit log2 Commit logn 36
  37. 37. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Mémoire Disque2 Commit log1 Disque1 . . . MemTable Column Family 1 . . . 1 2 Commit log2 Commit logn MemTable Column Family 2 MemTable Column Family n 37
  38. 38. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Column Family1 Mémoire Disque2 Commit log1 SStable 1 Disque1 . . . Column Family2 SStable 1 Column Family3 SStable 1 1 3Commit log2 Commit logn 38
  39. 39. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Column Family1 Mémoire Disque2 Commit log1 SStable 1 Disque1 . . . Column Family2 SStable 1 Column Family3 SStable 1 1 3Commit log2 Commit logn 39 MemTable Column Family 1 . . . 2 MemTable Column Family 2 MemTable Column Family n
  40. 40. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Column Family1 Mémoire Disque2 Commit log1 SStable 1 Disque1 . . . SStable 2 Column Family2 SStable 1 SStable 2 Column Family3 SStable 1 1 3Commit log2 Commit logn 40
  41. 41. @doanduyhai#C*ModelisationAvancee Chemin d’écriture Column Family1 Mémoire Disque2 Commit log1 SStable 1 Disque1 . . . 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
  42. 42. @doanduyhai#C*ModelisationAvancee Chemin de lecture Mémoire Off-Heap Disque Row Cache Mémoire JVM Heap 1 42 SELECT * FROM users WHERE partition =…
  43. 43. @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 =…
  44. 44. @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 =…
  45. 45. @doanduyhai#C*ModelisationAvancee Chemin de lecture Mémoire Off-Heap Disque Row Cache Mémoire JVM Heap Bloom Filter  Partition Key Cache Key Index Sample4 1 2 3 45 SELECT * FROM users WHERE partition =…
  46. 46. @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 Sample4 5 1 2 3 46 SELECT * FROM users WHERE partition =…
  47. 47. @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 Sample4 5 1 Column Family User 2 6 3 47 SELECT * FROM users WHERE partition =…
  48. 48. @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 Sample4 5 Memtable 1 2 7 ∑ 3 SStable 1 Column Family User 6 48 SELECT * FROM users WHERE partition =…
  49. 49. @doanduyhai#C*ModelisationAvancee Mémoire Off-Heap Disque Column Family User Row Cache Mémoire JVM Heap Partition Key Cache Commit log1 … Key Index Sample Compression offset Bloom Filter SStable 3 Système de fichiers SStable 2SStable 1 Commit log 2 Commit logn Key Index Sample Compression offset Bloom Filter Key Index Sample Compression offset Bloom Filter 49
  50. 50. @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
  51. 51. @doanduyhai#C*ModelisationAvancee Suppression de données SSTables immutables  pas de suppression physique Suppression logique  écrire une colonne tombstone 51
  52. 52. @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
  53. 53. @doanduyhai#C*ModelisationAvancee Compaction Beaucoup de SSTables  beaucoup d’accès disque → lent  fragmentation des données 53
  54. 54. @doanduyhai#C*ModelisationAvancee Compaction Beaucoup de SSTables  beaucoup d’accès disque → lent  fragmentation des données Purge des colonnes tombstone 54
  55. 55. @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
  56. 56. @doanduyhai#C*ModelisationAvancee Q & R  
  57. 57. @doanduyhai#C*ModelisationAvancee CQL3 EN DÉTAIL CQL3  stockage physique Détails d’implémentation Collections & Maps
  58. 58. @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
  59. 59. @doanduyhai#C*ModelisationAvancee Démo cassandra-cli : « users »
  60. 60. @doanduyhai#C*ModelisationAvancee Colonne marqueur RowKey: 10 => (column=, value=, timestamp=…)  => (column=age, value=00000023, timestamp=…) => (column=nom, value=4a6f686e20444f45, timestamp=…) 60
  61. 61. @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
  62. 62. @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));
  63. 63. @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
  64. 64. @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
  65. 65. @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
  66. 66. @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
  67. 67. @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
  68. 68. @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
  69. 69. @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
  70. 70. @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
  71. 71. @doanduyhai#C*ModelisationAvancee Q & R  
  72. 72. @doanduyhai#C*ModelisationAvancee Pourquoi CQL3 ? Retour du schéma (schemaless) 72
  73. 73. @doanduyhai#C*ModelisationAvancee Pourquoi CQL3 ? Retour du schéma (schemaless) Découpler vue logique/stockage physique 73
  74. 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 74
  75. 75. @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
  76. 76. @doanduyhai#C*ModelisationAvancee La clause « WHERE » S’applique aux clés des SortedMap (unicité) 76
  77. 77. @doanduyhai#C*ModelisationAvancee La clause « WHERE » S’applique aux clés des SortedMap (unicité) Autorise des recherches par plage (tri) 77
  78. 78. @doanduyhai#C*ModelisationAvancee La clause « WHERE » S’applique aux clés des SortedMap (unicité) Autorise des recherches par plage (tri) Ordre des clés très important!!!!  SELECT * FROM qualite_reseau WHERE operateur = ‘ORANGE’ AND ville = ‘Paris’ AND date ≥ 2014041619 AND date ≤ 2014041621  SELECT * FROM qualite_reseau WHERE operateur = ‘ORANGE’ AND date ≥ 2014041619 AND date ≤ 2014041621 78
  79. 79. @doanduyhai#C*ModelisationAvancee Les méta-données de CQL3 Noms des colonnes « clustered » dans les tables ? key_aliases | key_validator | column_aliases | comparator --------------------+----------------------+--------------------------+------------------------------------------------------------------------------- ["operateur"] | UTF8Type | ["ville","date"] | CompositeType(UTF8Type,Int32Type,UTF8Type) SELECT key_aliases,key_validator,column_aliases,comparator FROM system.schema_columnfamilies WHERE keyspace_name=‘xxx' AND columnfamily_name=‘qualite_reseau’ 79
  80. 80. @doanduyhai#C*ModelisationAvancee Détails d’implémentation Pourquoi ne pas tout stocker dans les #colonnes ? 80
  81. 81. @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
  82. 82. @doanduyhai#C*ModelisationAvancee Détails d’implémentation Pourquoi ne pas tout stocker dans les #colonnes ?  limite des 64K pour les #colonnes  colonnes counter, type spécial RowKey: SFR => (column=Lyon:2013110512:qualite, value=0.88) RowKey: SFR => (column=Lyon:2013110512:qualite:0.88, value=) 82
  83. 83. @doanduyhai#C*ModelisationAvancee Détails d’implémentation Pourquoi ne pas tout stocker dans les #colonnes ?  limite des 64K pour les #colonnes  colonnes counter, type spécial → counter colonne d’agrégation RowKey: SFR => (column=Lyon:2013110512:qualite, value=0.88) RowKey: SFR => (column=Lyon:2013110512:qualite:0.88, value=) 83
  84. 84. @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
  85. 85. @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;
  86. 86. @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;
  87. 87. @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
  88. 88. @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
  89. 89. @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
  90. 90. @doanduyhai#C*ModelisationAvancee Collection & Map Set: => (column=suiveurs:’Jean’, value=, timestamp=…) => (column=suiveurs:’Jacques’, value=, timestamp=…) SortedMap<nom_de_colonne,SortedMap<valeur,Ø>> Unicité 90
  91. 91. @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
  92. 92. @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’
  93. 93. @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
  94. 94. @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
  95. 95. @doanduyhai#C*ModelisationAvancee Collection & Map 1262304000000 01/01/2012 1383084226280 Append1REFERENCE TIME Liste prepend/append 95
  96. 96. @doanduyhai#C*ModelisationAvancee Collection & Map 1262304000000 01/01/2012 1383084226280 Prepend2 -xxxxxxx Append1 now() REFERENCE TIME 96 Liste prepend/append
  97. 97. @doanduyhai#C*ModelisationAvancee Collection & Map 1262304000000 01/01/2012 1383084226280 Append3Prepend2 -xxxxxxx Append1 now() REFERENCE TIME 97 Liste prepend/append
  98. 98. @doanduyhai#C*ModelisationAvancee Chargement  complet  taille recommandée ≈ [100-1000] Collection & Map 98
  99. 99. @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
  100. 100. @doanduyhai#C*ModelisationAvancee Q & R  
  101. 101. @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
  102. 102. @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
  103. 103. @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
  104. 104. @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
  105. 105. @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
  106. 106. @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
  107. 107. @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
  108. 108. @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
  109. 109. @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
  110. 110. @doanduyhai#C*ModelisationAvancee Gérer la mutabilité 110
  111. 111. @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
  112. 112. @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
  113. 113. @doanduyhai#C*ModelisationAvancee Approche CQRS* Gérer la mutabilité CREATE TABLE amis ( user_id uuid, ami_id uuid, ami_nom text, ami_bio text, … PRIMARY KEY(user_id, ami_id)) ; Process M.A.J de la bio des users 113 * Command Query Responsability Segregation
  114. 114. @doanduyhai#C*ModelisationAvancee Les pièges de la dé-normalisation Ne pas assez dé-normaliser  problème du N+1 select/read-before-write 100 commentaires → 101 selects CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_id uuid, contenu text, PRIMARY KEY(article_id, date_creation)); 114
  115. 115. @doanduyhai#C*ModelisationAvancee Les pièges de la dé-normalisation Compromis fonctionnels !  pagination par 10 commentaires  max 11 selects CREATE TABLE commentaires ( article_id uuid, date_creation timestamp, auteur_id uuid, contenu text, PRIMARY KEY(article_id, date_creation)); 115
  116. 116. @doanduyhai#C*ModelisationAvancee Les pièges de la dé-normalisation Trop dé-normaliser  intégrité des données  mises à jour complexes  batchs de correction de données …. cauchemardesques 116
  117. 117. @doanduyhai#C*ModelisationAvancee Les pièges de la dé-normalisation Se couvrir fonctionnellement !!!  BDD, test d’acceptance  tests unitaires 117
  118. 118. @doanduyhai#C*ModelisationAvancee Les pièges de la dé-normalisation Given 2 users Foo and Bar When Foo adds Bar as friend Then Foo friends list should display Bar’s details Given 2 users Foo and Bar When Foo adds Bar as friend And Bar changes his bio Then Foo should see new Bar’s bio in his friends list Given 2 users Foo and Bar When Foo adds Bar as friend And Bar deletes his account Then Foo should not see Bar in his friend list 118
  119. 119. @doanduyhai#C*ModelisationAvancee TODO  approche query-first Bonnes pratiques 119
  120. 120. @doanduyhai#C*ModelisationAvancee TODO  approche query-first  TDD & BDD  compromis fonctionnels  CQRS Bonnes pratiques 120
  121. 121. @doanduyhai#C*ModelisationAvancee Q & R  
  122. 122. @doanduyhai#C*ModelisationAvancee
  123. 123. @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
  124. 124. @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
  125. 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)); #partition: CompositeType(UUIDType,UTF8Type) #colonne: CompositeType(UUIDType,UUIDType) cellule: ByteType 125
  126. 126. @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
  127. 127. @doanduyhai#C*ModelisationAvancee Clés d’agrégation Pseudo « GROUP BY » Map<partition, SortedMap<clustering1, SortedMap<clustering2,cellule>>> PRIMARY KEY(partition, clustering1,clustering2); 127
  128. 128. @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));
  129. 129. @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
  130. 130. @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
  131. 131. @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
  132. 132. @doanduyhai#C*ModelisationAvancee Ordre d’agrégation Tri descendant naturel  peu efficace, raison ? → scan en arrière 10 uuid1uuid2 … uuid98 uuid99 uuid100 … … … … … … 33 uuid1 uuid2 … uuid51 uuid52 … … … … … … … … 132
  133. 133. @doanduyhai#C*ModelisationAvancee 133 Sur clé de partition « composite » CREATE TABLE xxx ( partition1 uuid, partition2 text, …. PRIMARY KEY((partition1, partition2)); SELECT * FROM xxx WHERE partition1 = #p1 AND partition2 IN (#p21, #p22, …) La clause « IN » SELECT * FROM xxx WHERE partition1 IN (#p11, #p12, …) AND partition2 = #p2
  134. 134. @doanduyhai#C*ModelisationAvancee 134 Sur clé d’agrégation CREATE TABLE xxx (partition uuid, clustering1 uuid, clustering2 uuid, clustering3 uuid …., PRIMARY KEY(partition, clustering1, clustering2, clustering3)); La clause « IN » SELECT … WHERE clustering1 = #c1 AND clustering2 IN (#c21, #c22, …) SELECT … WHERE clustering1 = #c1 AND clustering2 = #c2 AND clustering3 IN (#c31, #c32, …) SELECT … WHERE clustering1 = #c1 AND clustering2 IN (#c21, #c22, …) AND clustering3 = #c3
  135. 135. @doanduyhai#C*ModelisationAvancee 135 Comment ça marche ? → multiget ! La clause « IN »
  136. 136. @doanduyhai#C*ModelisationAvancee 136 Comment ça marche ? → multiget ! Combinaison linéaire  (#p1, #p21) && (#p1, #p22) La clause « IN » SELECT * FROM xxx WHERE partition1 = #p1 AND partition2 IN (#p21, #p22, …)
  137. 137. @doanduyhai#C*ModelisationAvancee Wide rows et « bucketing » Lignes trop larges  limite physique 2.109  hot-spots si nb #partition « nb #col  réparation coûteuse → 1colonne diffère, toute la ligne réparée 137
  138. 138. @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
  139. 139. @doanduyhai#C*ModelisationAvancee Démo cqlsh: « metrics_annee », « metrics_mois »
  140. 140. @doanduyhai#C*ModelisationAvancee Wide rows et « bucketing » Requêtes inter-partition  toutes les métriques CPU entre 25 Janvier et 10 Février ? CREATE TABLE metrics_mois ( type text, mois int, date timestamp, valeur double, PRIMARY KEY ((type, mois), date)) ; 140
  141. 141. @doanduyhai#C*ModelisationAvancee Wide rows et « bucketing » Requêtes inter-partition  toutes les métriques CPU entre 25 Janvier et 10 Février ? CREATE TABLE metrics_mois ( type text, mois int, date timestamp, valeur double, PRIMARY KEY ((type, mois), date)) ; SELECT * FROM metrics_mois WHERE type = ‘CPU’ AND mois IN (201401, 201402) AND date>=‘2014-01-25 00:00:00+0100’ AND date<=‘2014-02-10 00:00:00+0100’; 141
  142. 142. @doanduyhai#C*ModelisationAvancee Wide rows et « bucketing » Implémentation par multiget SELECT * FROM metrics_mois WHERE type = ‘CPU’ AND mois = 201401 AND date>=‘2014-01-25 00:00:00+0100’ AND date<=‘2014-02-10 00:00:00+0100’ && SELECT * FROM metrics_mois WHERE type = ‘CPU’ AND mois = 201402 AND date>=‘2014-01-25 00:00:00+0100’ AND date<=‘2014-02-10 00:00:00+0100’ 142
  143. 143. @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
  144. 144. @doanduyhai#C*ModelisationAvancee Wide rows et « bucketing » Pré-requis  valeur de #col de croissance monotone entre les partitions  date/timeuuid bons candidats 144
  145. 145. @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
  146. 146. @doanduyhai#C*ModelisationAvancee Q & R  
  147. 147. @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
  148. 148. @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
  149. 149. @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
  150. 150. @doanduyhai#C*ModelisationAvancee Démo cqlsh : « abonnes_telecom », « abonnes_telecom_par_localite »
  151. 151. @doanduyhai#C*ModelisationAvancee Q & R  
  152. 152. @doanduyhai#C*ModelisationAvancee TECHNIQUES DE MODÉLISATION EXOTIQUES Time To Live FTW Timestamp, WTF ? C.A.S. distribué
  153. 153. @doanduyhai#C*ModelisationAvancee Time To Live En bref  données volatiles/temporaires  seulement sur colonnes  résolution en seconde  expiré côté serveur 153
  154. 154. @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
  155. 155. @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
  156. 156. @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’;
  157. 157. @doanduyhai#C*ModelisationAvancee Time To Live Rate limiting CREATE TABLE rate_limiting ( user_id int, tentative uuid, PRIMARY KEY (user_id, tentative)) ; 157
  158. 158. @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
  159. 159. @doanduyhai#C*ModelisationAvancee Démo Rate Limiting Source: bit.ly/1noCqY1
  160. 160. @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
  161. 161. @doanduyhai#C*ModelisationAvancee Démo Timestamp Barrière d’écriture Source: bit.ly/1noCqY1
  162. 162. @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
  163. 163. @doanduyhai#C*ModelisationAvancee C.A.S. distribué Contrainte d’intégrité UPDATE abonnes SET preferences=… WHERE identifiant=… IF compte_valide=true 163
  164. 164. @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
  165. 165. @doanduyhai#C*ModelisationAvancee Démo cqlsh : « lock »
  166. 166. @doanduyhai#C*ModelisationAvancee Q & R  
  167. 167. @doanduyhai#C*ModelisationAvancee LES ANTI-PATTERNS Queues et suppression Détection de présence/d’absence Read-before-write Row cache
  168. 168. @doanduyhai#C*ModelisationAvancee Queues Implémentation naïve a b c d e Queue FIFO C* a b c d e 168
  169. 169. @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
  170. 170. @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
  171. 171. @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
  172. 172. @doanduyhai#C*ModelisationAvancee Queues Queue FIFO consommée a b c d e a f b c d e f 172
  173. 173. @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
  174. 174. @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
  175. 175. @doanduyhai#C*ModelisationAvancee Queues: solutions Utiliser JMS  best tool for the job !!!! 175
  176. 176. @doanduyhai#C*ModelisationAvancee Queues: solutions Utiliser JMS  best tool for the job !!!! Besoin de distribution ?  Apache Kafka 176
  177. 177. @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
  178. 178. @doanduyhai#C*ModelisationAvancee Queues: accès concurrents Multiple sources sn  ordonner les sources: s1, s2 … sn 178
  179. 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 179
  180. 180. @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
  181. 181. @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
  182. 182. @doanduyhai#C*ModelisationAvancee Queues: accès concurrents Multiple consommateurs cn  idem 182
  183. 183. @doanduyhai#C*ModelisationAvancee Queues: accès concurrents Rollback  pas de suppression !!! cm remet messages dans #bucketm+? futur → comptage faussé pour cm+? 183
  184. 184. @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 … … … … … … … … … …
  185. 185. @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
  186. 186. @doanduyhai#C*ModelisationAvancee Détection de présence/d’absence 186
  187. 187. @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
  188. 188. @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
  189. 189. @doanduyhai#C*ModelisationAvancee Mémoire Off-Heap Disque Row Cache Mémoire JVM Heap Bloom Filter  Partition Key Cache Compression offset Key Index Sample4 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
  190. 190. @doanduyhai#C*ModelisationAvancee Détection de présence/d’absence Nouvelle modélisation Nouveau chemin de lecture  Bloom filter en mémoire  partition key cache en mémoire  accès disque SSTable en cas de faux positif CREATE TABLE user_token ( user_id int, token uuid, PRIMARY KEY((user_id, token))) ; 190
  191. 191. @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
  192. 192. @doanduyhai#C*ModelisationAvancee Row cache Use-cases  données référentielles  taille raisonnable  partitions accédées très fréquemment 192
  193. 193. @doanduyhai#C*ModelisationAvancee Row cache Use-cases  données référentielles  taille raisonnable  partitions accédées très fréquemment Important  monitoring nécessaire du hit rate & de la taille des données !!!  coût de la sérialisation/dé-sérialisation (off-heap) 193
  194. 194. @doanduyhai#C*ModelisationAvancee Q & R  
  195. 195. @doanduyhai#C*ModelisationAvancee LES INDEX SECONDAIRES Implémentation Use-cases recommandés Retour d’expérience
  196. 196. @doanduyhai#C*ModelisationAvancee Implémentation Naïve CREATE TABLE user_par_pays ( pays text, user_id int, PRIMARY KEY(pays, user_id)) ; 196
  197. 197. @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
  198. 198. @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
  199. 199. @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
  200. 200. @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
  201. 201. @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
  202. 202. @doanduyhai#C*ModelisationAvancee Use-cases recommandés Bon candidats  peu de valeurs indexées # (mais assez quand même) 202
  203. 203. @doanduyhai#C*ModelisationAvancee Use-cases recommandés Bon candidats  peu de valeurs indexées # (mais assez quand même) Mauvais candidats  très peu de valeurs indexées # (index d’un booléen )  beaucoup de valeurs indexées # (index sur email )  m.a.j./suppression fréquentes  très gros cluster 203
  204. 204. @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
  205. 205. @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
  206. 206. @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
  207. 207. @doanduyhai#C*ModelisationAvancee Q & R  
  208. 208. @doanduyhai#C*ModelisationAvancee <FUTUR> C* Requêtes inter-clustering Colonnes statiques User defined type
  209. 209. @doanduyhai#C*ModelisationAvancee Requêtes inter-clustering (2.0.6) Données CREATE TABLE notes_film ( film_id uuid, note uuid, user_id int, commentaire text, PRIMARY KEY(film_id, note, user_id)); Note User_id Commentaire 1 10 Bla bla bla … … … 1 49 Bla bla bla 1 82 Bla bla bla 2 13 Bla bla bla 2 54 Bla bla bla 3 15 Bla bla bla 11 notes de valeur 1 209
  210. 210. @doanduyhai#C*ModelisationAvancee Requêtes inter-clustering (2.0.6) Pagination par 10  user_id 10 à 49 SELECT * FROM notes_film WHERE film_id=.. AND note=1 LIMIT 10 210 Note User_id Commentaire 1 10 Bla bla bla … … … 1 49 Bla bla bla 1 82 Bla bla bla 2 13 Bla bla bla 2 54 Bla bla bla 3 15 Bla bla bla 11 notes de valeur 1
  211. 211. @doanduyhai#C*ModelisationAvancee Requêtes inter-clustering (2.0.6) Deuxième page  user_id 82 SELECT * FROM notes_film WHERE film_id=.. AND note=1 AND user_id>49 LIMIT 10 211 Note User_id Commentaire 1 10 Bla bla bla … … … 1 49 Bla bla bla 1 82 Bla bla bla 2 13 Bla bla bla 2 54 Bla bla bla 3 15 Bla bla bla 11 notes de valeur 1
  212. 212. @doanduyhai#C*ModelisationAvancee Requêtes inter-clustering (2.0.6) Solution naïve (à la SQL) SELECT * FROM notes_film WHERE film_id=.. AND note≥1 AND user_id>49 LIMIT 10 212 Note User_id Commentaire 1 10 Bla bla bla … … … 1 49 Bla bla bla 1 82 Bla bla bla 2 13 Bla bla bla 2 54 Bla bla bla 3 15 Bla bla bla
  213. 213. @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
  214. 214. @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
  215. 215. @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
  216. 216. @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
  217. 217. @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
  218. 218. @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
  219. 219. @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
  220. 220. @doanduyhai#C*ModelisationAvancee User defined type (2.1) CREATE TABLE commentaires ( article_id int, date_creation timestamp, auteur user, contenu text, PRIMARY KEY (article_id, date_creation)); CREATE TYPE user ( id int, nom text, adresse text, bio text); 220
  221. 221. @doanduyhai#C*ModelisationAvancee User defined type (2.1) Syntaxe INSERT INTO commentaires(article_id,date_creation,auteur,contenu) VALUES( 10, 2014-04-16 10:00:00+0100, { id: 156, nom: ‘Pierre DUPOND’, adresse: ‘12 rue de la Paix 75016 PARIS’, bio: ‘Je suis un habitant du 16ème…’ }, ‘Cet article a trop de fautes d’orthographe…’); 221
  222. 222. @doanduyhai#C*ModelisationAvancee User defined type (2.1) Imbrication arbitraire CREATE TYPE user ( id int, nom text, adresse location, bio text); CREATE TYPE location ( numero int, voie text, code_postal int, ville text); 222
  223. 223. @doanduyhai#C*ModelisationAvancee User defined type (2.1) Limitations  modifications non atomiques  lecture eager  ALTER TYPE ADD, ALTER TYPE RENAME 223
  224. 224. @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
  225. 225. @doanduyhai#C*ModelisationAvancee User defined type (2.1) Colonnes d’agrégation (clustering)  tri → ordre du type des champs déclarés Collections & Maps  unicité → comparaison des champs déclarés dans l’ordre 225
  226. 226. @doanduyhai#C*ModelisationAvancee MERCI ! @doanduyhai doanduyhai@gmail.com doanduyhai

×