Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ristretto

Avatar for Viney Viney
October 14, 2019

 Ristretto

Introduce TinyLFU cache mechanism in Go

Avatar for Viney

Viney

October 14, 2019
Tweet

More Decks by Viney

Other Decks in Technology

Transcript

  1. R st et o A g P a , C

    e , M -B c 2 /1 /1 2
  2. W rk ro nd G ou ca he’s RU +

    m te l ck ! 2 /1 /1 4
  3. R st et o B tt r al o E

    pr ss 2 /1 /1 6
  4. R qu re en 4 C e 4 H c

    -h r 4 M -b (l c g a m u ) 4 S l h n c n g n i e 2 /1 /1 7
  5. 4 F A s 4 H C e n C

    i R n 4 M B g 2 /1 /1 9
  6. K y os 4 A i n l c p

    a i b 4 A a s e k -v 4 H e c d e n l i i 2 /1 /1 1
  7. M mo y ou di g A mi si n

    ol cy ia in LF 2 /1 /1 1
  8. C un Mi S et h 4 D p :

    B l 2 /1 /1 1
  9. E ic io P li y ia am le L

    U // Snippet from the Admission and Eviction Algorithm incHits := p.admit.Estimate(key) for ; room < 0; room = p.evict.roomLeft(cost) { sample = p.evict.fillSample(sample) minKey, minHits, minId := uint64(0), int64(math.MaxInt64), 0 for i, pair := range sample { if hits := p.admit.Estimate(pair.key); hits < minHits { minKey, minHits, minId = pair.key, hits, i } } if incHits < minHits { p.stats.Add(rejectSets, key, 1) return victims, false } p.evict.del(minKey) sample[minId] = sample[len(sample)-1] sample = sample[:len(sample)-1] victims = append(victims, minKey) } 2 /1 /1 1
  10. S or 4 D C 4 N t -l s

    G 4 N l s c e h 2 /1 /1 1
  11. S or (c nt.) 4 s .M 4 s m

    -w m 4 2 s 6 -c s 2 /1 /1 1
  12. H sh 4 r .m 4 n -p e c

    . BenchmarkMemHash-32 200000000 8.88 ns/op BenchmarkFarm-32 100000000 17.9 ns/op BenchmarkSip-32 30000000 41.1 ns/op BenchmarkFnv-32 20000000 70.6 ns/op 2 /1 /1 2
  13. H sh (c nt.) 4 s k 4 w s

    h e s i 2 /1 /1 2
  14. b n h p a n s l h c

    a g n 4 B -W 4 p h 4 b g 2 /1 /1 2
  15. G t 4 s , l n b e 4

    s .P 2 /1 /1 2
  16. G t (c nt.) AddToLossyBuffer(key): stripe := b.pool.Get().(*ringStripe) stripe.Push(key) b.pool.Put(stripe)

    Once buffer fills up, push to channel: select { case p.itemsCh <- keys: p.stats.Add(keepGets, keys[0], uint64(len(keys))) return true default: p.stats.Add(dropGets, keys[0], uint64(len(keys))) return false } p.itemCh processing: func (p *tinyLFU) Push(keys []uint64) { for _, key := range keys { p.Increment(key) } } 2 /1 /1 2
  17. S t 4 c select { case c.setBuf <- &item{key:

    hash, val: val, cost: cost}: return true default: // drop the set and avoid blocking c.stats.Add(dropSets, hash, 1) return false } 2 /1 /1 2
  18. M tr cs 4 p F S 4 1 %

    o d Add: valp := p.all[t] // Avoid false sharing by padding at least 64 bytes of space between two // atomic counters which would be incremented. idx := (hash % 25) * 10 atomic.AddUint64(valp[idx], delta) Read: valp := p.all[t] var total uint64 for i := range valp { total += atomic.LoadUint64(valp[i]) } return total 2 /1 /1 2
  19. H w o func main() { cache, err := ristretto.NewCache(&ristretto.Config{

    NumCounters: 1e7, // Num keys to track frequency of (10M). MaxCost: 1 << 30, // Maximum cost of cache (1GB). BufferItems: 64, // Number of keys per Get buffer. }) if err != nil { panic(err) } cache.Set("key", "value", 1) // set a value // wait for value to pass through buffers time.Sleep(10 * time.Millisecond) value, found := cache.Get("key") if !found { panic("missing value") } fmt.Println(value) cache.Del("key") } 2 /1 /1 3