带你读《云原生应用开发 Operator原理与实践》第二章 Operator 原理2.2Client-go 原理(十三)

简介: 带你读《云原生应用开发 Operator原理与实践》第二章 Operator 原理2.2Client-go 原理(十二)

1. Client-goIndexer

 

     资源对象从 DeltaFIFOPop 出去后又经过了哪些处理呢。这要从一开始的 sharedIndexInformer说起。注意,在 sharedIndexInformerRun 方法中,初始化了它的配置,并执行了 s.controller.Run方法。我们可以看到s.controller.Run中初始化了 Reflector,开始了指定资源的List-Watch 操作,并且同步到了DeltaFIFO中,同时执行了processLoop方法。此时我们可以看到 processLoop方法不断从DeltaFIFO中将资源对象 Pop来, 并且交给了之前的 c.config.Process方法进行处理。而c.config.Process方法就是sharedIndexInformerHandleDeltas方法,具体见代码清单 2-45



func(s*sharedIndexInformer)Run(stopCh<-chanstruct{}){

...

cfg:=&Config{

Queue:              fifo,

ListerWatcher:             s.listerWatcher,ObjectType:          s.objectType,FullResyncPeriod:s.resyncCheckPeriod,RetryOnError:                 false,

ShouldResync:       s.processor.shouldResync,

 

Process:         s.HandleDeltas,WatchErrorHandler:s.watchErrorHandler,

}

 

func(){

s.startedLock.Lock()

defers.startedLock.Unlock()

 

...

}()


s.controller=New(cfg)s.controller.(*controller).clock=s.clocks.started=true

s.controller.Run(stopCh)

}

 

func(c*controller)Run(stopCh<-chanstruct{}){deferutilruntime.HandleCrash()

gofunc(){

<-stopCh

c.config.Queue.Close()

}()

r:=NewReflector(


c.config.ListerWatcher,c.config.ObjectType,c.config.Queue,c.config.FullResyncPeriod,

)

r.ShouldResync=c.config.ShouldResync

r.clock=c.clock

...

}

c.reflectorMutex.Lock()c.reflector=rc.reflectorMutex.Unlock()

 

wait.Until(c.processLoop,time.Second,stopCh)

func(c*controller)processLoop(){for{

obj,err:=c.config.Queue.Pop(PopProcessFunc(c.config.Process))

iferr!=nil{

iferr==FIFOClosedError{

return

}

ifc.config.RetryOnError{

//Thisisthesafewaytore-enqueue.

c.config.Queue.AddIfNotPresent(obj)

}

}

}

}

 

 

综上可知,由 DeltaFIFOPop出来的对象最后交给了 HandleDeltas进行处理,而HandleDeltas中,将资源对象同步到了 Indexer中,至此我们引出了 Informer模块中的3个组件 Indexer。IndexerClient-go 中实现的一个本地存储,它可以建立索引并存Resource的对象。Reflector通过 DeltaFIFOQueue将资源对象存储到Indexer中。需要注意的是,Indexer中的数据与 ETCD中的数据是完全一致的,当 Client-go需要数据时,无须每次都从 APIServer中获取,从而减轻了请求过多造成的对 APIServer的压力, 具体见代码清单 2-46。

func(s*sharedIndexInformer)HandleDeltas(objinterface{})error{

s.blockDeltas.Lock()

defers.blockDeltas.Unlock()

 

//fromoldesttonewest

for_,d:=rangeobj.(Deltas){switchd.Type{

caseSync,Replaced,Added,Updated:s.cacheMutationDetector.AddObject(d.Object)

ifold,exists,err:=s.indexer.Get(d.Object);err==nil&&

exists{

if err:=s.indexer.Update(d.Object);err!=nil{returnerr


}

 

requestedresync 

nil{

 

==nil{


isSync:=falseswitch{

cased.Type==Sync:

//Synceventsareonlypropagatedtolistenersthat

 

isSync=true

cased.Type==Replaced:

ifaccessor,err:=meta.Accessor(d.Object);err==ifoldAccessor,err:=meta.Accessor(old);err

//Replacedeventsthatdidn'tchange


resourceVersionaretreatedasresyncevents

//andonlypropagatedtolisteners


thatrequestedresync

 

==oldAccessor.GetResourceVersion()

}


isSync=accessor.GetResourceVersion()

}

}

s.processor.distribute(updateNotification{oldObj:old,

newObj:d.Object},isSync)

}else{

if err:=s.indexer.Add(d.Object);err!=nil{returnerr

 

false)

}

s.processor.distribute(addNotification{newObj:d.Object},

 

}

caseDeleted:

iferr:=s.indexer.Delete(d.Object);err!=nil{


 

returnerr

}

s.processor.distribute(deleteNotification{oldObj:d.Object},false)

}

}

returnnil

}

 

Indexer   是如何实现存储并快速查找资源的呢?我们先看一下 Indexer接口提供的功能。CacheIndexer的一种非常经典的实现,所有的对象缓存在内存中,而且从Cache 这个类型的名称来看它属于包内私有类型,外部无法直接使用,只能通过专用的函数创建。 这里的 Store、Indexer使用了一个 threadSafeMap来保证并发安全的存储。它拥有存储相关的增、删、改、查等方法。threadSafeMap继承了 Store接口,而 Indexer扩展了threadSafeMap, 为 threadSafeMap提供了索引操作。threadSafeMap其实只能够存储和索引。存储即将runtime.object存储到 ItemsMap中;索引即为ItemsMap建立三层索引:IndicesMap类型索引namespace、nodeName);IndexMap 类型索引(namespace1、namespace2……);runtime.object类型索引,实现见代码清 2-47


typeIndexerinterface{Store

//indexName索引类,obj是对象,计算objindexName索引类中的索引键,通过索引键

获取所有的对象

//基本就是获取符合obj特征的所有对象,所谓的特征就是对象在索引类中的索引键

Index(indexNamestring,objinterface{})([]interface{},error)

//indexKeyindexName索引类中的⼀个索引键,函数返回indexKey指定的所有对象键

IndexKeys(indexName,indexedValuestring)([]string,error)

//获取indexName索引类中的所有索引键

ListIndexFuncValues(indexNamestring)[]string

//这个函数和 Index类似,只是返回值不是对象键,⽽是所有对象

ByIndex(indexName,indexedValuestring)([]interface{},error)

//返回Indexers

GetIndexers()Indexers

//添加Indexers,就是增加更多的索引分类

AddIndexers(newIndexersIndexers)error

}

 

Kubernetes中使用的比较多的索引函数是MetaNamespaceIndexFunc() 代码位置:

 

client-go/tools/cache/index.go,Indexer索引的实现是通过index.ByIndex来完成的, index.ByIndex的实现见代码清单 2-48。这个函数返回了符合索引函数的值的对象列表。



func(c*threadSafeMap)ByIndex(indexName,indexKeystring)([]interface{},error){c.lock.RLock()

deferc.lock.RUnlock()

 

indexFunc:=c.indexers[indexName]ifindexFunc==nil{

returnnil,fmt.Errorf("Indexwithname%sdoesnotexist",indexName)

}

index:=c.indices[indexName]set:=index[indexKey]

list:=make([]interface{},0,set.Len())for_,key:=rangeset.List(){

list=append(list,c.items[key])

}

 

returnlist,nil


}

 

上述方法接收两个参数:indexName(索引器的名称)indexedValue需要索引的 Key。首先根据索引器名称查找指定的索引器函数c.indexers[indexName]);然后根据索引器名称查找相应的缓存器函数(c.indices[indexName]) ;最后根据索引 Key

indexedValue)从缓存中进行数据查询,并返回查询结果。

相关文章
|
9天前
|
Kubernetes Cloud Native 持续交付
云原生技术在现代应用开发中的角色与实践
【9月更文挑战第9天】 随着云计算技术的飞速发展,云原生(Cloud Native)已经成为推动企业数字化转型的核心力量。本文将深入探讨云原生的基本概念、关键技术及其在实际开发中的应用案例,旨在为读者提供一条清晰的云原生技术学习路径和应用指南。通过实例分析,我们将揭示云原生如何优化资源管理、提升应用性能及加快部署速度,进而帮助企业构建更加灵活、可靠和高效的软件系统。
|
6天前
|
Cloud Native 持续交付 云计算
云原生技术在现代应用开发中的应用与实践
【9月更文挑战第12天】随着云计算技术的飞速发展,云原生已成为推动企业数字化转型的关键技术之一。本文将深入探讨云原生的基本概念、核心价值及其在现代应用开发中的实际应用案例,旨在为读者提供一套清晰的云原生应用开发指南。通过分析容器化、微服务架构、持续部署等核心技术的实践过程,我们将揭示云原生如何助力开发者高效构建、部署和管理可扩展的应用。你将看到代码示例,这些示例均选自真实世界的开发场景,帮助你理解云原生技术的强大功能和灵活性。
|
6天前
|
运维 Cloud Native Devops
云原生架构的崛起与实践云原生架构是一种通过容器化、微服务和DevOps等技术手段,帮助应用系统实现敏捷部署、弹性扩展和高效运维的技术理念。本文将探讨云原生的概念、核心技术以及其在企业中的应用实践,揭示云原生如何成为现代软件开发和运营的主流方式。##
云原生架构是现代IT领域的一场革命,它依托于容器化、微服务和DevOps等核心技术,旨在解决传统架构在应对复杂业务需求时的不足。通过采用云原生方法,企业可以实现敏捷部署、弹性扩展和高效运维,从而大幅提升开发效率和系统可靠性。本文详细阐述了云原生的核心概念、主要技术和实际应用案例,并探讨了企业在实施云原生过程中的挑战与解决方案。无论是正在转型的传统企业,还是寻求创新的互联网企业,云原生都提供了一条实现高效能、高灵活性和高可靠性的技术路径。 ##
16 3
|
5天前
|
运维 Cloud Native 持续交付
云原生技术:探索现代应用开发的新纪元
本文深入探讨了云原生技术的崛起,以及它如何彻底改变现代应用开发和部署的方式。我们将从云原生的基本概念入手,逐步解析其核心技术如容器化、微服务架构及自动化运维,并展示这些技术如何帮助开发者和企业实现更高效、更灵活的应用管理。通过实际案例分析,我们将揭示云原生技术在提升开发效率、优化资源利用和增强系统可扩展性方面的巨大潜力。
|
6天前
|
Cloud Native 持续交付 开发者
云原生技术在现代应用开发中的角色与实践
【9月更文挑战第12天】本文将探索云原生技术的核心概念及其在现代软件开发中的应用。通过分析容器化、微服务架构、持续集成/持续部署(CI/CD)和DevOps文化的融合,我们旨在揭示如何利用这些技术提升软件的可靠性、可扩展性和交付速度。同时,文章还将展示一个简化的代码示例,以直观地说明云原生技术的实际应用。
|
13天前
|
监控 Cloud Native 持续交付
云原生时代的微服务架构实践
【9月更文挑战第5天】随着云计算技术的飞速发展,云原生已成为现代软件开发的重要趋势。本文将深入探讨在云原生环境下,如何有效实施微服务架构,包括服务拆分、容器化部署、持续集成与交付等关键环节。通过具体案例,我们将展示如何在云平台上构建弹性、可扩展的微服务应用,并讨论在此过程中可能遇到的挑战及解决策略。
|
12天前
|
监控 Cloud Native 安全
云原生时代的微服务架构实践
【9月更文挑战第6天】在数字化转型的浪潮中,云原生技术以其灵活性、可扩展性成为企业架构升级的首选。本文将通过浅显易懂的语言和生动的比喻,带你一探微服务架构的世界,从理论到实践,逐步揭示如何利用云原生技术构建高效、可靠的微服务系统,同时穿插代码示例,为有志于云原生领域发展的技术人员提供一份实操指南。
29 2
|
14天前
|
Cloud Native 持续交付 Docker
云原生技术实践:Docker容器化部署教程
【9月更文挑战第4天】本文将引导你了解如何利用Docker这一云原生技术的核心工具,实现应用的容器化部署。文章不仅提供了详细的步骤和代码示例,还深入探讨了云原生技术背后的哲学,帮助你理解为何容器化在现代软件开发中变得如此重要,并指导你如何在实际操作中运用这些知识。
|
13天前
|
运维 Cloud Native 持续交付
云原生时代下的微服务架构实践
在数字化转型的浪潮中,云原生技术以其高效、灵活的特性成为企业IT架构升级的首选。本文将通过深入浅出的方式,探讨云原生环境下微服务架构的设计原则、关键技术及实施策略,旨在为读者提供一条清晰的技术路线图,帮助理解和掌握在云平台上构建和管理微服务的实用方法。
|
16天前
|
运维 Cloud Native Devops
云原生时代的DevOps实践:自动化、持续集成与持续部署
【9月更文挑战第3天】未来,随着人工智能、大数据等技术的不断融入,DevOps实践将更加智能化和自动化。我们将看到更多创新的技术和工具涌现出来,为软件开发和运维带来更多便利和效益。同时,跨团队协作和集成也将得到进一步加强,推动软件开发向更加高效、可靠和灵活的方向发展。

热门文章

最新文章