SlideShare une entreprise Scribd logo
1  sur  34
Télécharger pour lire hors ligne
50 AVENUE DES CHAMPS-ÉLYSÉES 75008 PARIS > FRANCE > WWW.OCTO.COM
Implementing a Key / Value Store
BluckDB
BJC - BOF - 15/12/16
github.com/BenJoyenConseil/bluckdb
@BenJoyeConseil
Pourquoi ...
◉ Comprendre les mécanismes des bases modernes
◉ Explorer les algos et les structures de donnée
◉ Faire du “bas niveau”
◉ Apprendre Go
◉ Ne pas être à poils lors de la formation HBase
Réinventer la roue ?
>01 Situer le kv store
Souvent présenté comme ça
Storage engine !
◉ LevelDB (LSM-Tree)
◉ RocksDB (LSM-Tree)
◉ WiredTiger (LSM-Tree)
◉ ForestDB (HB+Trie)
◉ InnoDB (B+Tree)
◉ BoltDB (B+Tree)
◉ Kyoto Cabinet (Hashtable)
◉ BluckDB (Hashtable)
◉ ...
database
Exemples de KV store comme moteur de stockage
LevelDB ... InnoDB
Server
MongoDB / MySQL / Riak / Lucene / ...
File system
Cockroachdb utilise RocksDB comme moteur de stockage
Quotable quote
All models are wrong but some are useful
— George Box
Models
>02 Deep Dive
Le design
1. Data storage abstraction
2. Data structure (index)
3. Memory management (page / block management, free space)
4. String / byte slice
5. Iterator / Cursor
6. Lock management
7. Comparator
Top 7 des composants dans un kv store (ref : article topito)
L’interface
type KVStore interface {
Get(k string) string
Put(k, v string)
Delete(k string)
}
First implem’
◉ Simple hashmap (separate chaining)
◉ Persistent store :
> Put -> append to file
> Get -> foreach line, split(‘:’)
MVP
bucket files (fixed number)
hash(k) % numBucket (static hashing)
File bucket 1
File bucket 2
File bucket 3 append
hash(k) % 3
First implem’
◉ Benchmarks persistent store
BenchmarkPutNaiveDiskKVStore-4 200000 6250 ns/op -> 6,2 µs
BenchmarkGetNaiveDiskKVStore-4 30 44017416 ns/op -> 44 ms
◉ Benchmarks in-memory hashmap
BenchmarkPutHashMap-4 1000000 1385 ns/op -> 1,3 µs
BenchmarkGetHashMap-4 2000000 711 ns/op -> 0,7 µs
MVP
Quotable quote
There’s clearly a trade-off between reads and writes, and it’s the mixing of
the two that causes all of the interesting challenges
— Adrian Colyer
>03 Ok, on fait un vrai design maintenant ?
Hashtables are arguably the single most important data structure known
to mankind.
— Steve Yegge
Le design
1. Data storage abstraction -> SSD Page 4k + Record
2. Data structure (index) -> Hashtable (extendible hash)
3. Memory management (page / block management, free space) -> mmap + custom
4. String / byte slice -> Go string native conv to []byte slice
5. Iterator / Cursor -> Pattern iterator
6. Lock management -> à l’extérieur
7. Comparator -> multi-level comparator (key length > hash > byte)
Top 7 des composants dans un kv store (ref : article topito)
Record layout
type Record interface {
key() []byte
val() []byte
valLen() uint16 // min 0
keyLen() uint16 // max 65536
}
type ByteRecord []byte
r := ByteRecord(byteArray[204 : 249])
overhead : 4 bytes
Record layout
func (r ByteRecord) Write(key, val string) {
...
copy( r[ : ], key)
copy( r[ lenKey : ], val )
binary.LittleEndian.PutUint16( r[ total : ], lenVal )
binary.LittleEndian.PutUint16( r[ total + RECORD_HEADER_SIZE : ], lenKey )
}
serialization
... k e y v a l u e 0x5 0x0 0x3 0x0 ...
Page layout
type Page []byte
const (
PAGE_SIZE = 4096
PAGE_USE_OFFSET = 4094
PAGE_LOCAL_DEPTH_OFFSET = 4092
)
func (p Page) Use() int {
return int( binary.LittleEndian.Uint16( p[PAGE_USE_OFFSET : ] ) )
}
...
Record1 Record2 Record3 Record1 v2 LD USE
Extendible Hashing algorithm
dynamic hashing
◉ Une fonction de Hash qui génère des résultats sur un large segment — typiquement un int32
◉ Préfixe du résultat de la fonction de Hash pour calculer l’indice dans la table d’adresse.
◉ Plusieurs entrées dans la table d’adresse peuvent pointer sur la même page
Extendible Hashing algorithm
p0
p0
p1
p2
..00
..01
..10
..11
...0100 key, value
...1101 key, value
ld=1
GD=2
...0110 key, value
...1110 key, value
...0111 key, value
...1011 key, value
ld=2
ld=2
page 1
page 2
page 3
Page
addresses
Extendible Hashing algorithm
Après le split
p0
p4
p1
p2
..00
..01
..10
..11
...0100 key, value
ld=2
GD=2
...0110 key, value
...1110 key, value
...0111 key, value
...1011 key, value
ld=2
ld=2
page 1
page 2
page 3
Page
addresses
...1101 key, value
ld=2
page 4
Extendible Hashing algorithm
Après le expand
p0
p4
p1
p2
p0
p4
p1
p2
.000
.001
.010
.011
.100
.101
.110
.111
...0100 key, value
ld=2
GD=3
...0110 key, value
...1110 key, value
...0111 key, value
...1011 key, value
ld=2
ld=2
page 1
page 2
page 3
...1101 key, value
ld=2
page 4
Directory layout
func (dir *Directory) extendibleHash(k util.Hashable) int {
return k.Hash() & ((1 << dir.Gd) - 1)
}
func (dir *Directory) getPage(k string) (Page) {
hash := dir.extendibleHash(util.Key(k))
id := dir.Table[hash]
offset := id * PAGE_SIZE
return Page(dir.data[offset : offset + PAGE_SIZE])
}
dir := &Directory{
Table: []int{0, 1, 3, 2, 0, 1, 3, 2},
Gd: 2,
LastPageId: 3,
data: []byte{...},
}
Mmap
Core
Data Storage
Memory Management
Design
Bluck server
http.Listen
Bluckstore
open()
close()
Directory
Mmap
persistMeta()
KVStore
Get(k)
Put(k,v)
Delete(k)
Page
GC()
ld()
Lock Management
RWMutex
File
Record
Write()
Iterator
>04 On parle des perf ?
Memory maps are the best thing known to mankind after hash tables.
— Emmanuel Goossaert
Memory mapping
◉ Mmap file -> []byte
> 0 copy, pas de passage de user space à kernel space
> Pas de buffer à gérer pour le flush
> Pas de block cache
◉ Pré-allocation des pages pour accélérer mmap
Optims
Chronologie des évolutions
Les benchmarks (Go)
Get Put
Mmap 2344 5452
Update 2881 10532
Iterator 8796 11102
ByteRecord 1819 9982
GOB serde 1874 3206
Reverse 1406 1529
Flush Meta 1398 2786
Pre
allocation
1408 1359
Les fonctionnalités qui font tout PÉTER !!!
◉ Update (in place ?)
◉ Metadata (consistency)
◉ Delete (shift? scan ?)
◉ Concurrency & Isolation
◉ Big record
$ go tool pprof
Avant :
Benchmark => itérations : 200.000 8796 ns/op 3376 B/op 106 allocs/op
(pprof) top10
1590ms of 1890ms total (84.13%)
Showing top 10 nodes out of 77 (cum >= 50ms)
flat flat% sum% cum cum%
500ms 26.46% 26.46% 920ms 48.68% runtime.mallocgc
260ms 13.76% 40.21% 260ms 13.76% runtime.heapBitsSetType
140ms 7.41% 47.62% 1630ms 86.24% github.com/BenJoyenConseil/bluckdb/bluckstore/mmap.Page.get
140ms 7.41% 55.03% 1430ms 75.66% runtime.convT2I
120ms 6.35% 61.38% 120ms 6.35% runtime.memclr
120ms 6.35% 67.72% 120ms 6.35% runtime.memmove
cpu
$ go tool pprof
Après :
Benchmark => itérations : 2.000.000 756 ns/op 16 B/op 1 allocs/op
(pprof) top10
2.33s of 2.36s total (98.73%)
Dropped 9 nodes (cum <= 0.01s)
Showing top 10 nodes out of 12 (cum >= 2.36s)
flat flat% sum% cum cum%
2.21s 93.64% 93.64% 2.33s 98.73% github.com/BenJoyenConseil/bluckdb/bluckstore/mmap.Page.get
0.06s 2.54% 96.19% 0.11s 4.66% runtime.mallocgc
0.03s 1.27% 97.46% 0.03s 1.27% runtime.heapBitsSetType
0.02s 0.85% 98.31% 0.02s 0.85% runtime.scanobject
0.01s 0.42% 98.73% 0.12s 5.08% runtime.newobject
cpu
Recap des compromis
◉ Mmap avec pré-allocation des pages : supprimer des enregistrements ne libère
pas l’espace disque
◉ Extendible Hashing & hashtable : performance pour l’accès, mais la persistance
des meta appart est très coûteuse et risquée (d’un point de vue cohérence)
◉ Delete : marquer les kv comme “deleted” augmente fortement le phénomène Write
Amplification versus shifting déplace beaucoup de données
◉ Update : “in place” il faut gérer la défragmentation versus append only il faut faire
du GC
◉ Concurrence : faire un hashtable threadsafe complexifie beaucoup le code (Mutex)
Recap des compromis
◉ La structure de donnée (Hashtable, LSM-Tree, B+Tree, Trie, etc...) définit le(s)
compromis
> Latence lecture
> Latence écriture
> Range scan
> Degré d’isolation
> Cohérence
> Haute dispo
◉ Choisissez !!
BluckDB
github.com/BenJoyenConseil/bluckdb
@BenJoyeConseil
Fork it

Contenu connexe

Tendances

Presentation langage go_19022015
Presentation langage go_19022015Presentation langage go_19022015
Presentation langage go_19022015Stéphane Legrand
 
DNS sous linux
DNS sous linuxDNS sous linux
DNS sous linuxSouhaib El
 
Stockage et hashage des mots de passe
Stockage et hashage des mots de passeStockage et hashage des mots de passe
Stockage et hashage des mots de passeThomas P
 
PHPTour 2011 - PHP5.4
PHPTour 2011 - PHP5.4PHPTour 2011 - PHP5.4
PHPTour 2011 - PHP5.4julien pauli
 
Gestion des logs sur une plateforme web
Gestion des logs sur une plateforme webGestion des logs sur une plateforme web
Gestion des logs sur une plateforme webfredcons
 
Nouveautés PHP 7 : Introduction et performances - MeetUP Openska
Nouveautés PHP 7 : Introduction et performances - MeetUP OpenskaNouveautés PHP 7 : Introduction et performances - MeetUP Openska
Nouveautés PHP 7 : Introduction et performances - MeetUP OpenskaOpenska
 
Initiation au php
Initiation au phpInitiation au php
Initiation au phpStrasWeb
 
ZendFramework2 - Présentation
ZendFramework2 - PrésentationZendFramework2 - Présentation
ZendFramework2 - Présentationjulien pauli
 
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...Tarik Zakaria Benmerar
 
Nouveautés dans TYPO3 CMS 6.0
Nouveautés dans TYPO3 CMS 6.0Nouveautés dans TYPO3 CMS 6.0
Nouveautés dans TYPO3 CMS 6.0Idéative
 
Coffee script
Coffee scriptCoffee script
Coffee scriptantho1404
 
Javascript les générateurs (generators)
Javascript   les générateurs (generators)Javascript   les générateurs (generators)
Javascript les générateurs (generators)Julien CROUZET
 
Formation Linux lpi 101
Formation Linux lpi 101 Formation Linux lpi 101
Formation Linux lpi 101 Kais Baccour
 
Analyse de données JSON dans Openrefine
Analyse de données JSON dans OpenrefineAnalyse de données JSON dans Openrefine
Analyse de données JSON dans OpenrefineMathieu Saby
 

Tendances (20)

Presentation langage go_19022015
Presentation langage go_19022015Presentation langage go_19022015
Presentation langage go_19022015
 
DNS sous linux
DNS sous linuxDNS sous linux
DNS sous linux
 
PostgreSQL Meetup Nantes #2
PostgreSQL Meetup Nantes #2PostgreSQL Meetup Nantes #2
PostgreSQL Meetup Nantes #2
 
Linux Administrateur
Linux AdministrateurLinux Administrateur
Linux Administrateur
 
Stockage et hashage des mots de passe
Stockage et hashage des mots de passeStockage et hashage des mots de passe
Stockage et hashage des mots de passe
 
PHPTour 2011 - PHP5.4
PHPTour 2011 - PHP5.4PHPTour 2011 - PHP5.4
PHPTour 2011 - PHP5.4
 
Gestion des logs sur une plateforme web
Gestion des logs sur une plateforme webGestion des logs sur une plateforme web
Gestion des logs sur une plateforme web
 
Nouveautés PHP 7 : Introduction et performances - MeetUP Openska
Nouveautés PHP 7 : Introduction et performances - MeetUP OpenskaNouveautés PHP 7 : Introduction et performances - MeetUP Openska
Nouveautés PHP 7 : Introduction et performances - MeetUP Openska
 
Shell
ShellShell
Shell
 
Initiation au php
Initiation au phpInitiation au php
Initiation au php
 
Initiation au php
Initiation au phpInitiation au php
Initiation au php
 
ZendFramework2 - Présentation
ZendFramework2 - PrésentationZendFramework2 - Présentation
ZendFramework2 - Présentation
 
My sql console
My sql consoleMy sql console
My sql console
 
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...
Manipulation des images IRM sur navigateur - Informatique Humaine et Médicale...
 
Nouveautés dans TYPO3 CMS 6.0
Nouveautés dans TYPO3 CMS 6.0Nouveautés dans TYPO3 CMS 6.0
Nouveautés dans TYPO3 CMS 6.0
 
Coffee script
Coffee scriptCoffee script
Coffee script
 
Javascript les générateurs (generators)
Javascript   les générateurs (generators)Javascript   les générateurs (generators)
Javascript les générateurs (generators)
 
Formation Linux lpi 101
Formation Linux lpi 101 Formation Linux lpi 101
Formation Linux lpi 101
 
Analyse de données JSON dans Openrefine
Analyse de données JSON dans OpenrefineAnalyse de données JSON dans Openrefine
Analyse de données JSON dans Openrefine
 
Google Developer Group (GDG) Aix-Marseille #1 (27/08/2018)
Google Developer Group (GDG) Aix-Marseille #1 (27/08/2018)Google Developer Group (GDG) Aix-Marseille #1 (27/08/2018)
Google Developer Group (GDG) Aix-Marseille #1 (27/08/2018)
 

Similaire à Implementing a key/value store

Les secrets de la JVM pour les algos à haute fréquence
Les secrets de la JVM pour les algos à haute fréquenceLes secrets de la JVM pour les algos à haute fréquence
Les secrets de la JVM pour les algos à haute fréquenceOCTO Technology
 
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -intro
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -introNosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -intro
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -introOlivier Mallassi
 
Spark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystSpark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystMathieu Goeminne
 
SSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLSSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLHervé Leclerc
 
Ingénierie de la performance au sein des mégadonnées
Ingénierie de la performance au sein des mégadonnéesIngénierie de la performance au sein des mégadonnées
Ingénierie de la performance au sein des mégadonnéesDaniel Lemire
 
Réu technodejs
Réu technodejsRéu technodejs
Réu technodejsnaholyr
 
gRPC, échange à haute fréquence !
gRPC, échange à haute fréquence !gRPC, échange à haute fréquence !
gRPC, échange à haute fréquence !David Caramelo
 
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018Carles Sistare
 
Performance et optimisation de PrestaShop
Performance et optimisation de PrestaShopPerformance et optimisation de PrestaShop
Performance et optimisation de PrestaShopPrestaShop
 
Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Dr Samir A. ROUABHI
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016Antoine Rey
 
Découverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanDécouverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanMicrosoft
 
Mat lab1
Mat lab1Mat lab1
Mat lab1fouadDD
 

Similaire à Implementing a key/value store (20)

Les secrets de la JVM pour les algos à haute fréquence
Les secrets de la JVM pour les algos à haute fréquenceLes secrets de la JVM pour les algos à haute fréquence
Les secrets de la JVM pour les algos à haute fréquence
 
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -intro
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -introNosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -intro
Nosql, hadoop, map reduce, hbase, sqoop, voldemort, cassandra -intro
 
Spark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et CatalystSpark - au dela du dataframe avec Tungsten et Catalyst
Spark - au dela du dataframe avec Tungsten et Catalyst
 
SSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQLSSL 2011 : Présentation de 2 bases noSQL
SSL 2011 : Présentation de 2 bases noSQL
 
Cours php
Cours phpCours php
Cours php
 
Ingénierie de la performance au sein des mégadonnées
Ingénierie de la performance au sein des mégadonnéesIngénierie de la performance au sein des mégadonnées
Ingénierie de la performance au sein des mégadonnées
 
mix-it 2011
mix-it 2011mix-it 2011
mix-it 2011
 
Réu technodejs
Réu technodejsRéu technodejs
Réu technodejs
 
gRPC, échange à haute fréquence !
gRPC, échange à haute fréquence !gRPC, échange à haute fréquence !
gRPC, échange à haute fréquence !
 
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018
gRPC, ECHANGES A HAUTE FREQUENCE ! DEVOXX 2018
 
Compte rendu Blend Web Mix 2015
Compte rendu Blend Web Mix 2015Compte rendu Blend Web Mix 2015
Compte rendu Blend Web Mix 2015
 
Vert.x 3
Vert.x 3Vert.x 3
Vert.x 3
 
Performance et optimisation de PrestaShop
Performance et optimisation de PrestaShopPerformance et optimisation de PrestaShop
Performance et optimisation de PrestaShop
 
Cours php bac info
Cours php bac infoCours php bac info
Cours php bac info
 
Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)Présentation Javascript à l'ESI (Alger)
Présentation Javascript à l'ESI (Alger)
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016
 
Découverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet SpartanDécouverte du moteur de rendu du projet Spartan
Découverte du moteur de rendu du projet Spartan
 
Cours de Matlab
Cours de MatlabCours de Matlab
Cours de Matlab
 
Mat lab1
Mat lab1Mat lab1
Mat lab1
 
Paris RailsCamp 2009
Paris RailsCamp 2009Paris RailsCamp 2009
Paris RailsCamp 2009
 

Implementing a key/value store

  • 1. 50 AVENUE DES CHAMPS-ÉLYSÉES 75008 PARIS > FRANCE > WWW.OCTO.COM Implementing a Key / Value Store BluckDB BJC - BOF - 15/12/16 github.com/BenJoyenConseil/bluckdb @BenJoyeConseil
  • 2. Pourquoi ... ◉ Comprendre les mécanismes des bases modernes ◉ Explorer les algos et les structures de donnée ◉ Faire du “bas niveau” ◉ Apprendre Go ◉ Ne pas être à poils lors de la formation HBase Réinventer la roue ?
  • 3. >01 Situer le kv store
  • 4. Souvent présenté comme ça Storage engine !
  • 5. ◉ LevelDB (LSM-Tree) ◉ RocksDB (LSM-Tree) ◉ WiredTiger (LSM-Tree) ◉ ForestDB (HB+Trie) ◉ InnoDB (B+Tree) ◉ BoltDB (B+Tree) ◉ Kyoto Cabinet (Hashtable) ◉ BluckDB (Hashtable) ◉ ... database Exemples de KV store comme moteur de stockage LevelDB ... InnoDB Server MongoDB / MySQL / Riak / Lucene / ... File system
  • 6. Cockroachdb utilise RocksDB comme moteur de stockage
  • 7. Quotable quote All models are wrong but some are useful — George Box Models
  • 8.
  • 10. Le design 1. Data storage abstraction 2. Data structure (index) 3. Memory management (page / block management, free space) 4. String / byte slice 5. Iterator / Cursor 6. Lock management 7. Comparator Top 7 des composants dans un kv store (ref : article topito)
  • 11. L’interface type KVStore interface { Get(k string) string Put(k, v string) Delete(k string) }
  • 12. First implem’ ◉ Simple hashmap (separate chaining) ◉ Persistent store : > Put -> append to file > Get -> foreach line, split(‘:’) MVP bucket files (fixed number) hash(k) % numBucket (static hashing) File bucket 1 File bucket 2 File bucket 3 append hash(k) % 3
  • 13. First implem’ ◉ Benchmarks persistent store BenchmarkPutNaiveDiskKVStore-4 200000 6250 ns/op -> 6,2 µs BenchmarkGetNaiveDiskKVStore-4 30 44017416 ns/op -> 44 ms ◉ Benchmarks in-memory hashmap BenchmarkPutHashMap-4 1000000 1385 ns/op -> 1,3 µs BenchmarkGetHashMap-4 2000000 711 ns/op -> 0,7 µs MVP
  • 14. Quotable quote There’s clearly a trade-off between reads and writes, and it’s the mixing of the two that causes all of the interesting challenges — Adrian Colyer
  • 15. >03 Ok, on fait un vrai design maintenant ? Hashtables are arguably the single most important data structure known to mankind. — Steve Yegge
  • 16. Le design 1. Data storage abstraction -> SSD Page 4k + Record 2. Data structure (index) -> Hashtable (extendible hash) 3. Memory management (page / block management, free space) -> mmap + custom 4. String / byte slice -> Go string native conv to []byte slice 5. Iterator / Cursor -> Pattern iterator 6. Lock management -> à l’extérieur 7. Comparator -> multi-level comparator (key length > hash > byte) Top 7 des composants dans un kv store (ref : article topito)
  • 17. Record layout type Record interface { key() []byte val() []byte valLen() uint16 // min 0 keyLen() uint16 // max 65536 } type ByteRecord []byte r := ByteRecord(byteArray[204 : 249]) overhead : 4 bytes
  • 18. Record layout func (r ByteRecord) Write(key, val string) { ... copy( r[ : ], key) copy( r[ lenKey : ], val ) binary.LittleEndian.PutUint16( r[ total : ], lenVal ) binary.LittleEndian.PutUint16( r[ total + RECORD_HEADER_SIZE : ], lenKey ) } serialization ... k e y v a l u e 0x5 0x0 0x3 0x0 ...
  • 19. Page layout type Page []byte const ( PAGE_SIZE = 4096 PAGE_USE_OFFSET = 4094 PAGE_LOCAL_DEPTH_OFFSET = 4092 ) func (p Page) Use() int { return int( binary.LittleEndian.Uint16( p[PAGE_USE_OFFSET : ] ) ) } ... Record1 Record2 Record3 Record1 v2 LD USE
  • 20. Extendible Hashing algorithm dynamic hashing ◉ Une fonction de Hash qui génère des résultats sur un large segment — typiquement un int32 ◉ Préfixe du résultat de la fonction de Hash pour calculer l’indice dans la table d’adresse. ◉ Plusieurs entrées dans la table d’adresse peuvent pointer sur la même page
  • 21. Extendible Hashing algorithm p0 p0 p1 p2 ..00 ..01 ..10 ..11 ...0100 key, value ...1101 key, value ld=1 GD=2 ...0110 key, value ...1110 key, value ...0111 key, value ...1011 key, value ld=2 ld=2 page 1 page 2 page 3 Page addresses
  • 22. Extendible Hashing algorithm Après le split p0 p4 p1 p2 ..00 ..01 ..10 ..11 ...0100 key, value ld=2 GD=2 ...0110 key, value ...1110 key, value ...0111 key, value ...1011 key, value ld=2 ld=2 page 1 page 2 page 3 Page addresses ...1101 key, value ld=2 page 4
  • 23. Extendible Hashing algorithm Après le expand p0 p4 p1 p2 p0 p4 p1 p2 .000 .001 .010 .011 .100 .101 .110 .111 ...0100 key, value ld=2 GD=3 ...0110 key, value ...1110 key, value ...0111 key, value ...1011 key, value ld=2 ld=2 page 1 page 2 page 3 ...1101 key, value ld=2 page 4
  • 24. Directory layout func (dir *Directory) extendibleHash(k util.Hashable) int { return k.Hash() & ((1 << dir.Gd) - 1) } func (dir *Directory) getPage(k string) (Page) { hash := dir.extendibleHash(util.Key(k)) id := dir.Table[hash] offset := id * PAGE_SIZE return Page(dir.data[offset : offset + PAGE_SIZE]) } dir := &Directory{ Table: []int{0, 1, 3, 2, 0, 1, 3, 2}, Gd: 2, LastPageId: 3, data: []byte{...}, } Mmap
  • 25. Core Data Storage Memory Management Design Bluck server http.Listen Bluckstore open() close() Directory Mmap persistMeta() KVStore Get(k) Put(k,v) Delete(k) Page GC() ld() Lock Management RWMutex File Record Write() Iterator
  • 26. >04 On parle des perf ? Memory maps are the best thing known to mankind after hash tables. — Emmanuel Goossaert
  • 27. Memory mapping ◉ Mmap file -> []byte > 0 copy, pas de passage de user space à kernel space > Pas de buffer à gérer pour le flush > Pas de block cache ◉ Pré-allocation des pages pour accélérer mmap Optims
  • 28. Chronologie des évolutions Les benchmarks (Go) Get Put Mmap 2344 5452 Update 2881 10532 Iterator 8796 11102 ByteRecord 1819 9982 GOB serde 1874 3206 Reverse 1406 1529 Flush Meta 1398 2786 Pre allocation 1408 1359
  • 29. Les fonctionnalités qui font tout PÉTER !!! ◉ Update (in place ?) ◉ Metadata (consistency) ◉ Delete (shift? scan ?) ◉ Concurrency & Isolation ◉ Big record
  • 30. $ go tool pprof Avant : Benchmark => itérations : 200.000 8796 ns/op 3376 B/op 106 allocs/op (pprof) top10 1590ms of 1890ms total (84.13%) Showing top 10 nodes out of 77 (cum >= 50ms) flat flat% sum% cum cum% 500ms 26.46% 26.46% 920ms 48.68% runtime.mallocgc 260ms 13.76% 40.21% 260ms 13.76% runtime.heapBitsSetType 140ms 7.41% 47.62% 1630ms 86.24% github.com/BenJoyenConseil/bluckdb/bluckstore/mmap.Page.get 140ms 7.41% 55.03% 1430ms 75.66% runtime.convT2I 120ms 6.35% 61.38% 120ms 6.35% runtime.memclr 120ms 6.35% 67.72% 120ms 6.35% runtime.memmove cpu
  • 31. $ go tool pprof Après : Benchmark => itérations : 2.000.000 756 ns/op 16 B/op 1 allocs/op (pprof) top10 2.33s of 2.36s total (98.73%) Dropped 9 nodes (cum <= 0.01s) Showing top 10 nodes out of 12 (cum >= 2.36s) flat flat% sum% cum cum% 2.21s 93.64% 93.64% 2.33s 98.73% github.com/BenJoyenConseil/bluckdb/bluckstore/mmap.Page.get 0.06s 2.54% 96.19% 0.11s 4.66% runtime.mallocgc 0.03s 1.27% 97.46% 0.03s 1.27% runtime.heapBitsSetType 0.02s 0.85% 98.31% 0.02s 0.85% runtime.scanobject 0.01s 0.42% 98.73% 0.12s 5.08% runtime.newobject cpu
  • 32. Recap des compromis ◉ Mmap avec pré-allocation des pages : supprimer des enregistrements ne libère pas l’espace disque ◉ Extendible Hashing & hashtable : performance pour l’accès, mais la persistance des meta appart est très coûteuse et risquée (d’un point de vue cohérence) ◉ Delete : marquer les kv comme “deleted” augmente fortement le phénomène Write Amplification versus shifting déplace beaucoup de données ◉ Update : “in place” il faut gérer la défragmentation versus append only il faut faire du GC ◉ Concurrence : faire un hashtable threadsafe complexifie beaucoup le code (Mutex)
  • 33. Recap des compromis ◉ La structure de donnée (Hashtable, LSM-Tree, B+Tree, Trie, etc...) définit le(s) compromis > Latence lecture > Latence écriture > Range scan > Degré d’isolation > Cohérence > Haute dispo ◉ Choisissez !!