转自go-zero点击查看原文
go-zero微服务库地址https://github.com/tal-tech/go-zero
通过 collection.Cache 进行缓存
go-zero微服务框架中提供了许多开箱即用的工具,好的工具不仅能晋升服务的性能而且还能晋升代码的鲁棒性防止出错,实现代码格调的对立不便别人浏览等等,本系列文章将别离介绍go-zero框架中工具的应用及其实现原理
过程内缓存工具collection.Cache
在做服务器开发的时候,置信都会遇到应用缓存的状况,go-zero 提供的简略的缓存封装 collection.Cache,简略应用形式如下
// 初始化 cache,其中 WithLimit 能够指定最大缓存的数量c, err := collection.NewCache(time.Minute, collection.WithLimit(10000))if err != nil { panic(err)}// 设置缓存c.Set("key", user)// 获取缓存,ok:是否存在v, ok := c.Get("key")// 删除缓存c.Del("key")// 获取缓存,如果 key 不存在的,则会调用 func 去生成缓存v, err := c.Take("key", func() (interface{}, error) { return user, nil})
cache 实现的建的性能包含
- 缓存主动生效,能够指定过期工夫
- 缓存大小限度,能够指定缓存个数
- 缓存增删改
- 缓存命中率统计
- 并发平安
- 缓存击穿
实现原理:
Cache 主动生效,是采纳 TimingWheel(https://github.com/tal-tech/g... 进行治理的
timingWheel, err := NewTimingWheel(time.Second, slots, func(k, v interface{}) { key, ok := k.(string) if !ok { return } cache.Del(key)})
Cache 大小限度,是采纳 LRU 淘汰策略,在新增缓存的时候会去查看是否曾经超出过限度,具体代码在 keyLru 中实现
func (klru *keyLru) add(key string) { if elem, ok := klru.elements[key]; ok { klru.evicts.MoveToFront(elem) return } // Add new item elem := klru.evicts.PushFront(key) klru.elements[key] = elem // Verify size not exceeded if klru.evicts.Len() > klru.limit { klru.removeOldest() }}
Cache 的命中率统计,是在代码中实现 cacheStat,在缓存命中失落的时候主动统计,并且会定时打印应用的命中率, qps 等状态.
打印的具体成果如下
cache(proc) - qpm: 2, hit_ratio: 50.0%, elements: 0, hit: 1, miss: 1
缓存击穿蕴含是应用 syncx.SharedCalls(https://github.com/tal-tech/g... 进行实现的,就是将同时申请同一个 key 的申请, 对于 sharedcalls 后续会持续补充。 相干具体实现是在:
func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}, error) { val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) { v, e := fetch() if e != nil { return nil, e } c.Set(key, v) return v, nil }) if err != nil { return nil, err } if fresh { c.stats.IncrementMiss() return val, nil } else { // got the result from previous ongoing query c.stats.IncrementHit() } return val, nil}
本文次要介绍了go-zero框架中的 Cache 工具,在理论的我的项目中十分实用。用好工具对于晋升服务性能和开发效率都有很大的帮忙,心愿本篇文章能给大家带来一些播种。