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

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

2.2.6        Client-go Informer 解析

 

1. Client-goInformer模块

 

Informer可以对 KubernetesAPIServer的资源执行 Watch操作 , 类型可以是Kubernetes内置资源,也可以是 CRD。其中最核心的模块是 Reflector、DeltaFIFO、Indexer。接下来我们逐个进行分析。


首先分析   Reflector,Reflector   用于监控指定资源的    Kubernetes。当资源发生变化时,如发生了资源添加(Added、资源更新Updated等事件,Reflector会将其资源对象存放在本地缓存   DeltaFIFO   中。它的作用就是获取 APIServer中对象数据并实时地更新到本地,使得本地数据和ETCD数据完全一样。它的数据结构见代码清单2-37

typeReflectorstruct{

namestring//这个 Reflector的名称,默认为⽂件 : ⾏数metrics*reflectorMetrics//⽤于保存 Reflector的⼀些监控指标expectedTypereflect.Type//期望放到 Store中的类型名称storeStore//Watch源同步的⽬标Store

listerWatcherListerWatcher//ListerWatcher接⼝,⽤于指定 List-Watch⽅法

period           time.Duration//Watch周期resyncPeriodtime.Duration//重新同步周期ShouldResyncfunc() bool

//clockallowsteststomanipulatetimeclockclock.Clock

lastSyncResourceVersionstring//最后同步的资源的版本号

lastSyncResourceVersionMutexsync.RWMutex//lastSyncResourceVersion的读写锁


}

 

通过 NewRefector实例化 Reflector对象,实例化过程中必须传入 ListerWatcher据接口对象,它拥有ListWatch方法,用于获取及监控资源列表,只要是实现了 ListWatch方法的对象都可以成为 ListerWatcher,Reflector对象通过 run函数启动监控并处理事件,而在 Reflector源码实现中最主要的是List-Watch函数,它负责 List/Watch指定的 KubernetesAPIServer资源,见代码清单 2-38。

//NewNamedReflectorsameasNewReflector,butwithaspecifiednameforloggingfunc NewNamedReflector(name string, lw ListerWatcher, expectedType interface{},storeStore,resyncPeriodtime.Duration)*Reflector{

reflectorSuffix := atomic.AddInt64(&reflectorDisambiguator, 1)r:=&Reflector{

name:name,

//weneedthistobeuniqueperprocess(somenamesarestillthesame)butobviouswhoitbelongsto

metrics:        newReflectorMetrics(makeValidPrometheusMetricLabel(fmt.

Sprintf("reflector_"+name+"_%d",reflectorSuffix))),

listerWatcher:lw,store:store,

expectedType:reflect.TypeOf(expectedType),

period:    time.Second,resyncPeriod:resyncPeriod,clock:&clock.RealClock{},

}

returnr

}


List-Watch是怎么实现的? List-Watch主要分为 ListWatch两部分。List责获取对应资源的全量列表,Watch负责获取变化的部分。首先进行 List操作,这里把ResourceVersion设置为 0,因为要获取同步的对象的全部版本,所以从 0开始 List,主要流程如下(见代码清单2-39

(1)r.listerWatcher.List 用于获取资源下的所有对象的数据。

(2)  listMetaInterface.GetResourceVersion   用于获取资源版本号(ResouceVersion,资源版本号非常重要,Kubernetes中所有的资源都拥有该字段,它标识当前资源对象的版本号。每次修改当前资源对象时,KubernetesAPIServer都会更改 ResouceVersion,使Client-go执行 Watch操作时可以根据 ResourceVersion 来确定当前资源对象是否发生过变化。

(3)   meta.ExtractList用于将资源数据转换成资源对象列表,将runtime.Object转换成[]runtime.Object,因为 r.listerWatcher.List只是获取一个列表。

4r.syncWith 用于将资源对象列表中的资源对象和资源版本号存储至DeltaFIFO中,并替换已存在的对象。

(5)r.setLastSyncResourceVersion 用于设置最新的资源版本号。


func(r*Reflector)ListAndWatch(stopCh<-chanstruct{})error{glog.V(3).Infof("Listingandwatching%vfrom%s",r.expectedType,r.name)varresourceVersionstring

options:=metav1.ListOptions{ResourceVersion:"0"}r.metrics.numberOfLists.Inc()

start:=r.clock.Now()

list,err:=r.listerWatcher.List(options)iferr!=nil{

returnfmt.Errorf("%s:Failedtolist%v:%v",r.name,r.expectedType,

err)

}

r.metrics.listDuration.Observe(time.Since(start).Seconds())listMetaInterface,err:=meta.ListAccessor(list)

iferr!=nil{

returnfmt.Errorf("%s:Unabletounderstandlistresult%#v:%v",


r.name,list,err)

}

resourceVersion=listMetaInterface.GetResourceVersion()items,err:=meta.ExtractList(list)

iferr!=nil{

returnfmt.Errorf("%s:Unabletounderstandlistresult%#v(%v)",r.name,list,err)

}

r.metrics.numberOfItemsInList.Observe(float64(len(items)))

iferr:=r.syncWith(items,resourceVersion);err!=nil{

returnfmt.Errorf("%s:Unabletosynclistresult:%v",r.name,err)

}

r.setLastSyncResourceVersion(resourceVersion)

 

resyncerrc:=make(chanerror,1)


cancelCh:=make(chanstruct{})deferclose(cancelCh)

gofunc(){

resyncCh,cleanup:=r.resyncChan()deferfunc(){

cleanup()//Callthelastonewrittenintocleanup

}()

for{

select{

case<-resyncCh:case<-stopCh:

returncase<-cancelCh:

return

}

ifr.ShouldResync==nil||r.ShouldResync(){glog.V(4).Infof("%s:forcingresync",r.name)iferr:=r.store.Resync();err!=nil{

resyncerrc<-errreturn

}

}

}()

 

for{


cleanup()

resyncCh,cleanup=r.resyncChan()

}

//givethestopChachancetostoptheloop,evenincaseofcontinue


statementsfurtherdownonerrorsselect{

case<-stopCh:

returnnildefault:

}

 

timeoutSeconds:=int64(minWatchTimeout.Seconds()* (rand.Float64()+


1.0))


options=metav1.ListOptions{ResourceVersion:resourceVersion,TimeoutSeconds:&timeoutSeconds,


}

 

r.metrics.numberOfWatches.Inc()

w,err:=r.listerWatcher.Watch(options)


 

 

iferr!=nil{

switcherr{

caseio.EOF:

//watchclosednormally

caseio.ErrUnexpectedEOF:

glog.V(1).Infof("%s:Watchfor%vclosedwithunexpected

EOF:%v",r.name, r.expectedType, err)

default:

utilruntime.HandleError(fmt.Errorf("%s:Failedtowatch

%v:%v",r.name,r.expectedType,err))

}

ifurlError,ok:=err.(*url.Error);ok{

ifopError,ok:=urlError.Err.(*net.OpError);ok{

iferrno,ok:=opError.Err.(syscall.Errno);ok&&

errno==syscall.ECONNREFUSED{

time.Sleep(time.Second)continue

}

}

}

returnnil

}

 


 

err!=nil{


iferr:=r.watchHandler(w,&resourceVersion,resyncerrc,stopCh);

 

iferr!=errorStopRequested{

glog.Warningf("%s:watchof%vendedwith:%v",r.name,


r.expectedType,err)

}

returnnil

}

}

}

 

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
3天前
|
运维 Cloud Native 持续交付
构建未来:云原生架构的演变与实践
【5月更文挑战第17天】 在数字化转型的浪潮中,企业正迅速采用云原生技术来构建和部署应用程序。本文将深入探讨云原生架构的核心概念、发展历程以及如何在现代IT环境中实现敏捷、可扩展和高效的服务。通过对容器化、微服务、持续集成和持续部署(CI/CD)等关键技术的分析,我们将揭示如何利用云原生方法论来优化资源利用、加快产品上市速度,并提高系统的可靠性。
13 3
|
5天前
|
存储 Java Go
Go 语言切片如何扩容?(全面解析原理和过程)
Go 语言切片如何扩容?(全面解析原理和过程)
15 2
|
5天前
|
Kubernetes Cloud Native 持续交付
构建高效稳定的云原生应用:容器编排与微服务治理实践
【5月更文挑战第14天】 随着企业数字化转型的深入,云原生技术以其弹性、敏捷和可扩展的特性成为现代应用开发的首选模式。本文将探讨如何通过容器编排工具如Kubernetes以及微服务架构的有效治理,构建和维护高效且稳定的云原生应用。我们将分析容器化技术的优势,并结合案例讨论在多云环境下实现持续集成、持续部署(CI/CD)的最佳实践,同时解决微服务带来的分布式复杂性问题。通过本文的阐述,读者将获得一套提升系统可靠性和业务连续性的策略框架。
7 0
|
5天前
|
负载均衡 监控 Go
Golang深入浅出之-Go语言中的服务网格(Service Mesh)原理与应用
【5月更文挑战第5天】服务网格是处理服务间通信的基础设施层,常由数据平面(代理,如Envoy)和控制平面(管理配置)组成。本文讨论了服务发现、负载均衡和追踪等常见问题及其解决方案,并展示了使用Go语言实现Envoy sidecar配置的例子,强调Go语言在构建服务网格中的优势。服务网格能提升微服务的管理和可观测性,正确应对问题能构建更健壮的分布式系统。
30 1
|
5天前
|
JSON 监控 安全
Golang深入浅出之-Go语言中的反射(reflect):原理与实战应用
【5月更文挑战第1天】Go语言的反射允许运行时检查和修改结构,主要通过`reflect`包的`Type`和`Value`实现。然而,滥用反射可能导致代码复杂和性能下降。要安全使用,应注意避免过度使用,始终进行类型检查,并尊重封装。反射的应用包括动态接口实现、JSON序列化和元编程。理解反射原理并谨慎使用是关键,应尽量保持代码静态类型。
25 2
|
5天前
|
机器学习/深度学习 Cloud Native 持续交付
构建高效机器学习模型的策略与实践构建未来:云原生技术在企业数字化转型中的关键作用
【4月更文挑战第30天】 在机器学习领域,构建一个高效的模型不仅需要深厚的理论基础,还需结合先进的技术手段和策略。本文将探讨一系列提升模型性能的方法,包括数据预处理、特征选择、模型调参以及集成学习等。通过具体案例分析,揭示这些方法如何在实际问题中得以应用,并讨论它们对模型性能的影响。文中还将涉及最新的研究进展,为读者提供前瞻性的指导意义。 【4月更文挑战第30天】随着企业加速其数字化转型之旅,云原生技术已成为推动创新和灵活性的核心。本文深入探讨了云原生架构的原则,包括微服务、容器化、持续集成/持续部署(CI/CD)、以及声明式APIs。分析了这些技术如何共同促进可伸缩性、敏捷性和容错性,同时
|
5天前
|
Kubernetes 监控 Cloud Native
构建未来:云原生架构的演进与实践
【4月更文挑战第30天】 随着数字化转型的不断深入,企业对IT基础设施的要求日益提高。云原生技术以其独特的弹性、可扩展性和敏捷性成为推动现代应用开发的关键动力。本文将探讨云原生架构的核心组件、实施策略以及面临的挑战,旨在为读者提供一个关于如何有效构建和部署云原生应用的全面视角。
|
5天前
|
Cloud Native Devops 持续交付
构建未来应用:云原生架构在现代企业中的实践与挑战
【4月更文挑战第29天】 随着数字化转型的加速,企业正迅速转向云计算以支撑其业务敏捷性和创新。云原生技术,作为推动这一转型的关键因素,正在重新定义软件开发和运维模式。本文将深入探讨云原生架构的核心组件,包括容器化、微服务、持续集成/持续部署(CI/CD)以及DevOps文化,并分析这些技术如何帮助企业实现弹性、可扩展和高效的应用部署。同时,我们将讨论在采纳云原生实践中所面临的挑战,包括安全性、治理和人才缺口等问题。
|
5天前
|
运维 Cloud Native Devops
构建未来应用:云原生架构的演进与实践
【4月更文挑战第29天】在数字化转型的浪潮中,企业亟需灵活、高效的技术支撑来应对市场的快速变化。云原生架构以其独特的设计理念和技术栈,成为推动这一变革的关键力量。本文深入探讨了云原生的核心概念、关键技术和实施策略,旨在为企业提供一个清晰的云原生转型蓝图,助力其构建更加动态、可扩展的应用系统。
|
5天前
|
Kubernetes Cloud Native 持续交付
构建未来:云原生架构在现代企业中的应用与实践
【4月更文挑战第29天】 随着数字化转型的浪潮席卷各行各业,企业对于信息技术基础设施的要求日益提高。传统的IT架构已难以满足快速迭代、灵活扩展和持续创新的需求。本文聚焦于云原生架构,一种为云计算环境量身打造的设计理念和技术集合,旨在帮助企业构建更加灵活、可靠和高效的系统。通过对云原生核心组件的解析、实施策略的探讨以及成功案例的分析,我们揭示了云原生架构如何助力企业在竞争激烈的市场中保持领先地位。

热门文章

最新文章