一般设计的微服务接口若被频繁大量调用,会导致CPU冲高,服务挂死等问题。此时可设计缓存方案,降低服务挂死风险。
beego 的 cache 模块是用来做数据缓存的,目前支持 file、memcache、memory 和 redis 四种引擎,本文主要介绍memory cache的使用,其他实现可参考beego官方文档


使用入门

  1. // 首先引入包
  2. import "github.com/astaxie/beego/cache"
  3. // 然后初始化一个全局变量对象bm
  4. bm, err := cache.NewCache("memory", `{"interval":60}`)
  5. // 然后我们就可以使用bm增删改缓存
  6. bm.Put("astaxie", 1, 10*time.Second)
  7. bm.Get("astaxie")
  8. bm.IsExist("astaxie")
  9. bm.Delete("astaxie")

缓存机制的实现

  1. // cache.NewCache
  2. func init() {
  3. Register("memory", NewMemoryCache) // 模块初始化会把 创建Cache实例的方法注册到Map中
  4. }
  5. func NewCache(adapterName, config string) (adapter Cache, err error) {
  6. instanceFunc, ok := adapters[adapterName] // 获取到创建Cache实例的方法
  7. if !ok {
  8. err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
  9. return
  10. }
  11. adapter = instanceFunc() // 调用方法创建Cache实例
  12. err = adapter.StartAndGC(config) // 调用GC
  13. if err != nil {
  14. adapter = nil
  15. }
  16. return
  17. }
  18. func (bc *MemoryCache) StartAndGC(config string) error {
  19. var cf map[string]int
  20. json.Unmarshal([]byte(config), &cf)
  21. if _, ok := cf["interval"]; !ok {
  22. cf = make(map[string]int)
  23. cf["interval"] = DefaultEvery
  24. }
  25. dur := time.Duration(cf["interval"]) * time.Second
  26. bc.Every = cf["interval"]
  27. bc.dur = dur
  28. go bc.vaccuum() //上面主要是解析config,获取interval,此处起一个协程调用缓存的清理方法
  29. return nil
  30. }
  31. func (bc *MemoryCache) vaccuum() {
  32. if bc.Every < 1 {
  33. return
  34. }
  35. for {
  36. <-time.After(bc.dur) // for循环,每bc.dur(如60)秒
  37. if bc.items == nil { // 若item为nil,退出循环,返回
  38. return
  39. }
  40. if keys := bc.expiredKeys(); len(keys) != 0 { //若不为空,清理掉过期的缓存键值对
  41. bc.clearItems(keys)
  42. }
  43. }
  44. }
  45. // cache.Put
  46. func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
  47. //除了键和值以外,还要给定超时时间参数
  48. bc.Lock()
  49. defer bc.Unlock()
  50. bc.items[name] = &MemoryItem{
  51. val: value,
  52. createdTime: time.Now(), //存入缓存时间
  53. lifespan: lifespan, //超时时间
  54. }
  55. return nil
  56. }
  57. // cache.Get
  58. func (bc *MemoryCache) Get(name string) interface{} {
  59. bc.RLock()
  60. defer bc.RUnlock()
  61. if itm, ok := bc.items[name]; ok {
  62. if itm.isExpire() { //如果超时,返回nil
  63. return nil
  64. }
  65. return itm.val
  66. }
  67. return nil
  68. }
  69. func (mi *MemoryItem) isExpire() bool {
  70. // 0 means forever
  71. if mi.lifespan == 0 {
  72. return false
  73. }
  74. return time.Now().Sub(mi.createdTime) > mi.lifespan //当前时间减去创建时间大于超时时间,则超时
  75. }

开发自己的引擎

cache 模块采用了接口的方式实现,因此用户可以很方便的实现接口,然后注册就可以实现自己的 Cache 引擎:

  1. type Cache interface {
  2. Get(key string) interface{}
  3. GetMulti(keys []string) []interface{}
  4. Put(key string, val interface{}, timeout time.Duration) error
  5. Delete(key string) error
  6. Incr(key string) error
  7. Decr(key string) error
  8. IsExist(key string) bool
  9. ClearAll() error
  10. StartAndGC(config string) error
  11. }
  12. // 用户开发完毕在最后写类似这样的:
  13. func init() {
  14. Register("myowncache", NewOwnCache())
  15. }