Un cache en mémoire rapide, concurrent et expulsant écrit pour garder un grand nombre d'entrées sans impact sur les performances. BigCache conserve des entrées sur le tas mais omet GC pour eux. Pour y parvenir, les opérations sur des tranches d'octets ont lieu, donc les entrées (DE) sérialisation devant le cache seront nécessaires dans la plupart des cas d'utilisation.
Nécessite GO 1.12 ou plus récent.
import (
"fmt"
"context"
"github.com/allegro/bigcache/v3"
)
cache , _ := bigcache . New ( context . Background (), bigcache . DefaultConfig ( 10 * time . Minute ))
cache . Set ( "my-unique-key" , [] byte ( "value" ))
entry , _ := cache . Get ( "my-unique-key" )
fmt . Println ( string ( entry ))Lorsque la charge du cache peut être prédite à l'avance, il est préférable d'utiliser l'initialisation personnalisée car une allocation de mémoire supplémentaire peut être évitée de cette manière.
import (
"log"
"github.com/allegro/bigcache/v3"
)
config := bigcache. Config {
// number of shards (must be a power of 2)
Shards : 1024 ,
// time after which entry can be evicted
LifeWindow : 10 * time . Minute ,
// Interval between removing expired entries (clean up).
// If set to <= 0 then no action is performed.
// Setting to < 1 second is counterproductive — bigcache has a one second resolution.
CleanWindow : 5 * time . Minute ,
// rps * lifeWindow, used only in initial memory allocation
MaxEntriesInWindow : 1000 * 10 * 60 ,
// max entry size in bytes, used only in initial memory allocation
MaxEntrySize : 500 ,
// prints information about additional memory allocation
Verbose : true ,
// cache will not allocate more memory than this limit, value in MB
// if value is reached then the oldest entries can be overridden for the new ones
// 0 value means no size limit
HardMaxCacheSize : 8192 ,
// callback fired when the oldest entry is removed because of its expiration time or no space left
// for the new entry, or because delete was called. A bitmask representing the reason will be returned.
// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
OnRemove : nil ,
// OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left
// for the new entry, or because delete was called. A constant representing the reason will be passed through.
// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
// Ignored if OnRemove is specified.
OnRemoveWithReason : nil ,
}
cache , initErr := bigcache . New ( context . Background (), config )
if initErr != nil {
log . Fatal ( initErr )
}
cache . Set ( "my-unique-key" , [] byte ( "value" ))
if entry , err := cache . Get ( "my-unique-key" ); err == nil {
fmt . Println ( string ( entry ))
}LifeWindow & CleanWindow LifeWindow est un moment. Après ce temps, une entrée peut être appelée morte mais non supprimée.
CleanWindow est un moment. Après ce temps, toutes les entrées mortes seront supprimées, mais pas les entrées qui ont encore la vie.
Trois caches ont été comparées: BigCache, FreeCache et Map. Des tests de référence ont été effectués à l'aide d'un CPU i7-6700K @ 4,00 GHz avec 32 Go de RAM sur Ubuntu 18.04 LTS (5.2.12-050212-générique).
Le code source de repères peut être trouvé ici
go version
go version go1.13 linux/amd64
go test -bench=. -benchmem -benchtime=4s ./... -timeout 30m
goos: linux
goarch: amd64
pkg: github.com/allegro/bigcache/v3/caches_bench
BenchmarkMapSet-8 12999889 376 ns/op 199 B/op 3 allocs/op
BenchmarkConcurrentMapSet-8 4355726 1275 ns/op 337 B/op 8 allocs/op
BenchmarkFreeCacheSet-8 11068976 703 ns/op 328 B/op 2 allocs/op
BenchmarkBigCacheSet-8 10183717 478 ns/op 304 B/op 2 allocs/op
BenchmarkMapGet-8 16536015 324 ns/op 23 B/op 1 allocs/op
BenchmarkConcurrentMapGet-8 13165708 401 ns/op 24 B/op 2 allocs/op
BenchmarkFreeCacheGet-8 10137682 690 ns/op 136 B/op 2 allocs/op
BenchmarkBigCacheGet-8 11423854 450 ns/op 152 B/op 4 allocs/op
BenchmarkBigCacheSetParallel-8 34233472 148 ns/op 317 B/op 3 allocs/op
BenchmarkFreeCacheSetParallel-8 34222654 268 ns/op 350 B/op 3 allocs/op
BenchmarkConcurrentMapSetParallel-8 19635688 240 ns/op 200 B/op 6 allocs/op
BenchmarkBigCacheGetParallel-8 60547064 86.1 ns/op 152 B/op 4 allocs/op
BenchmarkFreeCacheGetParallel-8 50701280 147 ns/op 136 B/op 3 allocs/op
BenchmarkConcurrentMapGetParallel-8 27353288 175 ns/op 24 B/op 2 allocs/op
PASS
ok github.com/allegro/bigcache/v3/caches_bench 256.257sLes écritures et les lectures dans BigCache sont plus rapides qu'en freecache. Les écritures pour mapper sont les plus lentes.
go version
go version go1.13 linux/amd64
go run caches_gc_overhead_comparison.go
Number of entries: 20000000
GC pause for bigcache: 1.506077ms
GC pause for freecache: 5.594416ms
GC pause for map: 9.347015ms go version
go version go1.13 linux/arm64
go run caches_gc_overhead_comparison.go
Number of entries: 20000000
GC pause for bigcache: 22.382827ms
GC pause for freecache: 41.264651ms
GC pause for map: 72.236853ms
Le test montre combien de temps sont les pauses GC pour les caches remplies de 20 mln d'entrées. BigCache et FreeCache ont un temps de pause GC très similaire.
Vous pouvez rencontrer la mémoire du système signalant ce qui semble être une augmentation exponentielle, mais ce comportement est attendu. GO Runtime alloue la mémoire en morceaux ou «des portes» et informera le système d'exploitation lorsqu'ils ne sont plus requis en modifiant leur état en «inactif». Les «portées» resteront dans le cadre de l'utilisation des ressources de processus jusqu'à ce que le système d'exploitation doit réutiliser l'adresse. Lecture complémentaire disponible ici.
BigCache s'appuie sur l'optimisation présentée dans la version 1.5 de GO (numéro-9477). Cette optimisation indique que si la carte sans pointeurs dans les clés et les valeurs est utilisée, GC omettra son contenu. Par conséquent, BigCache utilise map[uint64]uint32 où les clés sont hachées et les valeurs sont des compensations des entrées.
Les inscriptions sont conservées en tranches d'octets, pour omettre à nouveau GC. La taille des tranches d'octets peut se développer en gigaoctets sans impact sur les performances car GC ne verra que le pointeur unique.
BigCache ne gère pas les collisions. Lorsque un nouvel élément est inséré et qu'il est en collision avec un élément précédemment stocké, un nouvel élément écrase la valeur précédemment stockée.
Les deux caches offrent les mêmes caractéristiques de base, mais elles réduisent les frais généraux GC de différentes manières. BigCache s'appuie sur map[uint64]uint32 , FreeCache implémente sa propre cartographie construite sur des tranches pour réduire le nombre de pointeurs.
Les résultats des tests de référence sont présentés ci-dessus. L'un des avantages de BigCache sur FreeCache est que vous n'avez pas besoin de connaître la taille du cache à l'avance, car lorsque BigCache est plein, il peut allouer de la mémoire supplémentaire pour de nouvelles entrées au lieu d'écraser les existants comme FreeCache le fait actuellement. Cependant, la taille maximale dure dans BigCache peut également être définie, vérifiez HardMaxCacheSize.
Ce package comprend également une implémentation HTTP facilement déployable de BigCache, qui peut être trouvée dans le package de serveur.
BigCache Genesis est décrit dans Allegro.Tech Blog Blog: Rédaction d'un service de cache très rapide en Go
BigCache est libéré sous la licence Apache 2.0 (voir licence)