带你读《云原生应用开发:Operator原理与实践》——2.2.5 List-Watch 原理

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 带你读《云原生应用开发:Operator原理与实践》——2.2.5 List-Watch 原理

2.2.5 List-Watch 原理


List-Watch 机制是 Kubernetes 的系统消息通知机制,该机制确保了消息的实时性、顺序性和可靠性。List-Watch 由两部分组成:List 和 Watch。List 负责调用资源的 List RESTful API ,基于 HTTP 短链接实现;Watch 则调用资源的 Watch RESTful API,负责监听资源变更事件,基于 HTTP 长链接实现,也是本节重点分析的对象。

以 Deployment 资源为例,调用其 List 和 Watch 接口,结果见代码清单 2-33。

List 接口返回 Deployment 资源列表,比较简单。

代码清单 2-33

GET /apis/apps/v1/deployments
...
{
 "kind": "DeploymentList",
 "apiVersion": "apps/v1",
 "metadata": {...}
 "items": [
 {
 "metadata": {...},
 "spec": {...},
 "status": {...}
 },
 ...
 ]
}

Watch 接口返回事件(Event),这里采用 HTTP 长链接持续监听 Deployment 资源相关事件,每当有事件产生就返回一个 Event 。返回值的类型有 ADDED、MODIFIED 等,表示增加、修改等操作,Object 包含变更后最新的资源信息。

这里 Watch 接口的实现利用了 HTTP/1.1 协议的分块传输编码(Chunked Transfer Encoding),当客户端调用 Watch 接口时,Kubernetes APIServer 在 Response Header 中设置 Transfer-Encoding 的值为 chunked(见代码清单 2-34),表示采用分块传输编码,客户端收到该信息后,便和服务端保持该链接,并等待下一个数据块,即资源的事件信息。

代码清单 2-34

GET /apis/apps/v1/watch/deployments?watch=yes
---
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
...
{
 "type": "MODIFIED",
 "object": {
 "kind": "Deployment",
 "apiVersion": "apps/v1",
 "metadata": {...},
 "spec": {...},
 "status": {...}
 }
}

维 基 百 科

HTTP 分块传输编码允许服务器为动态生成的内容维持 HTTP 持久链接。通常,持久链接需要服务器在开始发送消息体前发送 Content-Length 消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。使用分块传输编码将数据分解成一系列数据块,并以一个或多个块发送,这样服务器发送数据时不需要预先知道发送内容的总的大小。

List-Watch 功能对应到 Client-go 中,就由 Reflector 组件负责实现,其本质是将 Kubernetes 中的对象资源数据存储到本地并实时更新,拥有很高的可靠性、实时性和顺序性。Reflector 首先通过 List 获取 Kubernetes 中指定类型的资源对象,基于资源对象的 ResourceVersion 信息,使用 Watch 监听该类型资源事件,从而确保事件消息的实时性,并且资源对象 ResourceVersion 的递增特性确保了消息事件的顺序性。当 Watch 监听意外断开时,Reflector 会重新 List-Watch 资源,以确保可靠性,由于使用 Watch 长链接监听替换轮询 List 来获得最新资源状态,极大减轻了 Kubernetes APIServer 的访问压力,在确保消息事件实时性的同时也保证了性能。

下面分析 Reflector 的关键实现,首先通过 NewReflector 函数创建 Reflector 对象,通过 Run 方法启动监听并处理事件,而 Run 方法中最核心的就是 List-Watch 方法,其核心逻辑分为 List、定时同步、Watch 这 3 个部分。

(1) List:调用 List 方法获取资源数据,将其转化为资源对象列表,并最终同步到 DeltaFIFO 队列中。

(2)定时同步:利用定时器定时触发 Resync 机制,将 Indexer 中的资源对象同步到 DeltaFIFO 队列中。

(3) Watch:监听环境中资源的变化,并调用相应事件处理函数进行处理。

核心代码分析见代码清单 2-35。

代码清单 2-35

func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
 //...
 if err := func() error {
 //...
 
 go func() {
 //...
 // 如果 listerWatcher 支持,则尝试以块的形式收集列表
 // 如果 listerWatcher 不支持,则尝试第一个列表请求返回完整的响应
 pager := pager.New(pager.SimplePageFunc(func(opts metav1.ListOptions) (runtime.
Object, error) {
 return r.listerWatcher.List(opts)
 }))
 
 //...
 // 返回完整列表
 list, err = pager.List(context.Background(), options)
 }()
 
 //...
 // 获取资源版本号
 resourceVersion = listMetaInterface.GetResourceVersion()
 
 // 将资源数据转换为资源对象列表
 items, err := meta.ExtractList(list)
 
 // 将资源信息存储到 DeltaFIFO 中
 if err := r.syncWith(items, resourceVersion); err != nil {
 return fmt.Errorf("unable to sync list result: %v", err)
 }
 //...
 }(); err != nil {
 return err
 }
go func() {
 // 返回重新同步的定时通道,里面有计时器
 resyncCh, cleanup := r.resyncChan()
 //...
 for {
 //...
 if r.ShouldResync == nil || r.ShouldResync() {
 // Resync 机制会将 Indexer 本地存储的资源对象同步到 DeltaFIFO 中
 if err := r.store.Resync(); err != nil {
 //...
 }
 }
 // 重新启用定时器定时触发
 resyncCh, cleanup = r.resyncChan()
 }
 }()
 for {
 ...
 // 监听资源变化
 w, err := r.listerWatcher.Watch(options)
 // 处理监听到的各类事件,并调用预先注册的 Add、Delete、Update 函数进行处理
 if err := r.watchHandler(start, w, &resourceVersion, resyncerrc, stopCh);
 ...
 }
} 

其中, watchHandler 中设置了事件处理函数,从 ResultChan() 方法返回的 Channel 中获取事件,并根据事件类型(event.Type)将事件分发给对应的处理函数,这里处理函数的逻辑都是将事件同步到 DeltaFIFO 队列中,具体见代码清单 2-36。

代码清单 2-36

func (r *Reflector) watchHandler(start time.Time, w watch.Interface, resourceVersion 
*string, errc chan error, stopCh <-chan struct{}) error {
 //...
 for {
 select {
 //...
 case event, ok := <-w.ResultChan():
 //...
 switch event.Type {
 case watch.Added:
 err := r.store.Add(event.Object)
 case watch.Modified:
 err := r.store.Update(event.Object)
 case watch.Deleted:
 err := r.store.Delete(event.Object)
 }
 //...
 }
 }
 //...
}
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
7天前
|
Kubernetes Cloud Native 持续交付
云原生技术在现代应用开发中的角色与实践
【9月更文挑战第9天】 随着云计算技术的飞速发展,云原生(Cloud Native)已经成为推动企业数字化转型的核心力量。本文将深入探讨云原生的基本概念、关键技术及其在实际开发中的应用案例,旨在为读者提供一条清晰的云原生技术学习路径和应用指南。通过实例分析,我们将揭示云原生如何优化资源管理、提升应用性能及加快部署速度,进而帮助企业构建更加灵活、可靠和高效的软件系统。
|
4天前
|
Cloud Native 持续交付 云计算
云原生技术在现代应用开发中的应用与实践
【9月更文挑战第12天】随着云计算技术的飞速发展,云原生已成为推动企业数字化转型的关键技术之一。本文将深入探讨云原生的基本概念、核心价值及其在现代应用开发中的实际应用案例,旨在为读者提供一套清晰的云原生应用开发指南。通过分析容器化、微服务架构、持续部署等核心技术的实践过程,我们将揭示云原生如何助力开发者高效构建、部署和管理可扩展的应用。你将看到代码示例,这些示例均选自真实世界的开发场景,帮助你理解云原生技术的强大功能和灵活性。
|
3天前
|
运维 Cloud Native 持续交付
云原生技术:探索现代应用开发的新纪元
本文深入探讨了云原生技术的崛起,以及它如何彻底改变现代应用开发和部署的方式。我们将从云原生的基本概念入手,逐步解析其核心技术如容器化、微服务架构及自动化运维,并展示这些技术如何帮助开发者和企业实现更高效、更灵活的应用管理。通过实际案例分析,我们将揭示云原生技术在提升开发效率、优化资源利用和增强系统可扩展性方面的巨大潜力。
|
4天前
|
Cloud Native 持续交付 开发者
云原生技术在现代应用开发中的角色与实践
【9月更文挑战第12天】本文将探索云原生技术的核心概念及其在现代软件开发中的应用。通过分析容器化、微服务架构、持续集成/持续部署(CI/CD)和DevOps文化的融合,我们旨在揭示如何利用这些技术提升软件的可靠性、可扩展性和交付速度。同时,文章还将展示一个简化的代码示例,以直观地说明云原生技术的实际应用。
|
1月前
|
运维 Cloud Native Android开发
云原生之旅:容器化与微服务架构的融合之道安卓应用开发入门指南
本文将深入探讨云原生技术的核心要素——容器化和微服务架构,并揭示它们如何共同推动现代软件的开发与部署。通过实际案例分析,我们将看到这两种技术如何相辅相成,助力企业实现敏捷、可扩展的IT基础设施。文章旨在为读者提供一条清晰的道路,指引如何在云原生时代利用这些技术构建和优化应用。 本文将引导初学者了解安卓应用开发的基本概念和步骤,从安装开发环境到编写一个简单的“Hello World”程序。通过循序渐进的讲解,让读者快速掌握安卓开发的核心技能,为进一步深入学习打下坚实基础。
39 1
|
19天前
|
Kubernetes Cloud Native 持续交付
云原生技术在现代应用开发中的应用
【8月更文挑战第29天】本文将探讨云原生技术在现代应用开发中的重要性,包括其概念、优势和实践。我们将通过代码示例来展示如何在云平台上构建和部署云原生应用。
|
3月前
|
存储 Java 测试技术
滚雪球学Java(57):解密Java中List接口底层实现原理
【6月更文挑战第11天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
36 2
滚雪球学Java(57):解密Java中List接口底层实现原理
|
3月前
|
运维 Cloud Native 持续交付
云原生技术:现代应用开发的革命性变革
云原生技术正在重新定义软件开发和部署的方式。通过采用容器、微服务、持续集成与持续交付(CI/CD)等关键技术,企业可以显著提升开发效率、缩短上市时间,并提高应用的可扩展性和可靠性。本文深入探讨了云原生技术的核心组件及其带来的实际业务价值,展示了其在现代应用开发中的革命性影响。
43 1
|
2月前
|
存储 Java 索引
Java List接口实现原理与性能评估
Java List接口实现原理与性能评估
|
3月前
|
Java 索引
JavaSE——集合框架一(3/7)-List系列集合:特点、方法、遍历方式、ArrayList集合的底层原理
JavaSE——集合框架一(3/7)-List系列集合:特点、方法、遍历方式、ArrayList集合的底层原理
34 2