client-go中带过期时间的cache实现,具体在:client-go\tools\cache\expiration_cache.go
    cache包下有各种数据结构的实现。本节看一下NewTTLStore创建并返回带有TTLPolicy的ExpirationCache实现:

    package main
    
    import (
        "k8s.io/client-go/tools/cache"
        "log"
        "time"
    )
    
    func stringKeyFunc(obj interface{}) (string, error) {
        key := obj.(string)
        return key, nil
    }
    
    func main() {
        sto := cache.NewTTLStore(stringKeyFunc, 5*time.Second)
        sto.Add("key1")
    
        time.Sleep(2 * time.Second)
    
        item, exists, err := sto.Get("key1")
        log.Printf("2s item: %v, exists: %v, err: %v", item, exists, err)
    
        for {
            time.Sleep(7 * time.Second)
            item, exists, err := sto.Get("key1")
            log.Printf("time: %v item: %v, exists: %v, err: %v", time.Now(), item, exists, err)
        }
    }
    

    部分输出如下:

    2020/09/09 21:04:51 2s item: key1, exists: true, err: <nil>
    2020/09/09 21:04:58 time: 2020-09-09 21:04:58.8331777 +0800 CST m=+9.134970501 item: <nil>, exists: false, err: <nil>
    2020/09/09 21:05:05 time: 2020-09-09 21:05:05.8332772 +0800 CST m=+16.135070001 item: <nil>, exists: false, err: <nil>
    

    可以看到5s之后exists为false。
    具体实现为:
    每次Get的时候都会执行getOrExpire方法,getOrExpire如果过期,则会将其删除。当且仅当它尚未过期时才从timestampedEntry中检索对象。它在删除过程中拥有写锁定。

    // getOrExpire retrieves the object from the timestampedEntry if and only if it hasn't
    // already expired. It holds a write lock across deletion.
    func (c *ExpirationCache) getOrExpire(key string) (interface{}, bool) {
        // Prevent all inserts from the time we deem an item as "expired" to when we
        // delete it, so an un-expired item doesn't sneak in under the same key, just
        // before the Delete.
        c.expirationLock.Lock()
        defer c.expirationLock.Unlock()
        timestampedItem, exists := c.getTimestampedEntry(key)
        if !exists {
            return nil, false
        }
        if c.expirationPolicy.IsExpired(timestampedItem) {
            klog.V(4).Infof("Entry %v: %+v has expired", key, timestampedItem.obj)
            c.cacheStorage.Delete(key)
            return nil, false
        }
        return timestampedItem.obj, true
    }