k8s-Informer之Indexer的解析(4)

ops/2024/12/12 2:40:26/

1、Indexer 介绍

k8s-Informer之Indexer的解析(4)

Indexer 是 Client-go 中实现的一个本地存储,它可以建立索引并存储 Resource 的对象。Indexer 中的数据始终要是与 ETCD 中数据一致的,当 client-go 需要数据时,可直接通过该本地缓存获取资源对象,不需要每次都从 APIServer中获取,这样就减轻了请求过多造成对 APIServer 、etcd的压力。

从 DeltaFIFO 中 Pop 出来的资源对象,交给了 HandlerDeltas 进行处理,在 HandleDeltas 中将资源对象同步到了 Indexer 中。


// k8s.io/client-go/tools/cache/shared_informer.go
func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {  s.blockDeltas.Lock()  defer s.blockDeltas.Unlock()  if deltas, ok := obj.(Deltas); ok {  return processDeltas(s, s.indexer, s.transform, deltas)  }  return errors.New("object given as Process argument is not Deltas")  
}// k8s.io/client-go/tools/cache/controller.go
func processDeltas(  handler ResourceEventHandler,  clientState Store,  transformer TransformFunc,  deltas Deltas) error {  // from oldest to newest  for _, d := range deltas {  obj := d.Object  if transformer != nil {  var err error  obj, err = transformer(obj)  if err != nil {  return err  }  }  switch d.Type {  case Sync, Replaced, Added, Updated:  if old, exists, err := clientState.Get(obj); err == nil && exists {  if err := clientState.Update(obj); err != nil {  return err  }  handler.OnUpdate(old, obj)  } else {  if err := clientState.Add(obj); err != nil {  return err  }  handler.OnAdd(obj)  }  case Deleted:  if err := clientState.Delete(obj); err != nil {  return err  }  handler.OnDelete(obj)  }  }  return nil  
}

2、Indexer 结构体定义

Indexer 接口继承了一个Store接口(实现本地缓存)

type Indexer interface {  Store  // indexName索引类,obj 是对象 // 通过计算 obj 在 indexName 索引类中的索引键,通过索引键获取所有的对象Index(indexName string, obj interface{}) ([]interface{}, error) // indexKey 是 indexName 索引类中的⼀个索引键,函数返回 indexKey 指定的所有对象键IndexKeys(indexName, indexedValue string) ([]string, error) // 获取 indexName 索引类中的所有索引键  ListIndexFuncValues(indexName string) []string  // 返回所有对象 ByIndex(indexName, indexedValue string) ([]interface{}, error)  // GetIndexers return the indexers   GetIndexers() Indexers  // 就是增加更多的索引分类AddIndexers(newIndexers Indexers) error  
}// store 接口,staging/src/k8s.io/client-go/tools/cache/store.go
type Store interface {Add(obj interface{}) errorUpdate(obj interface{}) errorDelete(obj interface{}) errorList() []interface{}ListKeys() []stringGet(obj interface{}) (item interface{}, exists bool, err error)GetByKey(key string) (item interface{}, exists bool, err error)Replace([]interface{}, string) errorResync() error
}

2.1、Store 结构体:

cache struct包含一个ThreadSafeStore接口的实现和计算object key的函数KeyFunc。cache struct会根据keyFunc生成某个obj对象对应的一个唯一key, 然后调用ThreadSafeStore接口中的方法来操作本地缓存中的对象。

type cache struct {  // cacheStorage ThreadSafeStore  keyFunc KeyFunc  
}

2.2、ThreadSafeStore

ThreadSafeStore 接口包含了操作本地缓存的增删改查方法以及索引功能的相关方法。


type ThreadSafeStore interface {  Add(key string, obj interface{})  Update(key string, obj interface{})  Delete(key string)  Get(key string) (item interface{}, exists bool)  List() []interface{}  ListKeys() []string  Replace(map[string]interface{}, string)  Index(indexName string, obj interface{}) ([]interface{}, error)  IndexKeys(indexName, indexedValue string) ([]string, error)  ListIndexFuncValues(name string) []string  ByIndex(indexName, indexedValue string) ([]interface{}, error)  GetIndexers() Indexers  Resync() error  
}

2.3、threadSafeMap

threadSafeMap struct 是ThreadSafeStore接口的一个实现


type threadSafeMap struct {  lock  sync.RWMutex  // items 就是存放资源对象,key根据资源对象来算出,value为资源对象本身items map[string]interface{}  // indexers maps a name to an IndexFunc  indexers Indexers  // indices maps a name to an Index  indices Indices  
}

3、Indexer 索引功能

与索引功能相关定义在 threadSafeMap 结构体中


// staging/src/k8s.io/client-go/tools/cache/thread_safe_store.go
type threadSafeMap struct {  lock  sync.RWMutex  items map[string]interface{}  // indexers maps a name to an IndexFunc  indexers Indexers  // indices maps a name to an Index  indices Indices  
}type IndexFunc func(obj interface{}) ([]string, error)type Index map[string]sets.String  // Indexers maps a name to an IndexFunc  
type Indexers map[string]IndexFunc  // Indices maps a name to an Index  
type Indices map[string]Index

3.1、 MetaNamespaceIndexFunc 函数

MetaNamespaceIndexFunc 函数在 Kubernetes 中使用的比较多的索引函数,是一个默认索引函数,它基于对象的命名空间进行索引。


func MetaNamespaceIndexFunc(obj interface{}) ([]string, error) {  meta, err := meta.Accessor(obj)  if err != nil {  return []string{""}, fmt.Errorf("object has no meta: %v", err)  }  return []string{meta.GetNamespace()}, nil  
}

3.2 、索引的实现 ByIndex() 函数

该方法传入索引器名称 indexName 和索引键名称indexedValue,方法寻找该索引器下,索引键对应的对象键列表,然后根据对象键列表,到Indexer缓存(即threadSafeMap中的items属性)中获取出相应的对象列表。

大致逻辑:

(1)首先根据索引器名称查找指定的索引器函数;

(2)然后根据索引器名称查找相应的缓存器函数;

(3)再根据索引 Key (indexedValue)从缓存中进行数据查询, 并返回查询结果;


func (c *threadSafeMap) ByIndex(indexName, indexedValue string) ([]interface{}, error) {  c.lock.RLock()  defer c.lock.RUnlock()  // 1、首先根据索引器名称查找指定的索引器函数indexFunc := c.indexers[indexName]  if indexFunc == nil {  return nil, fmt.Errorf("Index with name %s does not exist", indexName)  }  // 2、然后根据索引器名称查找相应的缓存器函数index := c.indices[indexName]  // 3、根据索引 Key (indexedValue)从缓存中进行数据查询, 并返回查询结果set := index[indexedValue]  list := make([]interface{}, 0, set.Len())  for key := range set {  list = append(list, c.items[key])  }  return list, nil  
}

使用示例:


pods, err := index.ByIndex("namespace", "default")
if err != nil {panic(err)
}
for _, pod := range pods {fmt.Println(pod.(*v1.Pod).Name)
}fmt.Println("------")pods, err := index.ByIndex("nodename", "node1")
if err != nil {panic(err)
}
for _, pod := range pods {fmt.Println(pod.(*v1.Pod).Name)
}

输出:

pod-1
pod-2
------
pod-1

总结:

Indexer 具有维护本地缓存的功能,还有一个更重要的功能就是索引功能了,这个索引的目的就是实现快速查找。如要查某个 Node 下的所有 Pod,或查找某个命名空间下的所有pod等等。使用索引就能实现快速查找。关于索引功能,则依赖于threadSafeMap结构体中的indexers与indices属性。

Informer


http://www.ppmy.cn/ops/141142.html

相关文章

在 Vue 3 中获取图片元素的宽高:原始尺寸与缩放后尺寸的处理方法

1.获取原始尺寸(不受代码修改大小影响) originalWidth.value imageRef.value.naturalWidth;//获取原始宽度 originalHeight.value imageRef.value.naturalHeight;//获取原始高度 2.当对图片应用了 transform: scale() 进行缩放后,width 和 …

锐捷网络设备常用命令(交换机、路由器)

因公司办公网络设备转为锐捷产品,特此学习一些锐捷交换机和路由器的相关配置: enable 进入特权模式 configure terminal 进入全局模式 logging on 日志显示(默认) no logging on 关闭日志显示 exit 返回上一层 end 返回到特权模式…

【Linux】文件查找 find grep

文章目录 1. 引言简介Linux文件系统的基本概念为什么文件查找命令在日常使用中非常重要 2. find 命令基本用法常见选项和参数高级用法和技巧实际示例 3. locate 命令如何工作与find命令的区别安装和使用locate实际示例 4. grep 结合文件查找使用grep进行内容查找结合find命令使…

Python实现中国象棋

探索中国象棋 Python 代码实现:从规则逻辑到游戏呈现 中国象棋,这款源远流长的棋类游戏,承载着深厚的文化底蕴与策略智慧。如今,借助 Python 与 Pygame 库,我们能够在数字世界中复刻其魅力,深入探究代码背后…

HIS(医院信息系统)中的大数据

一、定义 HIS是医院信息系统(Hospital Information System) 的缩写。它是利用计算机软硬件技术、网络通信技术等现代化手段,对医院及其个部门的人流、物流、材流进行综合管理,对医疗活动各阶段产生的数据进行采集、存储、处理、提取、传输、…

算法——差分

差分可以看作是前缀和的逆运算,前缀和可以帮我们快速得到某个区间的和,而差分就是我们将原数组看作是一个前缀和数组(q[])我们去构造一个差分数组(c[]) 一维差分 使存在如下关系: q[i] c[1]…

gitlab

一、gitlab 概念 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务。 b和GitHub一样属于第三方基于Git开发的作品,免费且开源(基于MIT协议),与Github类似…

ansible playbook 使用 script 模块在远程主机上执行脚本

需求一: 要在所有的远程主机上执行一下收集脚本,并在控制台打印出来 脚本如下: [root192 Playbooks]# cat CollectServerInformation.sh #!/bin/bash # Collect server information echo "Collecting server information..."# OS …