beego cache模块源码解析

缘起.什么是cache?

cache的中文名叫缓存,缓存在计算机的世界里无处不在,比如cpu的多级缓存,比如类似encache的本地缓存。举个现实中的例子,比如取钱,当然这样的场景被电子支付逐渐取代了,那就把时光倒退到10年前。假设你去饭店吃饭,发现兜里没钱了,去银行取了一顿饭的钱,等到下个饭点,又得去趟银行,不是银行忙死就是你累死,聪明的你,一定不会这么傻,你会取多些出来放在兜里,等下次用直接从兜里拿,你的布袋就是缓存。精明的你一定不会取出太多,取出一万块揣在 兜里,不知道的还以为你肿了呢?缓存不能为缓而缓,要缓的恰到好处。

缘生.为什么用cache?

根据我的经验,主要有两点:

a>提高性能,比如把热点数据放进memcache,redis。

b>减少对后端服务的冲击,给它们减压降温。比如有个服务b,需要被服务a调用。哪一天服务a喝醉昏了头,以超高qps向服务b发起冲击。十有八九,服务b会挂掉。那么,服务a服务b之间加个缓存,问题是不是就化解了。此时,我的耳边响起了那句宛如咒语一样的话:计算机里的问题都可以通过加一层来解决。

缘来.beego是怎么做的?

前面有些跑偏了,言归正传。

beego支持多个cache类型,内存、redis、file、memcache、ssdb。先看一下接口定义:

type Cache interface {

// get cached value by key.

      Get(key string)interface{}

// GetMulti is a batch version of Get.

      GetMulti(keys []string) []interface{}

// set cached value with key and expire time.

      Put(key string, valinterface{}, timeout time.Duration) error

// delete cached value by key.

      Delete(key string) error

// increase cached int value by key, as a counter.

      Incr(key string) error

// decrease cached int value by key, as a counter.

      Decr(key string) error

// check if cached value exists or not.

      IsExist(key string) bool

// clear all cache.

      ClearAll() error

// start gc routine based on config string settings.

      StartAndGC(config string) error

}

望文生义,其他函数功能不多解释。主要说说StartAndGC。这个函数主要用来初始连接与清除缓存,redis与memcache可以设置过期时间的缓存适配器是不需要做清除操作的,完全交由他们自己来做。内存缓存、文件缓存就需要自己费神了。简单看一下MemoryCache的实现。

// StartAndGC start memory cache. it will check expiration in every clock time.

func (bc *MemoryCache) StartAndGC(config string) error {

var cfmap[string]int

json.Unmarshal([]byte(config), &cf)

if _, ok := cf["interval"]; !ok {

cf = make(map[string]int)

cf["interval"] = DefaultEvery

}

dur := time.Duration(cf["interval"]) * time.Second

      bc.Every = cf["interval"]

bc.dur = dur

go bc.vacuum()

return nil

}

主要看go bc.vacuum()

这里起了个goroutine,来做过期检测,并清除过期值。

// check expiration.

func (bc *MemoryCache) vacuum() {

bc.RLock()

every := bc.Every

bc.RUnlock()

if every <1 {

return

      }

for {

<-time.After(bc.dur)

if bc.items == nil {

return

              }

if keys := bc.expiredKeys(); len(keys) !=0 {

bc.clearItems(keys)

}

}

}

清除其实就是从map里面删除掉:

// clearItems removes all the items which key in keys.

func (bc *MemoryCache) clearItems(keys []string) {

bc.Lock()

defer bc.Unlock()

for _, key :=range keys {

delete(bc.items, key)

}

}

其他缓存适配器大同小异,当然,你也可以自己实现一个cache,只要实现上面那个cache接口 即可。

有了这些适配器,怎么找到并使用他们呢?

// Instance is a function create a new Cache Instance

type Instancefunc() Cache

var adapters = make(map[string]Instance)

// Register makes a cache adapter available by the adapter name.

// If Register is called twice with the same name or if driver is nil,

// it panics.

func Register(name string, adapterInstance) {

if adapter == nil {

panic("cache: Register adapter is nil")

}

if _, ok := adapters[name]; ok {

panic("cache: Register called twice for adapter " + name)

}

adapters[name] = adapter

}

每个适配器文件里实现了init方法,

func init() {

Register("memory", NewMemoryCache)

}

原来是把适配器注册到了全局变量里。如果要使用适配器,只需传入适配器类型便可。服务很是到位:

func test(){

bm, err := cache.NewCache("redis",`{"conn": "127.0.0.1:6379"}`)

if err != nil {

t.Error("init err")

}

timeoutDuration :=10 * time.Second

if err = bm.Put("astaxie",1, timeoutDuration); err != nil {

t.Error("set Error", err)

}

}

缘终:技术没有终点

第一次写技术博客,很粗糙。看过不如写过,写过不如用过。

你可能感兴趣的:(beego cache模块源码解析)