Polaris系列-07.启动分析六

news2024/9/24 1:21:46

本篇分析 配置中心模块 启动流程:

先看启动配置参数:
在这里插入图片描述
进入方法:
在这里插入图片描述
先看看配置中心服务数据模型:初始化也是围绕着下面各个属性赋值...

// Server 配置中心核心服务
type Server struct {
	cfg *Config

	storage           store.Store
	fileCache         cachetypes.ConfigFileCache
	groupCache        cachetypes.ConfigGroupCache
	grayCache         cachetypes.GrayCache
	caches            cachetypes.CacheManager
	watchCenter       *watchCenter
	namespaceOperator namespace.NamespaceOperateServer
	initialized       bool

	history       plugin.History
	cryptoManager plugin.CryptoManager
	hooks         []ResourceHook

	// chains
	chains *ConfigChains

	sequence int64
}

初始化有幂等性,保证初始化一次;
和服务发现模块一样,也有服务代理proxySvr,也保存了原始的服务originServer实例对象:

// Initialize 初始化配置中心模块
func Initialize(ctx context.Context, config Config, s store.Store, cacheMgr cachetypes.CacheManager,
	namespaceOperator namespace.NamespaceOperateServer) error {
	if originServer.initialized {
		return nil
	}
	proxySvr, originSvr, err := doInitialize(ctx, config, s, cacheMgr, namespaceOperator)
	if err != nil {
		return err
	}
	originServer = originSvr
	server = proxySvr
	return nil
}

所以我们去看看是如何doInitialize(...)的:
在这里插入图片描述

再看上图中的第118行:originSvr.initialize(...): 点进去:
在这里插入图片描述
在这里插入图片描述

1.看看watchCenter结构体:

在这里插入图片描述

type SubscribtionContext struct {
	subID  string
	cancel context.CancelFunc
}

WatchContext interface {
	// ClientID .
	ClientID() string
	// ClientLabels .
	ClientLabels() map[string]string
	// AppendInterest .
	AppendInterest(item *apiconfig.ClientConfigFileInfo)
	// RemoveInterest .
	RemoveInterest(item *apiconfig.ClientConfigFileInfo)
	// ShouldNotify .
	ShouldNotify(event *model.SimpleConfigFileRelease) bool
	// Reply .
	Reply(rsp *apiconfig.ConfigClientResponse)
	// Close .
	Close() error
	// ShouldExpire .
	ShouldExpire(now time.Time) bool
	// ListWatchFiles
	ListWatchFiles() []*apiconfig.ClientConfigFileInfo
	// IsOnce
	IsOnce() bool
}

WatchContext接口有以下3个具体实现:long poll 它,出现了……
在这里插入图片描述
我们先只关注第2项:polaris下的watch.go(不考虑nacos)

type LongPollWatchContext struct {
	clientId         string
	labels           map[string]string
	once             sync.Once
	finishTime       time.Time
	finishChan       chan *apiconfig.ConfigClientResponse
	watchConfigFiles map[string]*apiconfig.ClientConfigFileInfo
	betaMatcher      BetaReleaseMatcher
}

2.再看 eventhub.Subscribe(eventhub.ConfigFilePublishTopic, wc, eventhub.WithQueueSize(QueueSize))
方法本身在上篇已经介绍:发布订阅模式,再贴出流程图:
在这里插入图片描述
这里我们先看看入参的值:见名知意:
在这里插入图片描述
第3个参数:队列长度:10240,还有那30秒,正是我们在Polaris系列-00.前言 篇中谈到“入坑”的缘由之一……
在这里插入图片描述
最后看第2个参数:wc,它实现了Handler接口:
在这里插入图片描述
在这里插入图片描述
所以依据上述流程,我们先看watchcenter监听到文件内容改变后是如何处理的:
先看消息数据模型:event.Message
在这里插入图片描述

type ConfigFileReleaseKey struct {
	Id          uint64
	Name        string
	Namespace   string
	Group       string
	FileName    string
	ReleaseType ReleaseType
}

type ReleaseType string

const (
	// ReleaseTypeFull 全量类型
	ReleaseTypeFull = ""
	// ReleaseTypeGray 灰度类型
	ReleaseTypeGray = "gray"
)

清楚了数据结构之后,我们再看实现:wc.notifyToWatchers(event.Message)
FYI: 省略了例外判断逻辑:

func (wc *watchCenter) notifyToWatchers(publishConfigFile *model.SimpleConfigFileRelease) {
	// namespace + group + filename 拼接起来
	watchFileId := utils.GenFileId(publishConfigFile.Namespace, publishConfigFile.Group, publishConfigFile.FileName)
	// watchers是一个map: fileId -> []clientId
	clientIds, _ := wc.watchers.Load(watchFileId)

	// 包装通知客户端入参模型:见下面解释说明1
	changeNotifyRequest := publishConfigFile.ToSpecNotifyClientRequest()
	// 配置变更客户端响应对象
	response := api.NewConfigClientResponse(apimodel.Code_ExecuteSuccess, changeNotifyRequest)

	notifyCnt := 0
	// 获取clientIds此刻的一个数据快照,再遍历之:
	clientIds.Range(func(clientId string) {
		// clientId -> watchContext
		watchCtx, _ := wc.clients.Load(clientId)
		// 是否要通知:见下面解释2
		if watchCtx.ShouldNotify(publishConfigFile) {
			// 解释3
			watchCtx.Reply(response)
			notifyCnt++
			// 只能用一次,通知完就要立马清理掉这个 WatchContext
			// 只有StreamWatchContext的IsOnce()实现才是false
			if watchCtx.IsOnce() {
				// 疑问4
				wc.RemoveAllWatcher(watchCtx.ClientID())
			}
		}
	})
	// 日志输出
}

解释说明1:
在这里插入图片描述
解释说明2: 后面新版本console中配置文件变更时会弹出框,让我们填写版本,防止我们无脑地随便更新……
在这里插入图片描述

func (c ConfigFileReleaseKey) FileKey() string {
	return fmt.Sprintf("%v@%v@%v", c.Namespace, c.Group, c.FileName)
}

解释3: 往finishChan chan中投递数据,看来早有人在守着此chan,等待读取里面数据:

func (c *LongPollWatchContext) Reply(rsp *apiconfig.ConfigClientResponse) {
	c.once.Do(func() {
		c.finishChan <- rsp
		close(c.finishChan)
	})
}

我们看看谁调用下面这2个方法(之一):
在这里插入图片描述
果然有客户端(而且只有一处调用)在监听等待结果。我们先不在这里去深入研究,只是确定一件事情:有人在监听此chan,获取配置变更最新结果。而上图另一个GetNotifieResultWithTime(...)只出现在client_test.go文件中,长舒一口气…
在这里插入图片描述
疑问, 从上述代码中:wc.RemoveAllWatcher(watchCtx.ClientID())
用了一次watchCtx后就删除了,这……那后续文件再变更怎么办?我们接着看…

3.go wc.startHandleTimeoutRequestWorker(ctx):每秒检测,移除过期的订阅者:
在这里插入图片描述

func (c *LongPollWatchContext) ShouldExpire(now time.Time) bool {
	return now.After(c.finishTime)
}

type LongPollWatchContext struct {
	clientId         string
	labels           map[string]string
	once             sync.Once
	finishTime       time.Time
	finishChan       chan *apiconfig.ConfigClientResponse
	watchConfigFiles map[string]*apiconfig.ClientConfigFileInfo
	betaMatcher      BetaReleaseMatcher
}

看来我们丢失了一些环节,比如s.clients 是什么时候/如何 关联上值的?
还有上面提出的那个疑问:后续再有文件变更又该如何,毕竟你都移除了watchCtx

我们先把整体梳理完,再尝试去找答案…

初始化配置中心核心服务 Server数据模型后,往下:
在这里插入图片描述
在这里插入图片描述
进入第一个代理:上上图的第132行:
在这里插入图片描述
在这里插入图片描述
第二层代理:
在这里插入图片描述
在这里插入图片描述
至此,配置中心初始化大概流程介绍完毕。下一篇从下面蓝行开始:
在这里插入图片描述


我们回头看看上面留的两个问题:

  1. s.clients 是什么时候/如何 关联上值的?
  2. 后续再有文件变更又该如何,毕竟你都移除了watchCtx

先看2: 既然有删除,那肯定有添加:
在这里插入图片描述
查找调用点:nacos我们不看,只看第2个红框:
在这里插入图片描述
在这里插入图片描述
此方法实现的接口:
在这里插入图片描述
我们看看上上图的第113行:
1.先看第3个参数:默认30秒超时,正是对应hold住请求30秒:
在这里插入图片描述
进入AddWatcher(...):
在这里插入图片描述
上面的超时30秒 结合上方中的 3.go wc.startHandleTimeoutRequestWorker(ctx):每秒检测,移除过期的订阅者方法 正是 官方wiki文档 Polaris系列00篇说到的 默认hold住请求30秒…

我们本着尝试解答疑问2,没想到把疑问1也解答了。。。

最后我们再看看谁调用了LongPullWatchFile(...): 两种实现: http + grpc:
在这里插入图片描述
在这里插入图片描述
最后,我还是有些说服不了自己,文件变更后,移除了watchCtx, 那是不是客户端就主动再发起监听呢,这样咱们Polaris- server服务器才能在配置文件变更时再次推送给客户端?只能理解成这就是一个http/grpc请求,既然在这一次请求中收到配置文件内容变更,那就算是完成了本次监听的使命,后续要监听的话,客户端只能主动再发起请求监听。如果知情者看到此疑问,请不吝解惑,谢谢。

今天周六,加班的感觉。。。有点顶… 状态不佳,最后祝大家周末愉快…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1938172.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机13(动态数码管实验)

一、数码管动态显示原理 1、动态显示是利用减少段选线&#xff0c;分开位选线&#xff0c;利用位选线不同时选择通断&#xff0c;改变段选数据来实现的。 &#xff08;1&#xff09;多位数码管依然可以进行静态的一个显示&#xff0c;那么在前面我们介绍静态数码管的时候&…

VTK源码分析:Type System

作为一款开源跨平台的数据可视化代码库&#xff0c;VTK以其清晰的流水线工作方式、丰富的后处理算法、异种渲染/交互方式&#xff0c;而被众多CAx软件选作后处理实施方案。而异种渲染/交互方式的实现&#xff0c;主要是倚重于VTK的类型系统&#xff0c;因此&#xff0c;有必要对…

visio保存一部分图/emf图片打开很模糊/emf插入到word或ppt中很模糊

本文主要解决三个问题 visio保存一部分图 需求描述&#xff1a;在一个visio文件中画了很多个图&#xff0c;但我只想把其中一部分保存成某种图片格式&#xff0c;比如jpg emf png之类的&#xff0c;以便做后续的处理。 方法&#xff1a;超级容易。 选中希望保存的这部分图&…

免费【2024】springboot 爱看漫画小程序的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

分布式搜索之Elasticsearch入门

Elasticsearch 是什么 Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心&#xff0c;它集中存储您的数据&#xff0c;帮助您发现意料之中以及意料之外的情况。 Elastic Stack 又是什么呢&a…

使用docker swarm搭建ruoyi集群环境

整体目标 项目背景 领导给到了我一个客户&#xff0c;客户商业模式为成本制作&#xff0c;成本核算。其中涉及到大量涉密数据&#xff0c;且与我们现有产品几乎没有兼容点&#xff08;我们是一套低代码的框架&#xff0c;客户有很多业务二开&#xff09; 测试环境给到了我6台…

黑马微服务拆分2 (路由 登录 配置)

会利用微服务网关做请求路由 会利用微服务网关做登录身份校验 会利用Nacos实现统一配置管理 会利用Nacos实现配置热更新 今天粗略的完成了黑马笔记里边的代码实现 其实本身黑马商城的源码就写的逻辑有漏洞&#xff0c;加上对业务没有仔细分析 导致出现的bug调试了很久 这…

如何判断自己的数据格式适合使用json还是Excel的形式存入neo4j数据库

判断自己的数据格式适合使用JSON还是Excel的形式存入Neo4j数据库&#xff0c;主要取决于数据的复杂性、规模、结构、以及你或你的团队对这两种格式的熟悉程度。以下是一些关键因素&#xff0c;可以帮助你做出决策&#xff1a; 数据的复杂性&#xff1a; 如果你的数据包含大量的…

【Zynq UltraScale+ RFSoC】~~~

Zynq UltraScale RFSoC 系列为 5G 无线和射频级模拟应用引入了颠覆性的集成和架构突破&#xff0c;可直接支持整个 5G sub-6GHz 频段。这个创新系列现已开始批量生产。此设计演示展示了多通道&#xff08;8T8R 或 16T16R&#xff09;Zynq UltraScale RFSoC 评估工具工具工具&am…

ICMP 和 IGMP 的区别

ICMP 和 IGMP 协议 IP 层分支图 ICMP&#xff08;Internet Control Message Protocol&#xff0c;因特网控制信息协议&#xff09; 用于补充 IP 传输数据报的过程中&#xff0c;发送主机无法确定数据报是否到达目标主机。 ICMP 报文分为出错报告报文和查询报文两种。 若数据…

C语言 | Leetcode C语言题解之第263题丑数

题目&#xff1a; 题解&#xff1a; bool isUgly(int n) {if (n < 0) {return false;}int factors[] {2, 3, 5};for (int i 0; i < 3; i) {while (n % factors[i] 0) {n / factors[i];}}return n 1; }

python:本机摄像头目标检测实时推理(使用YOLOv8n模型)

本文将介绍如何使用本机摄像头进行目标检测实时推理的python代码。 文章目录 一、下载YOLO权重文件二、环境配置三、完整代码 一、下载YOLO权重文件 https://github.com/ultralytics/ultralytics?tabreadme-ov-file 拉到网页最下面&#xff0c;选择适合的模型&#xff0c;下…

Armv8/Armv9架构的学习大纲-学习方法-自学路线-付费学习路线

本文给大家列出了Arm架构的学习大纲、学习方法、自学路线、付费学习路线。有兴趣的可以关注&#xff0c;希望对您有帮助。 如果大家有需要的&#xff0c;欢迎关注我的CSDN课程&#xff1a;https://edu.csdn.net/lecturer/6964 ARM 64位架构介绍 ARM 64位架构介绍 ARM架构概况…

56、本地数据库迁移到阿里云

现有需求&#xff0c;本地数据库迁移到阿里云上。 库名xy102表 test01test02test01 test023条数据。1、登录阿里云界面创建免费试用ECS实列。 阿里云登录页 (aliyun.com)](https://account.aliyun.com/login/login.htm?oauth_callbackhttps%3A%2F%2Fusercenter2.aliyun.com%…

Spring -- 三层架构

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 应用分层 介绍 在阿里的开发手册里,关于工程结构部分,定义的常见工程的应用分层结构 那么什么是应用分层呢? 应用分层是一种软件开发设计思想,他将应用程序分层N个层次.这N个层次分别负责各…

JVM:JavaAgent技术

文章目录 一、Java工具的介绍二、Java Agent技术1、介绍2、静态加载模式3、动态加载模式 三、搭建java agent静态加载模式环境1、创建maven项目2、编写类和premain方法3、编写MANIFEST.MF文件4、使用maven-assembly-plugin进行打包5、创建Spring Boot应用 一、Java工具的介绍 …

Vscode离线下载对应版本的ms-python.vsix

一、查看vscode的版本号和发行时间 vscode界面中Help-About查看版本号和发行时间&#xff0c;ms-python的发行时间需要和这个时间相近&#xff1a; 二、在github仓库中查看ms-python有什么版本&#xff0c;以及发行时间 github仓库路径 https://github.com/microsoft/vsco…

算法学习笔记(Hello算法)—— 时间复杂度

1.1 统计时间增长趋势 时间复杂度分析统计的不是算法运行时间&#xff0c;而是算法运行时间随着数据量变大时的增长趋势。 // 算法 A 的时间复杂度&#xff1a;常数阶 void algorithm_A(int n) {System.out.println(0); }// 算法 B 的时间复杂度&#xff1a;线性阶 void algo…

计算机网络入门 -- TCP详解

计算机网络入门 – TCP详解 1.TCP协议 1.1 报文格式 1.32位序号&#xff1a;该条TCP数据携带的起始序号。 2.32位确认序号&#xff1a;期望对方发送数据从那个序号开始发送。 3.4位首部长度&#xff1a;最大为0xF(15)&#xff0c;指的是TCP头部长度。 首部长度 4 位首部长…

huawei USG6001v1学习---防火墙高可靠性(双机热备)

1.什么是双机热备 如图&#xff1a;当左图的防火墙发生故障时&#xff0c;整个系统都会收到影响&#xff0c;而右图即使有防火墙发生故障&#xff0c;但是还有一台防火墙做备份&#xff0c;相对于只有一台防火墙&#xff0c;要可靠些。 由于防火墙上不仅需要同步配置信息&…