kubernetes lru cache典型应用场景

LRU缓存

背景

kubernetes lru cache典型应用场景

在运维场景下, 当我们对某一类资源进行回收的时候,其实回收的时候,会出发很多耗时的操作,但在这个过程中,如果我们有时候仍然需要获取一下该资源最新的状态, 那通畅会有这么几种做法

  • 清理工作和异步操作在完成的时候,去更改数据源,同时清除缓存
  • 数据缓存当发现该对象呗删除的时候,直接穿透,不缓存每次都获取一下

今天说的主要是第二种, 每次都强制更新当前最新状态

数据结构

  • LRUExpireCache
// LRUExpireCache LRU上面的一层封装, 主要作用是避免返回过期时间的数据
type LRUExpireCache struct {
    clock Clock

    cache *lru.Cache
    lock  sync.Mutex
}
  • cacheEntry
// 缓存项的一个包装, 如果缓存时间超过过期时间,会删除该key, 返回nil
type cacheEntry struct {
    value      interface{}
    expireTime time.Time
}

完整实现

import (
    "sync"
    "time"

    "github.com/hashicorp/golang-lru"
)

// Clock 一个抽象的时间工具接口
type Clock interface {
    Now() time.Time
}

type realClock struct{}

func (realClock) Now() time.Time { return time.Now() }

// LRUExpireCache LRU上面的一层封装, 主要作用是避免返回过期时间的数据
type LRUExpireCache struct {
    clock Clock

    cache *lru.Cache
    lock  sync.Mutex
}

// Add 添加一个元素并且指定过期时间
func (c *LRUExpireCache) Add(key interface{}, value interface{}, ttl time.Duration) {
    c.lock.Lock()
    defer c.lock.Unlock()
    c.cache.Add(key, &cacheEntry{value, c.clock.Now().Add(ttl)})
}

// Get 从LRU缓存中获取一个元素,并且元素不能过期
func (c *LRUExpireCache) Get(key interface{}) (interface{}, bool) {
    c.lock.Lock()
    defer c.lock.Unlock()
    e, ok := c.cache.Get(key)
    if !ok {
        return nil, false
    }
    if c.clock.Now().After(e.(*cacheEntry).expireTime) {
        c.cache.Remove(key)
        return nil, false
    }
    return e.(*cacheEntry).value, true
}

// Remove 移除一个元素
func (c *LRUExpireCache) Remove(key interface{}) {
    c.lock.Lock()
    defer c.lock.Unlock()
    c.cache.Remove(key)
}

// Keys 获取所有的key
func (c *LRUExpireCache) Keys() []interface{} {
    c.lock.Lock()
    defer c.lock.Unlock()
    return c.cache.Keys()
}

type cacheEntry struct {
    value      interface{}
    expireTime time.Time
}

// NewLRUExpireCache 返回一个Lru cache
func NewLRUExpireCache(maxSize int) *LRUExpireCache {
    return NewLRUExpireCacheWithClock(maxSize, realClock{})
}

// NewLRUExpireCacheWithClock 指定一个时间的抽象接口
func NewLRUExpireCacheWithClock(maxSize int, clock Clock) *LRUExpireCache {
    cache, err := lru.New(maxSize)
    if err != nil {
        panic(err)
    }
    return &LRUExpireCache{clock: clock, cache: cache}
}

总结

上面说的场景在k8s里面是用于namespace生命周期审计的一个功能, 当发现一个删除操作的时候, 会吧它加入到当前的lrucache里面

    if a.GetKind().GroupKind() == v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() {
        // if a namespace is deleted, we want to prevent all further creates into it
        // while it is undergoing termination.  to reduce incidences where the cache
        // is slow to update, we add the namespace into a force live lookup list to ensure
        // we are not looking at stale state.
        if a.GetOperation() == admission.Delete {
            l.forceLiveLookupCache.Add(a.GetName(), true, forceLiveLookupTTL)
        }
        // allow all operations to namespaces
        return nil
    }

如果检测到有了这个缓存就每次都更新下当前namespace的缓存

    // forceLiveLookup if true will skip looking at local cache state and instead always make a live call to server.
    forceLiveLookup := false
    if _, ok := l.forceLiveLookupCache.Get(a.GetNamespace()); ok {
        // we think the namespace was marked for deletion, but our current local cache says otherwise, we will force a live lookup.
        forceLiveLookup = exists && namespace.Status.Phase == v1.NamespaceActive
    }

    // refuse to operate on non-existent namespaces
    if !exists || forceLiveLookup {
        // as a last resort, make a call directly to storage
        namespace, err = l.client.CoreV1().Namespaces().Get(a.GetNamespace(), metav1.GetOptions{})
        switch {
        case errors.IsNotFound(err):
            return err
        case err != nil:
            return errors.NewInternalError(err)
        }
        glog.V(4).Infof("found %s via storage lookup", a.GetNamespace())
    }

大概思路就是这样,要是有个能交流的人就好了,继续 Again!

原创文章,作者:baxiaoshi,如若转载,请注明出处:http://www.sreguide.com/kubernetes/kubernetes-lru-cache%e5%85%b8%e5%9e%8b%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

QQ: 52866169