加入我们,从10月8日至10日在纽约市,学习最新的GraphQL联邦和API平台工程技巧、趋势和新闻。加入我们,参加2024年纽约市的GraphQL峰会
文档
免费开始

部署最佳实践

使用托管联邦部署的最佳实践和工作流程


当在子图上推出变更时子图,我们建议以下工作流程:

  1. 通过在您的CI管道中运行运行 rover subgraph check来验证每个变更的向后兼容性。
  2. 合并成功通过的向后兼容性变更
  3. 将变更部署到您的
  4. 等待所有副本完成部署。
  5. 运行 rover subgraph publish以更新您的 配置:
rover subgraph publish my-supergraph@my-variant \
--schema ./accounts/schema.graphql \
--name accounts \
--routing-url https://my-running-subgraph.com/api

安全推送配置更新

尽可能的,你应该以向后兼容的方式更新你的子图配置,以避免中断服务。如上所述,最佳做法是在更新之前运行rover subgraph check。你还应该尽量减少你对 schemas 进行的破坏性变更

此外,只有在该子图的所有副本都已部署之后,才调用rover subgraph publish发布子图。这确保了所有的都可以执行针对你的图的所有操作,并且操作不能尝试访问尚不存在的

在极少数配置变更与你的不向后兼容的情况下,你应该在部署你的更新代码之前更新你注册的

你还应该在(并单独于)其他更改之前执行会影响的配置更新。这有助于避免查询规划器生成在下游服务失败验证或违反你的解析器的查询的场景。

这包括以下示例

  • 修改@key@requires@provides指令
  • 从接口中移除类型实现

一般情况下,在推送影响您router's 查询计划器的配置更改时,始终要谨慎行事,并考虑这些更改将如何影响您的其他

示例场景

假设我们在一个子图中定义了一个Channel接口,并在另外两个子图中定义了实现Channel的类型:

# channel subgraph
interface Channel @key(fields: "id") {
id: ID!
}
# web subgraph
type WebChannel implements Channel @key(fields: "id") {
id: ID!
webHook: String!
}
# email subgraph
type EmailChannel implements Channel @key(fields: "id") {
id: ID!
emailAddress: String!
}

要安全地从您的中移除EmailChannel类型:

  1. 执行rover subgraph publish操作,以从email子图中移除EmailChannel类型。
  2. 部署一个新版本子图,该版本移除了EmailChannel类型。

第一步会导致query planner停止发送,例如...on EmailChannel,如果将其发送到不了解该类型的子图,则会导致验证失败。

如果您想保留EmailType但将其从Channel接口中移除,则操作类似。不需要完全删除EmailChannel类型,而只需从类型定义中移除implements Channel附加部分即可。这是因为query planner将查询扩展到接口或联合体,然后扩展到实现它们的类型上的片段。

例如,以下将...

query FindChannel($id: ID!) {
channel(id: $id) {
id
}
}

...生成两个查询,分别针对每个子图,如下所示:

# Generated by the query planner
# To email subgraph
query {
_entities(...) {
...on EmailChannel {
id
}
}
}
# To web subgraph
query {
_entities(...) {
...on WebChannel {
id
}
}
}

当前情况下,router将所有接口扩展到实现类型。

移除子图

要“注销”Apollo中的子图,请调用rover subgraph delete

⚠️ 注意

此操作无法撤销!

rover subgraph delete my-supergraph@my-variant --name accounts

The next time it starts up or polls, your router obtains an updated configuration that reflects the removed subgraph.

高级部署工作流程

使用 托管联邦,您可以控制您的 router 集群使用哪个版本的架构。在大多数情况下,将所有 router 实例升级到新架构版本是安全的,前提是您已使用 架构检查 确认您的更改具有向后兼容性。然而,您的部署模型可能需要高级工作流程来部署某个特定版本的架构。

两种类型的高级部署工作流程

  • 蓝绿部署工作流程。对于需要渐进式推出的部署,如蓝绿部署,您可以在部署时将每个环境的主图架构固定到您的 图变体。在不同生产环境之间使用单个 变体,允许 获取所有环境的集合生产流量报告,并在知识库中提供架构的连贯变更日志。

  • 图变体工作流程。在 router 层的更改可能涉及各种不同的更新,例如 将实体迁移到另一个子图。如果您的基础设施需要更高级的部署过程来处理不同的 router 更新,您可以使用 图变体 来管理不同配置的 router 集群。

    图变体的常见用途是 合同,例如,为超级图架构的公共和私有 API 创建不同的合同变体。

示例蓝绿部署

此功能正在开发中 预览.您的疑问和反馈非常受重视不要犹豫与您的Apollo联系人取得联系.

蓝色-绿色部署策略使用两个环境:一个环境(蓝色)为实时流量服务模式变体,另一个环境(绿色)使用开发中的新发布变体。当新版本准备就绪时,流量将从蓝色环境迁移到绿色环境。每个新版本都会重复此周期。

以下是以新发布环境(绿色)的超级图模式为例部署的步骤;示例使用GraphOS平台API来执行自定义操作:

  1. 使用平台API一次性发布所有发布子图publishSubgraphs 模式

    ## Publish multiple subgraphs together in a batch
    ## and retrieve the associated launch, along with any downstream launches synchronously.
    mutation PublishSubgraphsMutation(
    $graphId: ID!
    $graphVariant: String!
    $revision: String!
    $subgraphInputs: [PublishSubgraphsSubgraphInput!]!
    ) {
    graph(id: $graphId) {
    publishSubgraphs(
    graphVariant: $graphVariant
    revision: $revision
    subgraphInputs: $subgraphInputs
    downstreamLaunchInitiation: "SYNC"
    ) {
    launch {
    id
    downstreamLaunches {
    id
    graphVariant
    status
    }
    }
    }
    }
    }

    这启动了发布,以及为合同所需的任何后续发布。它返回发布 ID,以及配置为与模式同步(downstreamLaunchInitiation: "SYNC")返回的下游发布 ID。

    注意

    对于合同,您还可以请求返回与每个发布相关的任何可能变体,例如downstreamLaunches { graphVariant }。查询特定发布时,请务必在以下步骤中传递与发布关联的变体。

  2. 轮询完成的发布和任何后续发布

    ## Poll for the status of any individual launch by ID
    query PollLaunchStatusQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) {
    graph(id: $graphId) {
    variant(name: $graphVariant) {
    launch(id: $launchId) {
    status
    }
    }
    }
    }

    注意

    在轮询一个合同时,此$graphVariant 的查询必须引用合同变体而非基础变体。您可以从第1步中的查询中获取它,从Launch.graphVariant / downstreamLaunches { graphVariant }.

  3. 启动和下游启动完成之后,检索启动的超级图模式。

    ## Fetch the supergraph SDL by launch ID.
    query FetchSupergraphSDLQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) {
    graph(id: $graphId) {
    variant(name: $graphVariant) {
    launch(id: $launchId) {
    build {
    result {
    ... on BuildSuccess {
    coreSchema {
    coreDocument
    }
    }
    }
    }
    }
    }
    }
    }

    注意

    在检索一个合同时,此$graphVariant 参数的查询必须引用一个合同变体。您可以从第1步中的查询中获取它,从Launch.graphVariant / downstreamLaunches { graphVariant }.

  4. 使用-s--supergraph 选项来指定超级图模式。

    • 指定-s--supergraph 选项将禁用从Uplink轮询模式。

    • docker run 命令中使用此选项的示例,请参见指定超级图.

  5. 如果您需要回滚到之前的蓝绿部署,请确保之前的部署可用,并将流量切换回之前的部署。

    • 路由器镜像必须使用通过--supergraph 标志内嵌的超级图模式。

    • 部署应包括路由器和子图,以确保解析器和模式兼容。

    • 如果之前的部署无法重新部署,请用要回滚到的launchID 重复步骤3和4。确保部署的子图与超级图模式兼容,然后使用针对目标launchID 新获取的超级图模式重新部署路由器。在考虑仅回滚超级图模式之前,请参阅其注意事项

示例金丝雀部署

金丝雀部署在独立于实时生产环境的环境中应用图更新,并从小部分生产流量开始验证其更新。在金丝雀部署中验证更新后,更多生产流量逐步路由到它,直到它处理所有流量。

要配置您的金丝雀部署,您可以获取金丝雀部署的的超级图模式,然后让该金丝雀部署向prod 变体报告指标。类似于蓝绿部署示例,您的金丝雀部署固定到与您的其他实时部署相同的图变体,因此两个部署的指标都报告给相同的图变体。随着您的金丝雀部署的扩容,它最终将成为稳定部署,为所有生产流量提供服务,因此我们希望该部署向实时prod 变体报告。

为配置生产图变种的金丝雀部署:prod 变种:

  1. 使用平台API一次性发布所有金丝雀部署的子图publishSubgraphs 修改.

    ## Publish multiple subgraphs together in a batch
    ## and retrieve the associated launch, along with any downstream launches synchronously.
    mutation PublishSubgraphsMutation(
    $graphId: ID!
    $graphVariant: String!
    $revision: String!
    $subgraphInputs: [PublishSubgraphsSubgraphInput!]!
    ) {
    graph(id: $graphId) {
    publishSubgraphs(
    graphVariant: "prod" ## name of production variant
    revision: $revision
    subgraphInputs: $subgraphInputs
    downstreamLaunchInitiation: "SYNC"
    ) {
    launch {
    id
    downstreamLaunches {
    id
    graphVariant
    status
    }
    }
    }
    }
    }

    这会启动一个发布,以及任何下游必需的发布。它返回发布ID,下游发布的ID配置为与修改同步(downstreamLaunchInitiation: "SYNC")。

    注意

    对于合同,您还可以请求任何下游发布返回与每个发布关联的变种,例如,downstreamLaunches { graphVariant }。当查询特定发布时,请确保在以下步骤中传递与发布相关的变种。

  2. 轮询完成的发布和任何后续发布

    ## Poll for the status of any individual launch by ID
    query PollLaunchStatusQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) {
    graph(id: $graphId) {
    variant(name: $graphVariant) {
    launch(id: $launchId) {
    status
    }
    }
    }
    }

    注意

    在轮询合同时,此查询的$graphVariant 参数必须引用合同变种而不是基础变种。您可以从步骤1中的查询中获取,从Launch.graphVariant / downstreamLaunches { graphVariant }

  3. 启动和下游启动完成之后,检索启动的超级图模式。

    ## Fetch the supergraph SDL by launch ID.
    query FetchSupergraphSDLQuery($graphId: ID!, $graphVariant: String!, $launchId: ID!) {
    graph(id: $graphId) {
    variant(name: $graphVariant) {
    launch(id: $launchId) {
    build {
    result {
    ... on BuildSuccess {
    coreSchema {
    coreDocument
    }
    }
    }
    }
    }
    }
    }
    }

    注意

    在检索一个合同时,此$graphVariant 参数的查询必须引用一个合同变体。您可以从第1步中的查询中获取它,从Launch.graphVariant / downstreamLaunches { graphVariant }.

  4. 使用-s--supergraph 选项来指定超级图模式。

    • 指定-s--supergraph 选项将禁用从Uplink轮询模式。

    • docker run 命令中使用此选项的示例,请参见指定超级图.

  5. 如果您需要回滚,请确保先前的部署可用,并将流量切换回实时部署。

    • 路由器镜像必须使用通过--supergraph 标志内嵌的超级图模式。

    • 部署应包括路由器和子图,以确保解析器和模式兼容。

    • 如果之前的部署无法重新部署,请用要回滚到的launchID 重复步骤3和4。确保部署的子图与超级图模式兼容,然后使用针对目标launchID 新获取的超级图模式重新部署路由器。在考虑仅回滚超级图模式之前,请参阅其注意事项

使用您的金丝雀部署将指标报告到GraphOS,您可以使用GraphOS Studio验证金丝雀的性能,然后再将更改推出到图的其余部分。

修改查询规划逻辑

类似于您对待数据库迁移的方式,将您的查询规划逻辑的迁移视为类似的处理。仔细考虑查询规划器更改对下游服务的影响,并规划适当的“双重读取”。

以下是Products 子图和Reviews 子图的示例:

# Products subgraph
type Product @key(fields: "upc") {
upc: ID!
nameLowerCase: String!
}
# Reviews subgraph
type Product @key(fields: "upc") {
upc: ID!
reviews: [Review]! @requires(fields: "nameLowercase")
nameLowercase: String! @external
}

假设我们想要弃用nameLowercase 字段并使用name 字段替换它,如下所示:

# Products subgraph
type Product @key(fields: "upc") {
upc: ID!
nameLowerCase: String! @deprecated
name: String!
}
# Reviews subgraph
type Product @key(fields: "upc") {
upc: ID!
nameLowercase: String! @external
name: String! @external
reviews: [Review]! @requires(fields: "name")
}

要在现有位置执行此迁移

  1. 修改Products 子图以添加新字段。(如常规做法,首先部署所有副本,然后使用 rover subgraph publish 推送新.)
  2. 部署一个 Reviews 子图的新版本,该子图包含一个接受源对象中的 nameLowercasename 的解析器。
  3. 修改在注册表中 Reviews's 子图的模式,使其 @requires(fields: "name")
  4. 部署一个 Reviews 子图的新版本,该子图包含一个只接受其源对象中的 name 的解析器。

或者,您可以通过修改子图的 URL 以原子迁移的方式在子图级别执行此

  1. 修改 Products 子图,添加 name 字段(如常规定义,首先部署所有副本,然后使用 rover subgraph publish 推送新的子图模式)。
  2. 向一个新 URL 部署一组 Reviews 副本,该副本从 name 读取。
  3. 将带有新 URL 和上述模式更改的 Reviews 子图注册。

使用这种原子策略,查询计划器解决所有旧 subgraph URL 上的未解决请求,该 URL 依赖于 nameLowercase 和旧的查询 -planning 配置,该配置 @requires 字段。所有新请求都通过使用新的查询 -planning 配置的新 subgraph URL 进行,该配置 @requires 字段。

可靠性和安全性

您的 router 通过轮询 Apollo Uplink 获取其配置,Apollo Uplink 是专门用于提供 配置的 Apollo 主机端点。如果您更新的配置因 Uplink 出错而不可访问,您的 router 还会继续提供其最近获取的配置。

如果您在 Uplink 出错期间重新启动一个 router 实例或启动一个新实例,该实例无法在 Apollo 解决故障之前获取其配置。

subgraph publish 生命周期

每当您为特定的 rover subgraph publish 子图调用 时,它不仅更新该子图已注册的模式,还更新 router 的管理的配置。

因为您的图是动态变化的,并且可能多个子图会同时更新,因此即使子图检查成功,也可能出现合成错误。为了这个原因,更新子图会在云中重新触发合成,确保在更新配置之前,所有子图仍然组合成一个完整的超图。后台工作流程可以总结如下:

  1. 子图模式被上传到Apollo并进行索引。
  2. 将子图更新到注册表以使用其新的模式。
  3. 所有子图在云中合成以生成新的超图模式。
  4. 如果合成失败,则命令退出并发出错误。
  5. 如果合成成功,Apollo Uplink将开始提供更新的超图模式。

方程式的另一边是路由器。路由器可以定期轮询Apollo Uplink以获取其配置的更改。动态配置更新的生命周期如下:

  1. 路由器轮询其配置的更新。
  2. 在更新时,路由器下载更新的配置,包括新的超图模式。
  3. 路由器使用新的超图模式更新其查询规划逻辑。
  4. 路由器继续使用旧配置解析正在进行的请求,同时使用更新的配置对所有新请求进行处理。

或者,除了从Apollo Uplink获取配置外,路由器在其部署时还可以指定超图模式的路径。这种静态配置在您希望路由器使用与Uplink中最新验证的模式不同的模式时非常有用,或者当您没有连接到Apollo Uplink时。

回滚部署

在回滚部署时,您必须确保超图模式和路由器版本与目标环境中部署的子图和子图模式兼容,以便所有可能的GraphQL操作都能够成功执行。

向前滚动以撤销

撤销操作通常通过向前滚动到新版本并撤销子图代码库中的更改来实现,然后按照变更管理技术文档中概述的全过程(发布子图模式和新代码的滚动推出)执行完整发布过程。

回滚整个部署

对于蓝色绿色部署场景,其中部署中的 路由器子图 具有带版本号的 Docker 容器镜像,您可以尝试回滚整个部署(假设没有底层数据库模式变更)。这样做可以保证嵌入到路由器镜像中的 超级图模式 与目标环境中底层的子图兼容。这类回滚通常发生在蓝色绿色部署如果 促销后分析 失败时

仅回滚超级图模式

在很少的情况下,如果只对兼容性变更(例如,设置渐变 @override 百分比)进行 backwards-compatible 更改,则可能只需通过使用 --supergraph 标志来固定 路由器 舰队 到特定 launchID 来仅回滚超级图模式。

这种方法仅适用于对有限 schema 变更的短期修复。它要求路由器锁定到特定的超级图 launchID,因为重新发布底层子图将导致生成新的超级图模式。

鉴于这种方法存在的问题,我们通常建议通过 回滚到新版本

回滚指南

回滚指南总结

  • 任何回滚都必须确保路由器的 超级图模式 与目标环境中部署的底层 子图 兼容。

  • GraphOS 的标准 CI/CD 模式交付管道 是寻求持续部署和赋予子图团队独立部署具有 GraphOS 检查安全性的环境的多数环境的最佳选择。有关详细信息,请参阅 变更管理技术笔记

  • 在具有现有蓝色绿色或金丝雀部署且依赖不可变基础设施方法的环境(其中无法在生产工作负载上进行就地更新、补丁或配置更改)中,路由器映像可以使用嵌入式超级图模式。超级图模式使用 --supergraph 标志为特定 GraphOS launchID 设置路由器,该 GraphOS launchID 由发布用于蓝色绿色或金丝雀部署的特定子图图像版本所用的子图模式生成。这样,蓝色绿色或金丝雀部署可以被整体保留不变,因此回滚到以前的部署将确保路由器的超级图模式与目标环境中部署的底层子图兼容。

  • 通常情况下,我们不建议仅单独回滚 router 上的 supergraph 模式 的兼容性也必须考虑。子模式后续发布的子图生成新的 supergraph 模式可能会丢失回滚更改,所以通常最好是修复子图存储库中真实来源的问题。

上一条
联邦模式检查
下一条
自愿错误报告
评分文章评分在 GitHub 上编辑编辑论坛Discord

©2024Apollo Graph Inc.,以 Apollo GraphQL 作为业务名称。

隐私政策

公司