Skip to main content

实体的生命周期

本文档高度概括了目录后端以及实体在目录中流动所涉及的技术流程。 它主要面向希望在安装或扩展目录时了解其内部结构的开发人员。 不过,它也可以为其他人员提供信息。

关键概念

目录形成了一个类似中心的地方,从各种权威来源获取实体并保存在数据库中,进行自动处理,然后通过应用程序接口(API)显示出来,供 Backstage 和其他人员快速、方便地访问。 最常见的来源是YAML 文件这些文件在目录中注册,并由各自的 Owner 维护。 目录会确保根据这些文件的变化及时更新。

开发人员可以自定义目录的主要扩展点有

  • 实体提供者--将原始实体数据输入目录;
  • 政策--制定关于实体形状的基准规则;
  • 处理程序--验证、分析和修改原始实体数据,使其成为最终形式。

所涉及的高级流程包括

  • 在这里,实体提供者从外部来源获取原始实体数据,并将其播入数据库;
  • 在这里,策略和处理器不断处理所摄取的数据,并可能同时发出其他原始实体(也要进行处理)、错误、与其他实体的关系等;
  • 在这里,各种处理器发出的所有数据被组合在一起,成为最终的输出实体。

一个实体在通过最后一个流程并进入最终实体之前,是不会被外界看到的(通过目录 API)。

General overview

下文将详细介绍这些过程。

摄取数据

每个目录部署都有一些实体提供者它们负责以自己认为合适的方式从外部权威来源获取数据,将这些数据转化为实体对象,并在添加或删除这些实体时通知数据库。 它们是未处理的实体如果没有实体提供者,就不会有实体进入系统。

数据库会始终跟踪属于每个提供商的实体集;没有两个提供商可以尝试输出相同的实体。 当一个提供商发出删除实体的信号时,就会导致一个急于删除清除:立即清除数据库中的实体及其导致的所有辅助数据。

Ingestion overview

默认安装了两个提供程序:一个用于处理用户注册的位置(例如 YAML 文件的 URL),另一个用于处理应用程序配置中的静态位置。 你可以在后端初始化代码中将更多第三方提供程序传递给目录创建程序,也可以轻松编写自己的提供程序。

实体提供程序是一个实现EntityProvider它有三个主要部分:

  • 身份:每个提供程序实例都有一个唯一、稳定的标识符,数据库可以用它来跟踪每个未处理实体的发起者。
  • 连接:在后端启动时,每个提供程序都会连接到目录运行时。
  • 事件流:在其生命周期内,提供程序可以在任何时间点向运行时发出更改事件,以修改其未处理实体集。

提供商完全可以选择如何以及何时产生这些变化事件。 例如,应用程序配置提供商只在启动时进行一次更新,然后就处于休眠状态。 位置数据库提供商在启动时进行一次初始更新,然后在每次检测到位置数据库发生变化时进行小规模的 delta 更新。 LDAP 提供商由一个定时器循环从外部驱动,偶尔会触发一次全面更新。 未来的某些提供商可能完全由事件驱动,通过事件总线或网络钩子提供信息。 提供商之间不存在神奇的协调;如果它们需要在彼此间安排同步或锁定(例如,为了避免在多个目录服务机器上重复工作),它们需要在带外进行处理。

所发射的实体会经过一些粗略的验证,以确保它们至少符合关于实体形状的最基本模式规则。 例如,它们需要有一个kind, ametadata.name和一个metadata.namespace除此之外,摄取阶段认为自己的工作已经完成,并将未处理的实体存储起来,以便处理系统在稍后时间进行处理。 这意味着,您为实体设置的更精确的验证规则是不是现阶段尚未应用。

处理

每个未处理的实体都带有一个时间戳,它告诉处理循环下次尝试处理它的时间。 当实体首次出现时,这个时间戳被设置为 "现在"--要求尽快处理它。

每个目录部署都有一些处理器它们负责接收目录认为需要处理的未处理实体,然后通过一系列处理阶段运行这些数据,对实体进行变异,并输出有关实体的辅助数据。 所有这些工作完成后,目录会获取所有信息,并将其作为已处理实体、错误和与其他实体的关系单独存储。 然后,目录会检查这些输出触及了哪些实体,并触发这些实体的最终组装(请参阅下文的 "缝合")。

Processing overview

实体总是一个接一个地处理,但所有目录服务主机都会协同处理,以分散负载。 请注意,每个处理器都可以为处理管道中的一个或多个固定步骤做出贡献。 首先,所有处理器为一个步骤做出的贡献都会按照处理器注册的顺序运行,然后,所有处理器为下一个步骤做出的贡献都会按照相同的顺序运行,依此类推。

每一步都有机会选择性地修改实体,并选择性地发出其他信息。 例如,处理器可能会查看spec如果处理器输出了一个实体,那么这个实体就会被逐字存储,并带有一个时间戳,说明它也应该尽快被处理。 如果输出了错误,那么就说明这个实体出了问题,它不应该取代我们之前在最终实体中的无错版本。 如果输出了关系,那么它们就会被放到一个专用的关系表中,由下面的拼接过程来处理。

可选的低级细节说明:当实体被发射时,目录会跟踪发射实体和被发射实体之间的 > 边。 这发生在幕后,从外部隐藏起来,用来形成 > 图。 这和关系不是一回事!这些边的目的是 > 能够检测到实体何时成为孤儿(见下文),并 > 能够在整个图中执行急切删除,当根被明确 > 取消注册,并且没有其他东西可以让低级节点存活时。 我们将在本文稍后部分详细讨论 > 孤儿和删除。

最后一步完成后,如果没有遇到错误,处理过的实体和所有关系都会被持久化到数据库 中。 然后,目录会将这个实体和与之有关系的所有实体视为拼接对象。

值得注意的是,处理过程不会导致删除或取消注册实体;它只能调用新实体或更新之前调用过的实体。 有关详情,请参阅下文。

缝合

缝合会最终确定实体,方法是收集前几个步骤的所有输出,并将它们合并到最终对象中,这就是目录 API 所能看到的内容。 随着最终实体本身的更新,缝合器也会确保搜索表得到相应的刷新。

注意:这里提到的搜索表与 Backstage 的核心搜索 > 功能无关,而是支持过滤 > 目录 API 查询结果功能的表。

Stitching overview

图中显示了缝合机如何从多个来源读取数据:

  • 处理步骤返回的已处理实体
  • 处理步骤产生的错误(如果有)
  • 处理步骤产生的所有关系,以及碰巧指向当前实体的 其他 实体处理步骤产生的任何关系

最后一部分值得注意:这就是缝合器如何收集所有关系边的方法,包括输入和输出关系边,无论这些关系边是谁生成的。

目前,拼接是一个固定的过程,不能修改或扩展。 这意味着,您想对最终结果进行的任何修改,都必须在摄取或处理过程中进行。

错误处理

实体摄取和处理过程中的错误可能以各种方式发生,而且发生的时间点可能远远晚于实体注册的时间点。 例如,注册的文件可能在远程系统中被删除,或者用户可能不小心更改了文件内容,导致无法成功解析等。

出现这些错误主要有两种方式。

首先,目录后端会生成详细的日志,其中应包含足够的信息,以便读者查找错误原因。 由于这些日志通常不容易被最终用户发现,因此这主要是Backstage操作员的有用工具,他们既可以调试由其控制的静态注册实体的问题,也可以帮助最终用户查找问题。

其次,对于大多数类别的错误,实体本身会包含一个描述问题的状态字段。 如果您放置了相应的错误呼出组件(error callout component),该字段的内容就会显示在Backstage实体页面的顶部。EntityProcessingErrorsPanel)那里。

我们仍在努力改进处理循环错误的浮现和可观察性。

孤儿化

如前所述,实体在内部形成了一个图,图边从处理过的父实体到处理父实体时发出的子实体。

处理循环会持续运行,因此这些边会随着时间的推移而被重新考虑。 如果处理父实体时不再发出给定的子实体,那么以前的边就会被切断。 如果该子实体也没有其他边指向它,那么它就会变成_蜕变_最终结果如下:

  • 拼接过程会在子实体上注入一个 "backstage.io/orphan: 'true'"注解。 子实体不会从目录中删除,但会一直存在,直到通过目录 API 显式删除为止,如果设置了 "orphanStrategy: delete "配置,则会隐式删除,或者直到被原始父实体或开始引用它的其他父实体 "回收 "为止。 子实体的Backstage目录页面会检测到新注解,并告知用户孤儿状态。

孤儿可能在几种不同的情况下出现。

  • If a catalog-info YAML file is moved from one place to another in the version control system without updating the registration in the catalog, it will effectively become orphaned "by" that registered location
  • If the user edits a corresponding parent catalog-info YAML file removing the entity's entry - for example in the case of a Location parent entity, orphaning can happen if editing or removing the target/targets lines pointing to the file containing the child entity.
  • Another common cause is large batch processors such as the ones that crawl through remote systems looking for entities, no longer finding something that it used to find before. Maybe the data was moved, or deleted, in the remote system. So for example when a person leaves the company an LDAP org discovery processor might leave an orphaned User entity behind. Note that this only applies to processors - ingestion that happens using entity providers work differently, described below.

需要注意的是,删除文件或意外损坏文件导致无法成功读取并不会导致孤儿化。 硬性错误,包括无法找到或读取不同的远程文件,都会在实体 > 上标记为硬性错误,以告知 Owners 出了问题。 但处理和其他 > 行为照常进行。

之所以存在 "孤儿 "机制,而不是触发急切删除,是为了安全起见。 由于系统的异步性和人类的易变性,类似的情况可能纯属偶然。 特别是当外部系统开始消费和依赖目录时,未经所有者明确同意而突然删除实体可能会造成严重后果。 因此,目录的立场是,通常由用户直接操作添加的实体也应仅由用户直接操作删除。

不过,如果想自动删除孤儿实体,可以通过以下应用程序配置选项启用自动清理功能。

catalog:
orphanStrategy: delete

隐式删除

实体提供者--而非处理者--须遵守渴望这里解释了这一概念。

回顾一下,所有实体提供者都管理着一个私有的实体 "桶",如外部集成它们可以对这些实体执行一些操作,包括添加、更新和删除。 实体的添加/更新会受到常规处理循环的影响,这意味着桶实体最终可能会形成整个实体图的根,而这些实体图是由这些处理器以递归方式处理桶内容及其后代时发出的。

当提供程序发布删除其数据桶中的实体时,该实体以及由它处理出来的整个实体树_注意是 "考虑"--如果且仅当它们在其他情况下会成为孤儿(没有其他父实体发射它们)时,它们才会被删除。 由于实体图并不是严格意义上的树形,多个根实际上可能最终间接引用了图中更下面的一个节点。 如果是这种情况,在所有这些根消失之前,该节点不会消失。

您使用 "创建 "按钮或添加到应用程序配置中注册的 yaml 文件的 URL 均由实体提供程序处理。 这意味着这种隐式删除机制会在某些日常情况下发挥作用。 让我们来举例说明。

想象一下,您有一个单核处理器,只有一个Location在根目录信息文件中的实体,而该实体指向软件仓库中的其他三个目录信息文件,并以Component每一个实体。

/
feature_one/
catalog-info.yaml <- kind: Component
feature_two/
catalog-info.yaml <- kind: Component
feature_three/
catalog-info.yaml <- kind: Component
catalog-info.yaml <- kind: Location

如果注册根Location实体,实际效果是五首先,一个名为generated--这就是提供商放在其 "桶 "中的 URL。 然后,随着处理循环的进行,Location你所指向的实体作为该实体的子实体出现,然后三个Component实体作为Location.

作为 Backstage 界面的最终用户,您现在可能想删除三个Component您可以访问实体视图右上方的三点菜单来实现这一操作。 出现的弹出对话框会通知您,该实体实际上属于某个根,您可能想删除该根(相当于取消注册最初注册的 URL)。 如果您选择这样做、全部_在同一操作中,上述五个实体中的任何一个都将被删除。

如果您不想进行这种强力修剪,您可能会选择移除其中一个target你的Location目录信息文件,然后删除含有Component现在,目录中会留下一个无主组件,你可以使用显式删除(见下文)来删除该组件。

明确删除

目录及其 REST API 还允许直接删除单个实体。 对于孤儿实体(没有任何父实体主动更新的实体)来说,这样做是有意义的。 实体视图三点菜单选项下的弹出界面确实提供了这一选项,在实体概述页面顶部的信息框中可以看到孤儿状态。

但是,如果你试图对一个正在被父实体主动更新的实体进行显式删除,那么当处理循环重新考虑仍在其中的父实体时,它很快就会再次出现。