K8S Informer机制原理解读 | Indexer

Indexer

Indexer是client-go用来存储资源对象并自带索引功能的本地存储,Reflector从DeltaFIFO中将消费出来的资源对象存储至Indexer。Indexer中的数据与Etcd集群中的数据保持完全一致。client-go可以很方便地从本地存储中读取相应的资源对象数据,而无须每次都从远程Etcd集群中读取,这样可以减轻Kubernetes API Server和Etcd集群的压力。

在介绍Indexer之前,先介绍一下ThreadSafeMap。ThreadSafeMap是实现并发安全的存储。作为存储,它拥有存储相关的增、删、改、查操作方法,例如Add、Update、Delete、List、Get、Replace、Resync等。Indexer在ThreadSafeMap的基础上进行了封装,它继承了与ThreadSafeMap相关的操作方法并实现了Indexer Func等功能,例如Index、IndexKeys、GetIndexers等方法,这些方法为ThreadSafeMap提供了索引功能。Indexer存储结构如图所示。

K8S Informer机制原理解读 | Indexer_第1张图片

1. ThreadSafeMap并发安全存储

ThreadSafeMap是一个内存中的存储,其中的数据并不会写入本地磁盘中,每次的增、删、改、查操作都会加锁,以保证数据的一致性。ThreadSafeMap将资源对象数据存储于一个map数据结构中,ThreadSafeMap结构代码示例如下:

staging/src/k8s.io/client-go/tools/cache/thread_safe_store.go

K8S Informer机制原理解读 | Indexer_第2张图片
items字段中存储的是资源对象数据,其中items的key通过keyFunc函数计算得到,计算默认使用MetaNamespaceKeyFunc函数,该函数根据资源对象计算出/格式的key,如果资源对象的为空,则作为key,而items的value用于存储资源对象。

2. Indexer索引器

在每次增、删、改ThreadSafeMap数据时,都会通过updateIndices或deleteFromIndices函数变更Indexer。Indexer被设计为可以自定义索引函数,这符合Kubernetes高扩展性的特点。Indexer有4个非常重要的数据结构,分别是Indices、Index、Indexers及IndexFunc。直接阅读相关代码会比较晦涩,通过Indexer Example代码示例来理解Indexer,印象会更深刻。Indexer Example代码示例如下:

K8S Informer机制原理解读 | Indexer_第3张图片
首先定义一个索引器函数UsersIndexFunc,在该函数中,我们定义查询出所有Pod资源下Annotations字段的key为users的Pod。

cache.NewIndexer函数实例化了Indexer对象,该函数接收两个参数:第1个参数是KeyFunc,它用于计算资源对象的key,计算默认使用cache.MetaNamespaceKeyFunc函数;第2个参数是cache.Indexers,用于定义索引器,其中key为索引器的名称(即byUser),value为索引器。通过index.Add函数添加3个Pod资源对象。最后通过index.ByIndex函数查询byUser索引器下匹配ernie字段的Pod列表。Indexer Example代码示例最终检索出名称为one和three的Pod。

现在再来理解Indexer的4个重要的数据结构就非常容易了,它们分别是Indexers、IndexFunc、Indices、Index,数据结构如下:

// IndexFunc knows how to compute the set of indexed values for an object.
type IndexFunc func(obj interface{}) ([]string, error)
// Index maps the indexed value to a set of keys in the store that match on that value
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

Indexer数据结构说明如下。

  • Indexers:存储索引器,key为索引器名称,value为索引器的实现函数。
  • IndexFunc:索引器函数,定义为接收一个资源对象,返回检索结果列表。
  • Indices:存储缓存器,key为缓存器名称(在Indexer Example代码示例中,缓存器命名与索引器命名相对应),value为缓存数据。
  • Index:存储缓存数据,其结构为K/V。
3. Indexer索引器核心实现

index.ByIndex函数通过执行索引器函数得到索引结果,代码示例如下:

K8S Informer机制原理解读 | Indexer_第4张图片
ByIndex接收两个参数:IndexName(索引器名称)和indexKey(需要检索的key)。首先从c.indexers中查找指定的索引器函数,从c.indices中查找指定的缓存器函数,然后根据需要检索的indexKey从缓存数据中查到并返回数据。

提示:Index中的缓存数据为Set集合数据结构,Set本质与Slice相同,但Set中不存在相同元素。由于Go语言标准库没有提供Set数据结构,Go语言中的map结构类型是不能存在相同key的,所以Kubernetes将map结构类型的key作为Set数据结构,实现Set去重特性。

End…

以上就是针对k8s informer机制的详细讲解。

关注我,带你学习更多的K8S知识。
任何不会的问题都可以关注「程序员溪昂」,后台私信求解或者下方留言哦
K8S Informer机制原理解读 | Indexer_第5张图片

你可能感兴趣的:(Go,kubernetes,kubernetes,容器,云原生)