一般设计的微服务接口若被频繁大量调用,会导致CPU冲高,服务挂死等问题。此时可设计缓存方案,降低服务挂死风险。
beego 的 cache 模块是用来做数据缓存的,目前支持 file、memcache、memory 和 redis 四种引擎,本文主要介绍memory cache的使用,其他实现可参考beego官方文档。
使用入门
// 首先引入包import "github.com/astaxie/beego/cache"// 然后初始化一个全局变量对象bmbm, err := cache.NewCache("memory", `{"interval":60}`)// 然后我们就可以使用bm增删改缓存bm.Put("astaxie", 1, 10*time.Second)bm.Get("astaxie")bm.IsExist("astaxie")bm.Delete("astaxie")
缓存机制的实现
// cache.NewCachefunc init() {Register("memory", NewMemoryCache) // 模块初始化会把 创建Cache实例的方法注册到Map中}func NewCache(adapterName, config string) (adapter Cache, err error) {instanceFunc, ok := adapters[adapterName] // 获取到创建Cache实例的方法if !ok {err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)return}adapter = instanceFunc() // 调用方法创建Cache实例err = adapter.StartAndGC(config) // 调用GCif err != nil {adapter = nil}return}func (bc *MemoryCache) StartAndGC(config string) error {var cf map[string]intjson.Unmarshal([]byte(config), &cf)if _, ok := cf["interval"]; !ok {cf = make(map[string]int)cf["interval"] = DefaultEvery}dur := time.Duration(cf["interval"]) * time.Secondbc.Every = cf["interval"]bc.dur = durgo bc.vaccuum() //上面主要是解析config,获取interval,此处起一个协程调用缓存的清理方法return nil}func (bc *MemoryCache) vaccuum() {if bc.Every < 1 {return}for {<-time.After(bc.dur) // for循环,每bc.dur(如60)秒if bc.items == nil { // 若item为nil,退出循环,返回return}if keys := bc.expiredKeys(); len(keys) != 0 { //若不为空,清理掉过期的缓存键值对bc.clearItems(keys)}}}// cache.Putfunc (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {//除了键和值以外,还要给定超时时间参数bc.Lock()defer bc.Unlock()bc.items[name] = &MemoryItem{val: value,createdTime: time.Now(), //存入缓存时间lifespan: lifespan, //超时时间}return nil}// cache.Getfunc (bc *MemoryCache) Get(name string) interface{} {bc.RLock()defer bc.RUnlock()if itm, ok := bc.items[name]; ok {if itm.isExpire() { //如果超时,返回nilreturn nil}return itm.val}return nil}func (mi *MemoryItem) isExpire() bool {// 0 means foreverif mi.lifespan == 0 {return false}return time.Now().Sub(mi.createdTime) > mi.lifespan //当前时间减去创建时间大于超时时间,则超时}
开发自己的引擎
cache 模块采用了接口的方式实现,因此用户可以很方便的实现接口,然后注册就可以实现自己的 Cache 引擎:
type Cache interface {Get(key string) interface{}GetMulti(keys []string) []interface{}Put(key string, val interface{}, timeout time.Duration) errorDelete(key string) errorIncr(key string) errorDecr(key string) errorIsExist(key string) boolClearAll() errorStartAndGC(config string) error}// 用户开发完毕在最后写类似这样的:func init() {Register("myowncache", NewOwnCache())}
