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

Ristretto

98f8e6125c052c4ac3fcc94f97919371?s=47 Viney
October 14, 2019

 Ristretto

Introduce TinyLFU cache mechanism in Go

98f8e6125c052c4ac3fcc94f97919371?s=128

Viney

October 14, 2019
Tweet

Transcript

  1. R st et o V 2 /1 /1 1

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

    e , M -B c 2 /1 /1 2
  3. W y? D ra h ee i 2 /1 /1

    3
  4. W rk ro nd G ou ca he’s RU +

    m te l ck ! 2 /1 /1 4
  5. C e ne 2 /1 /1 5

  6. R st et o B tt r al o E

    pr ss 2 /1 /1 6
  7. 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
  8. G id ng ri ci le 2 /1 /1 8

  9. 4 F A s 4 H C e n C

    i R n 4 M B g 2 /1 /1 9
  10. M mo y ou di g K y os 2

    /1 /1 1
  11. 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
  12. M mo y ou di g A mi si n

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

    B l 2 /1 /1 1
  14. T ny FU 2 /1 /1 1

  15. 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
  16. F st cc ss S or 2 /1 /1 1

  17. S or 4 D C 4 N t -l s

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

    -w m 4 2 s 6 -c s 2 /1 /1 1
  19. F st cc ss H sh 2 /1 /1 1

  20. 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
  21. H sh (c nt.) 4 s k 4 w s

    h e s i 2 /1 /1 2
  22. C nc rr nc C nt nt on es st

    nc 2 /1 /1 2
  23. 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
  24. C nc rr nc G t 2 /1 /1 2

  25. G t 4 s , l n b e 4

    s .P 2 /1 /1 2
  26. 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
  27. C nc rr nc S t 2 /1 /1 2

  28. 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
  29. 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
  30. 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
  31. S ar h 2 /1 /1 3

  32. D ta as 2 /1 /1 3

  33. L op ng 2 /1 /1 3

  34. C DA YL 2 /1 /1 3

  35. M xe : 25% W it s, 75% R ad

    2 /1 /1 3
  36. R ad: 100% R ad 2 /1 /1 3

  37. W it : 100% W it s 2 /1 /1

    3
  38. T DO 2 /1 /1 3

  39. Q&A 2 /1 /1 3