k8s编程-Operator-Indexer

761 阅读2分钟

功能:存储数据。数据与apiserver保持一致,实时更新。因此除了直接调用apiserver进行读请求,还可以直接通过indexer读取,减轻apiserver的压力。

原理:数据主要通过threadSafeMap来存放 (满足ThreadSafeStore接口)

可以通过NewIndexer函数创建(实际返回的是cache)

代码:

func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer {
	return &cache{
		cacheStorage: NewThreadSafeStore(indexers, Indices{}),
		keyFunc:      keyFunc,
	}
}

cache中的所有存储操作,调用的都是cacheStorage的方法

为什么要使用Index: 在指定namespace或者其他条件进行检索时,需要用到index来加速检索。否则使用List或者Get,效率很低

在cache中,存在多个Index相关的方法,那么什么是index呢

image.png

首先需要介绍三个数据类型: index/indicies/indexer

// Index maps the indexed value to a set of keys in the store that match on that value
//key是IndexFunc计算出来的结果,⽐如default,value是所有obj的key的集合
type Index map[string]sets.String
// 这里sets.String 其实是一个value为空struct的map,所以可以作为Set使用

// Indexers maps a name to an IndexFunc
//key是索引的分类名,⽐如namespace,value是⼀个⽅法,通过该⽅法可以获取obj的namespace,⽐如default
type Indexers map[string]IndexFunc

// Indices maps a name to an Index
// key是索引的分类名,⽐如namespace
type Indices map[string]Index


按照如上关系,举例来说,在Indicies中找到namespace的index,再从Index中找到 default 的所有pod的key,最后通过这些key可以从item中获取pod信息

结合下图。Indexer和Indices都可以进行索引查询,举例如下

  • indexer:查询key为Namespace,返回func,通过func计算出Index;再去Items理查询获取到obj。
  • Indicies: 查询key为 Namespace,获取到对应的Index; 再查询为default的所有结果,放到Items里就能获取到所有的pod对象( object

image.png

更新索引: updateIndices

更新流程举例:
threadSafeMap为例,

func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.Update(key, obj)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

关键在于updateIndices,这里可以看到更新的过程


// updateIndices modifies the objects location in the managed indexes:
// - for create you must provide only the newObj
// - for update you must provide both the oldObj and the newObj
// - for delete you must provide only the oldObj
// updateIndices must be called from a function that already has a lock on the cache
func (c *threadSafeMap) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	var oldIndexValues, indexValues []string
	var err error
	for name, indexFunc := range c.indexers {
		if oldObj != nil {
			oldIndexValues, err = indexFunc(oldObj)
		} else {
			// [:0]  相当于取了一个空slice
			oldIndexValues = oldIndexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		if newObj != nil {
			indexValues, err = indexFunc(newObj)
		} else {
			indexValues = indexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		index := c.indices[name]
		if index == nil {
			index = Index{}
			c.indices[name] = index
		}

		if len(indexValues) == 1 && len(oldIndexValues) == 1 && indexValues[0] == oldIndexValues[0] {
			// We optimize for the most common case where indexFunc returns a single value which has not been changed
			continue
		}

		for _, value := range oldIndexValues {
			c.deleteKeyFromIndex(key, value, index)
		}
		for _, value := range indexValues {
			c.addKeyToIndex(key, value, index)
		}
	}
}

参考

部分图片参考自:www.bilibili.com/video/BV15m…