译 | .NET Core 基础架构进化之路(二)


原文:Matt Mitchell

翻译:Edi Wang

(接上篇 译 | .NET Core 基础架构进化之路(一))

640?wx_fmt=gif

Maestro 及依赖流

.NET Core 3.0 基础结构难题的最后一部分就是我们所说的依赖项流。这不是 .NET Core 的唯一概念。除非它们是完全独立的,否则大多数软件项目都包含某种对其他软件的版本化引用。在 .NET Core 中,这些通常表示为 NuGet 包。当我们想要库提供的新功能或修补程序时,我们会通过更新项目中引用的版本号来提取这些新更新。当然,这些包也可能具有对其他包的版本化引用,这些其他包可能具有更多的引用,依此类推。这将创建一个图(graph)。当每个仓库都拉取其输入依赖项的新版本时,更改会流过此图。

一个复杂图

大多数软件项目的主要开发生命周期(开发人员经常处理的)通常涉及少量相互关联的仓库。输入依赖项通常稳定,更新是稀疏的。当他们确实需要更改时,它通常是手动操作。开发人员评估输入包的可用版本,选择适当的版本,并提交更新。.NET Core 中不是这样。组件需要独立,以不同的节奏提供,并且具有高效的内循环开发经验,这导致了大量具有大量相互依赖的存储库。相互依赖性还形成了一个相当深的图:

640?wx_fmt=png

dotnet/core-sdk 仓库充当所有子组件的聚合点。我们提供一个特定的 dotnet/core-sdk 编译版本,它描述了所有其他引用的组件。

我们还期望新的输出能快速通过此图,以便尽可能频繁地验证最终产品。例如,我们期望ASP.NET Core 或 .NET Core 运行时的最新版本尽可能经常在 SDK 中表示自己。这实质上意味着以常规的快速节奏更新每个仓库中的依赖项。在足够大的图(如 .NET Core)中,这很快成为手动执行的不可能完成的任务。这种大小的软件项目可能会通过多种方式来解决:

自动浮动输入版本

在此模型中,dotnet/core-sdk 可能引用 Microsoft.NETCore.App,这是 dotnet/core-setup 生成的,允许 NuGet 浮动到最新的预发行版本。虽然这行得通,但它也有重大的缺点。编译变得非确定性。签出较旧的 git SHA 和编译不一定使用相同的输入或生成相同的输出。重现错误变得困难。在 dotnet/core-setup 中,一个糟糕的提交可能会破坏任何在 PR 和 CI 检查之外拉取其输出的仓库。编译的编排成为一项主要任务,因为生成中的独立计算机可能会在不同的时间还原包,从而产生不同的输入。所有这些问题都是"可以解决的",但需要巨大的投资和不必要的基础设施复杂性。

"组合"编译

在此模型中,使用每个输入存储库中的最新 git SHA,以依赖项顺序同时生成整个图。生成每个阶段的输出将用于下一阶段。仓库有效地将其输入依赖项版本号覆盖其输入阶段。在成功编译结束时,将发布输出,并且所有仓库都更新其输入依赖项,以匹配刚刚编译的内容。与自动浮动版本号相比,这稍有改进,因为单个存储库版本不会因其他存储库中的不良签入而被爆,但它仍然有主要缺点。突发更改几乎不可能在仓库之间有效地流动,并且重现失败仍然是有问题的,因为存储库中的源通常与实际构建的内容不匹配(因为输入版本被覆盖在源代码管理)。

自动依赖项流

在此模型中,外部基础结构用于在存储库之间以确定性、验证方式自动更新依赖项。存储库在源中显式声明其输入依赖项和相关版本,并"订阅"来自其他仓库的更新。新的编译完成时,系统将查找匹配的订阅,更新任何声明的输入依赖项,并打开具有更改的 PR。此方法提高了可重复性、对重大更改进行流式操作的能力,并允许存储库所有者控制更新的完成方式。缺点是,它比其他两种方法中的任何一个都慢得多。更改只能以沿流路径每个存储库中的 PR 和官方 CI 时间总和的速度从栈底部流向顶部。

.NET Core 已尝试所有 3 种方法。我们在 1.x 的早期用了浮动版本,在 2.0 中进行了某种程度的自动依赖项流,并用在了 2.1 和 2.2 的组成版本。有了3.0,我们决定在自动化依赖项流上投入大量资金,并放弃其他方法。我们希望通过一些重要的方式改进以前的 2.0 基础架构:

简化产品实际内容的可追溯性

在任何给定的仓库中,通常可以确定哪些组件的版本用作输入,但几乎总是很难确定这些组件的构建位置、这些组件来自哪些 git SHA、它们之间的输入依赖关系等等。

减少所需的人工操作

大多数依赖项更新都是普通的。在更新 PR 通过验证以加快流程时自动合并它们。

使依赖项流信息与仓库状态分开

仓库应仅包含有关其节点在依赖关系图中的当前状态的信息。它们不应包含有关转换的信息,例如何时应进行更新、从中提取哪些来源等。

基于"意图"而不是分支的流依赖项

因为 .NET Core 由相当多的半自治团队组成,具有不同的分支理念、不同的组件发货节奏等,因此不使用分支作为意图的代理。团队应该根据这些输入的用途(而不是它们来自何处)定义他们拉入存储库的新依赖项。此外,这些投入的目的应由这些投入的小组宣布。

"意图"应从编译时推迟

为了提高灵活性,请避免在生成完成之前分配生成的意图,从而允许声明多个意图。在生成时,输出只是一个在一些 git SHA 上构建的位桶。就像在 Azure DevOps 生成的输出上运行发布管道一样,它实质上为输出分配了目的,在依赖项流系统中分配生成意图开始基于意图的流动依赖项过程。

考虑到这些目标,我们创建了一个名为 Maestro++ 的服务和一种称为"darc"的工具来处理我们的依赖项流。Maestro++ 处理数据以及依赖项的自动移动,而 darc 为 Maestro++ 提供了人机界面以及了解整个产品依赖状态的窗口。依赖项流基于 4 个主要概念:依赖项信息、编译、通道和订阅。

编译、通道和订阅

依赖项信息

在每个仓库中,都有仓库的输入依赖项的声明,以及eng/Version.Details中有关这些输入依赖项的源信息。读取此文件,然后传递每个输入依赖项的仓库+sha 组合生成产品依赖关系图。

编译

编译只是 Azure DevOps 内部构建中的 Maestro+ 视图。生成标识仓库+sha、总版本号以及从编译生成的完整资源集及其位置(例如 NuGet 包、zip 文件、安装程序等)。

通道

通道表示意图。将通道视为跨仓库分支可能很有用。可以将生成分配给一个或多个通道,以将意图分配给输出。通道可以与一个或多个释放管道关联。将生成分配给通道将激活发布管道并导致发布发生。根据发布发布活动更新生成的资源位置。

订阅

订阅表示转换。它将放置在特定通道上的编译的输出映射到另一个仓库的分支上,并提供有关何时进行这些转换的其他信息。

这些概念的设计使仓库所有者不需要栈或其他团队进度的全局知识,以便参与依赖项流。他们基本上只需要知道三件事:

  • 它们所做的编译的意图(如果有),以便可以分配通道。

  • 它们的输入依赖项及其产生的仓库。

  • 他们希望从哪些渠道更新这些依赖项。

例如,假设我拥有 dotnet/core-setup 存储库。我知道我的主分支为日常 .NET Core 3.0 开发编译二进制文件。我想将新编译分配给预先声明的".NET Core 3.0 开发"通道。我也知道,我有几个 dotnet/coreclr 和 dotnet/corefx 包输入。我不需要知道他们是如何编译的,也不是从什么分支编译的。我需要知道的是,我希望每天从'.NET Core 3.0开发'通道的最新dotnet/coreclr 输入,以及来自'.NET Core 3.0开发'通道的最新dotnet/corefx 输入,每当它们出现时。

首先,我添加一个 eng/Version.Details 文件。然后,我使用"darc"工具确保主分支上仓库的每个新生成默认分配给".NET Core 3.0 开发"通道。接下来,我将订阅设置为从 .NET Core 3.0 开发中提取输入,用于网dotnet/corefx, dotnet/coreclr, dotnet/standard 等的编译。这些订阅具有节奏和自动合并策略(例如,每周或每个生成)。

激活每个订阅的触发器时,Maestro++ 会根据与新生成的输出相交声明的依赖项更新核心设置回购中的文件(eng/version.Details.xml、eng/version.props 和其他一些文件)。它将打开 PR,一旦满足配置的检查,将自动合并 PR。

640?wx_fmt=jpeg

这反过来在主分支上生成新的核心设置编译。完成后,将自动将编译分配给".NET Core 3.0 开发"通道。".NET Core 3.0 开发"通道具有关联的发布管道,用于将构建的输出伪影(例如包和符号文件)推送到一组目标位置。由于此通道适用于日常公共开发编译,因此包和符号将推送到不同的公共位置。发布管道完成后,将完成通道分配,并触发在此事件上激活的任何订阅。随着更多组件的添加,我们构建了一个完整流图,表示仓库之间的所有自动流。

640?wx_fmt=png

.NET Core 3 开发通道的流图,包括有助于 .NET Core 3 开发流的其他通道(例如 Arcade 的".NET 最新工具")。

一致性和不协调性

.NET Core 依赖关系图状态的可见性增加,这突出说明了一个现有问题:当在图中的各个节点引用同一组件的多个版本时,会发生什么情况?.NET Core 依赖关系图中的每个节点可能会将依赖项流到多个其他节点。例如,由dotnet/core-setup 产生的 Microsoft.NETCore.App 依赖项流向 dotnet/toolset, dotnet/core-sdk, aspnet/extensions 和许多其他位置。由于拉取请求验证时间的变化、需要对重大更改做出反应以及所需的订阅更新频率,此依赖项的更新将在每个位置以不同的速率提交。当这些仓库流向其他位置并最终在 dotnet/core-sdk 下合并时,可能有许多不同的 Microsoft.NETCore.App 版本在整个图形中被反向引用。这称为"不协调"。当在整个依赖关系图中仅引用每个产品依赖项的单个版本时,该图是符合逻辑的。如果可能的话,我们总是努力提供一个连贯的产品。

不协调会导致哪些问题?

不协调表示可能的错误状态。例如,我们来看看 Microsoft.NETCore.App。此包表示特定的 API 层面。虽然可以在仓库依赖关系图中引用多个版本的 Microsoft.NETCore.App,但 SDK 只附带一个版本。此运行时必须满足可能在此运行时上执行的传递引用组件(例如 WinForms 和 WPF)的所有要求。如果运行时不能满足这些要求(例如,爆破式 API 更改),则可能会发生故障。在不连贯的图中,由于所有存储库均未引入同一版本的 Microsoft.NETCore.App,因此有可能错过重大更改。

这是否意味着不协调总是错误状态?

不。例如,假设图中的 Microsoft.NETCore.App 的不协调性仅表示 coreclr 中的单个更改,即单个不会爆的 JIT Bug 修复。从技术上讲,在图表中的每个点都不需要引入新的 Microsoft.NETCore.App。简单地将相同的组件与新的运行时进行发布就足够了。

如果不协调只是偶尔重要,为什么我们努力提供一个连贯的产品?

因为确定何时不协调并不重要是很难的。简单地将一致性作为所需状态的运来比尝试理解不相干组件之间对已完成产品的任何语义影响差异更容易。它可以完成,但在构建的基础上,它是耗时密集型的,容易出错。将一致性强制为默认状态更安全。

依赖流的干货

所有这些自动化和跟踪都有大量的优势,随着仓库图的增大,这些优势变得显而易见。它为解决我们每天的实际问题开辟了许多可能性。虽然我们刚刚开始探索这一领域,但系统可以开始回答有趣的问题并处理以下情况:

  • dotnet/core-sdk 的 git SHA A 和 SHA B 之间发生了哪些"真正的"变化? 通过 Version.Details.xml 文件来构建完整的依赖关系图,我可以识别图中发生的非依赖项更改。

  • 修复需要多长时间才能在产品中出现? 通过组合存储库流图和每个存储库遥测数据,我们可以估计在图中将修复程序从存储库 A 移动到存储库 B 需要多长时间。这在发布后期特别有价值,因为它有助于我们在查看是否进行特定更改时做出更准确的成本/收益估计。例如:我们是否有足够的时间来进行此修复并完成方案测试?

  • core-sdk 及其所有输入编译生成的所有文件的位置是什么? 

  • 在服务版本中,我们希望采取特定的修复,但暂缓其他。通道可以放置在允许特定修复程序自动流经图的模式下,但其他修复程序被阻止或需要批准。

640?wx_fmt=gif

下一步是什么?

随着 .NET Core 3.0 逐渐落地,我们正在寻找需要改进的新领域。虽然规划仍处于(非常)早期阶段,但我们预计在一些关键领域进行投资:

  • 缩短将修复程序转换为可发布、连贯产品的时间 – 依赖关系图中的跃点数量非常重要。这允许存储库在其进程中具有很大的自治性,但会增加我们的端到端"构建"时间,因为每个跃点都需要提交和正式编译。我们希望显著缩短端到端时间。

  • 改进我们的基础架构遥测 — 如果我们能够更好地跟踪失败的位置、资源使用情况、依赖状态的表现等,我们可以更好地确定我们的投资需要哪些地方才能提供更好的产品。在 .NET Core 3.0 中,我们朝这个方向迈出了一小步,但我们还有很长的路要走。

多年来,我们不断发展我们的基础设施。从 Jenkins 到 Azure DevOps,从手动依赖项流到 Maestro++,从许多工具实现到一个工具,我们对提供 .NET Core 3.0 所做的更改是向前迈出的一大步。我们准备开发并出一种比以往更加可靠的更令人兴奋的产品。

640?wx_fmt=jpeg

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

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

相关文章

在.Net Core中实现一个WebSocket路由

Net Core中使用WebSocket默认是没有路由系统的,只能通过Request.Path"/xxx"来判断请求,例如:1 2 3 4 5 6 7 8 91011121314151617181920app.Use(async (context, next) >{ if (context.Request.Path "/ws") { …

Dapper介绍--Micro-ORM

一.概述目前对于.net的数据访问ORM工具很多,EF和EF Core是一个重量级的框架。最近在搭建新的项目架构,来学习一下轻量级的数据访问ORM工具Dapper。Dapper支持SQL Server,MySQL,Sqlite,SqlCE,Fir…

剑指 Offer 31. 栈的压入、弹出序列

思路&#xff1a;模拟就完事 class Solution { public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {stack<int> c;int idx0;for(int v:pushed){c.push(v);while(c.size()&&c.top()popped[idx]){c.pop();idx;}…

Educational Codeforces Round 84 (Rated for Div. 2) D. Infinite Path 构建环 + 思维

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 懒得写了&#xff0c;直接贴图了。 思路&#xff1a; 遇事不决画成图&#xff0c;考虑将iii向p[i]p[i]p[i]连一个边&#xff0c;可以发现每个点入度为111&#xff0c;出度为111&#xff0c;所以画出来是若…

WSL+VSCODE体验UBUNTU环境下的开发

首先安装 WSL&#xff0c;我这里选择的是 ubuntu18.04 这个应用。切换 WSL 的默认用户为 root 用户切换成 root 用户主要是避免后续开发中遇到权限问题比较麻烦&#xff0c;直接默认 root 解决问题。找到ubuntu安装目录&#xff0c;一般在C:\Program Files\WindowsApps\Canonic…

程序员修仙之路--优雅快速的统计千万级别uv

菜菜&#xff0c;咱们网站现在有多少PV和UV了&#xff1f;Y总&#xff0c;咱们没有统计pv和uv的系统&#xff0c;预估大约有一千万uv吧写一个统计uv和pv的系统吧网上有现成的&#xff0c;直接接入一个不行吗&#xff1f;别人的不太放心&#xff0c;毕竟自己写的&#xff0c;自己…

P3391 【模板】文艺平衡树 fhq-treap 模板

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 这是学splaysplaysplay的时候的一个模板题&#xff0c;之前学过fhq−treapfhq-treapfhq−treap&#xff0c;但是没怎么用他做过题&#xff0c;今天一做还发现不少问题&#xff0c;真是眼高…

123. 买卖股票的最3佳时机 III

思路&#xff1a;动态规划&#xff0c; dp1是当前第一次买入的最大值 dp2是当前第一次卖出的最大值 dp3是当前第二次买入的最大值 dp4是当前第二次卖出的最大值 转移看代码&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int dp1-…

微软正式开源WSL 2的内核源码

微软在今年5月举办的 Build 2019 上宣布了第二代 Windows 的 Linux 子系统 —— WSL 2。与第一代相比&#xff0c;WSL 2 重新设计了架构&#xff0c;使用真正的 Linux 内核&#xff0c;支持在 Windows 上运行 ELF64 Linux 二进制文件。按照计划&#xff0c;WSL 2 的初始版本已于…

【NOI2016】优秀的拆分【后缀数组】【ST表】【关键点】【调和级数复杂度】【差分】

传送门 题意&#xff1a;如果一个字符串可以拆分为AABB的形式&#xff0c;其中A和B是任意非空字符串&#xff0c;则我们这种拆分是优秀的。求给定串的所有子串的拆分方案数之和。 N≤30000N \leq30000N≤30000 本来是个神仙题 但明明一个O(nlogn)O(nlogn)O(nlogn)的题为啥只…

剑指 Offer 43. 1~n 整数中 1 出现的次数(数位dp)

思路&#xff1a;就是数位dp&#xff0c;dp[idx][sum][limit]代表&#xff0c;到idx位&#xff0c;前面有sum个0&#xff0c;有没有limit限制&#xff1b; class Solution { public:int dp[20][50][2];int len; int pos[20];int countDigitOne(int n) {for(int i0;i<15;i)f…

Windows新终端中玩转ASCII和Emoji游戏的正确姿势

前一段时间&#xff0c;我搬运了几个Windows Terminal中玩游戏的视频.Windows Terminal - 动图GIF作背景图Windows Terminal - 母牛说HiWindows Terminal - 字符水族箱今天我来给大家展示一下具体的玩法~Emoji版双人碰碰球目前有个现成的 .NET core 项目可以直接用&#xff0c;…

剑指 Offer 38. 字符串的排列(有重复元素的排列)

思路&#xff1a;dfs 暴搜 class Solution { public:vector<string> permutation(string s) {vector<string> a;function<bool(char,int,int)> check[&](char x,int st,int idx){if(st>idx) return false;for(int ist;i<idx;i) if(s[i]x) return …

nowcoder Forsaken的数列 fhq-treap

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 很明显的数据结构了&#xff0c;splaysplaysplay当然能写&#xff0c;但是fhq−treapfhq-treapfhq−treap更加简洁易懂。 考虑第一个操作&#xff0c;无非就是分裂出[1,pos−1][1,pos-1][1…

我与微软的不解之缘 - 我的Insider Dev Tour 2019讲师之旅

作者&#xff1a;Lamond Lu大家好&#xff0c;我是陆楠&#xff0c;来自北京盛安德科技发展有限公司青岛分公司&#xff0c;今年非常有幸作为讲师参加了微软Insider Dev Tour烟台站的活动&#xff0c;我主讲了如何使用最新的微软开发工具开发调试NodeJS项目。与微软结缘与大多数…

.NET Core 3.0之深入源码理解Kestrel的集成与应用(一)

写在前面ASP.NET Core 的 Web 服务器默认采用Kestrel&#xff0c;这是一个基于libuv(一个跨平台的基于Node.js的异步I/O库)的跨平台、轻量级的Web服务器。在开始之前&#xff0c;先回顾一下.NET Core 3.0默认的main()方法模板中&#xff0c;我们会调用Host.CreateDefaultBuilde…

P2596 [ZJOI2006]书架 无旋treap 按照排名分裂

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 实现如下操作&#xff1a; 思路&#xff1a; fhq-treap板子辣&#xff0c;不要被他的编号误导了&#xff0c;我们还是需要按照排名来分裂&#xff0c;从上到下标号1−n1-n1−n即可&#xff0c;注意在按照…

【水】几个网络流图论模型的记录

DAG相关 最小路径覆盖 定义&#xff1a;最少不重路径覆盖DAG 初始时每个点是独立的 之后每次加一条边把两个点连到一起 因为只能用一次&#xff0c;所以是个最大匹配 最小路径覆盖N-拆点后最大匹配\text{最小路径覆盖N-拆点后最大匹配}最小路径覆盖N-拆点后最大匹配 最小链…

surging 微服务引擎 2.0 会有多少惊喜?

surging 微服务引擎从2017年6月至今已经有两年的时间&#xff0c;这两年时间有多家公司使用surging 服务引擎&#xff0c;并且有公司搭建了CI/CD&#xff0c;并且使用了k8s 集群&#xff0c;这里我可以说下几家公司的服务搭建情况&#xff0c;公司名不便透露&#xff0c;我们就…

Codeforces Round #630 (Div. 2) E. Height All the Same 排列组合

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 由于n,mn,mn,m都很大&#xff0c;不难猜到这是一个公式题。 首先化简题目中的两个操作&#xff0c;第二个操作就是可以让奇偶性相同的位置的高度相同。第一个操作虽然是改变相邻两个的奇偶…