Indexer

Indexer是一个用来存储资源对象的内存存储,处理用户的查询是非常快速高效的。源码路径为k8s.io/client-go/tools/cache/index.go。

Indexer的实现主要分为2部分,ThreadSafeMap是底层的并发安全存储,Indexer索引器用来注册索引函数。

1.ThreadSafeMap并发安全存储

Indexer是在ThreadSafeMap的基础上进行了封装,ThreadSafeMap使用了读写锁来保证并发的读写安全。ThreadSafeMap的源码路径为k8s.io/client-go/tools/cache/thread_safe_store.go。

ThreadSafeMap的定义示例如下。

type threadSafeMap struct {
    lock  sync.RWMutex
    items map[string]interface{}
    indexers Indexers
    indices Indices
}

其中items是用来存储资源对象的map,key默认由Meta-NamespaceKeyFunc函数处理后得到,经过处理后的key的格式为namespace/name。items的值用来存储资源对象。

ThreadSafeMap增删改查的入口方法分别是AddIndexers、deleteFromIndices、updateIndices、GetIndexers。这些方法会执行底层针对items的Add、Delete、Update、Get、List等方法。

2.Indexer索引器

Indexer被设计成是一个可以自定义索引函数的索引器,这样方便我们进行自定义扩展,也符合Kubernetes高度可扩展性的需求。

Indexer有4个重要的数据结构来支撑实现自定义索引的特性,示例如下。

type Indexers map[string]IndexFunc
type IndexFunc func(obj interface{}) ([]string, error)
type Indices map[string]Index
type Index map[string]sets.String

·Indexers:map类型,用来存储自定义的索引,key是自定义的索引名,value是索引函数。

·IndexFuc:索引函数。

·Indices:map类型,用来存储缓存器,key是缓存器的名字,value是具体的索引缓存。

·Index:map类型,用来存储缓存数据,key是索引,value是set集合。

下面通过源码中的测试用例函数来了解如何自定义一个索引器的函数,源码路径为k8s.io/client-go/tools/cache/index_test.go,示例如下。

func testIndexFunc(obj interface{}) ([]string, error) {
    pod := obj.(*v1.Pod)
    return []string{pod.Labels["foo"]}, nil
}
func TestGetIndexFuncValues(t *testing.T) {
    index := NewIndexer(MetaNamespaceKeyFunc, Indexers{"testmodes": testIndexFunc})
    pod1 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "one", Labels: 
        map[string]string{"foo": "bar"}}}
    pod2 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "two", Labels: 
        map[string]string{"foo": "bar"}}}
    pod3 := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "tre", Labels: 
        map[string]string{"foo": "biz"}}}
    index.Add(pod1)
    index.Add(pod2)
    index.Add(pod3)
    keys := index.ListIndexFuncValues("testmodes")
    if len(keys) != 2 {
        t.Errorf("Expected 2 keys but got %v", len(keys))
    }
    for _, key := range keys {
        if key != "bar" && key != "biz" {
            t.Errorf("Expected only 'bar' or 'biz' but got %s", key)
        }
    }
}

·testIndexFunc()是一个自定义的索引器函数,具体功能是通过labels过滤key中包含foo字段的Pod,并返回value。

·NewIndexer()用来初始化一个Indexers索引器,第一个参数是自定义的索引器名字"testmodes",第二个参数是自定义索引器的具体函数testIndexFunc。

·初始化Indexer之后创建了3个Pod资源对象并且label都包含foo字段,通过index.Add()方法存入index,然后执行ListIndexFuncValues()并传入自定义的索引函数名称"testmodes"来获取符合索引规则的值。

这个测试用例下还有一个testUsersIndexFunc自定义索引器函数,并通过TestMultiIndexKeys函数内的index.ByIndex进行测试。

posted @ 2023-02-26 14:28  muzinan110  阅读(44)  评论(0编辑  收藏  举报