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

迁移实体和根字段

将实体字段从一个子图传输到另一个子图


作为你的增长时,你可能想要将一个 的一部分移动到另一个子图。例如,假设您的 Payments 子图定义了一个 Bill

Payments子图
type Bill @key(fields: "id") {
id: ID!
amount: Int!
payment: Payment
}
type Payment {
# ...
}

随着你的 的发展,你决定为你的 supergraph 添加一个 计费 子图。合理地将计费功能及其账单金额移动到那里。你希望 看起来如下:

Payments子图
type Bill @key(fields: "id") {
id: ID!
payment: Payment
}
type Payment {
# ...
}
计费子图
type Bill @key(fields: "id") {
id: ID!
amount: Int!
}

本指南展示了如何使用 @override 指令将一个 amount 字段@override 指令 指令从一个子图迁移到另一个子图。

使用 @override 迁移

💡 提示

Apollo 建议 的组织逐步使用递进的 @override 迁移。请参阅 递增迁移与递进 @override 部分

按照以下步骤一次性将一个字段从一个子图迁移到另一个子图。这些步骤使用了页面顶部描述的示例付款和计费子图中的 amount 字段,但你也可以使用任何实体字段。

  1. 如果 @override 指令尚未导入,请将其包含在你的模式 @link 导入中:

    计费子图
    extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.7",
    import: ["@key", "@shareable", "@override"])
  2. 部署新的计费子图版本,该版本定义并解析你想要移动的字段。在这种情况下,该模式向 Bill 实体 添加了一个新的 amount 字段。

计费子图
type Bill @key(fields: "id") {
id: ID!
+ amount: Int! @override(from: "Payments")
}
  • 应用 @override 指令告知路由器解析计费子图中的 amount 字段,而不是付款子图中的字段。
  1. 使用 rover subgraph publish 将计费子图更新后的模式发布到 GraphOS。

    当路由器接收到其更新的时,它立即开始解析 Billing 子图中Bill.amount字段,同时继续解析 Payments 子图中的Bill.payment

    注意

    您可以通过单个更改迁移多个实体字段。要这样操作,将@override应用于您想要移动的每个实体字段。您甚至可以通过这种方式迁移整个实体。

  2. 现在由于Bill.amount已解析在 Billing 子图中,您可以安全地删除该及其字段从 Payments 子图中:

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    - amount: Int!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int! @override(from: "Payments")
    }

    在此更改后,重新部署 Payments 子图并发布其更新后的规范。

    注意

    由于router已经预先忽略 Payments 子图中的Bill.amount(得益于@override),您可以安全地按任何顺序发布更新后的规范或部署子图。

  3. 从 Billing 子图中移除@override指令,因为其不再有任何效果:

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    - amount: Int! @override(from: "Payments")
    + amount: Int!
    }

随着您部署 Billing 子图并发布此最终规范更改,您已成功实现了Bill.amount到 Billing 子图的迁移,且无中断服务。

渐进式迁移与逐步 @override
自从2.7

渐进式@override是 GraphOS 路由器的企业特性之一,并且需要具有GraphOS 企业计划的组织。如果您的组织没有企业计划,您可以通过注册免费的企业试用来试用它。

按照以下步骤逐步将一个字段从其中一个子图迁移到另一个子图。这些步骤使用页面顶部描述的 Payments 和 Billing 子图中的示例金额字段,但您可以将这些步骤应用于任何实体字段。

  1. 如果 @override 指令尚未导入,请将其包含在你的模式 @link 导入中:

    计费子图
    extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.7",
    import: ["@key", "@shareable", "@override"])
  2. 部署 Billing 子图的新版本,该版本定义并解析要迁移的字段。在这种情况下,该方案为Bill实体添加了一个新的amount字段。

计费子图
type Bill @key(fields: "id") {
id: ID!
+ amount: Int! @override(from: "Payments", label: "percent(1)")
}
  • 使用 @override 指令告诉路由器在计费子图而不是付款子图中解析 amount 字段。

  • label 参数添加到 @override 指令中可以设置要直接分配到计费子图的流量百分比。从小百分比开始。设置 label: "percent(1)" 意味着计费子图将解析 amount 的查询的 1%,而其余的 99% 将由付款子图解析。

  1. 使用 rover subgraph publish 将计费子图的更新架构发布到 GraphOS。

    当路由器接收其更新的超级图架构时,它开始大约 1% 的时间从计费子图解析 Bill.amount 字段,而其余 99% 仍然从付款子图解析。

    注意

    您可以通过单个更改迁移多个实体字段。要这样操作,将@override应用于您想要移动的每个实体字段。您甚至可以通过这种方式迁移整个实体。

  2. 逐步迭代地增加分配给计费子图的流量百分比,更新您的路由器的超级图架构,并验证计费子图的性能。继续进行,直到迁移完成后以 label: "percent(100)" 关键字,并且所有流量都由计费子图解析。

    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int! @override(from: "Payments", label: "percent(100)")
    }
  3. 现在,由于 Bill.amount 的解析已移至计费子图,您可以安全地从付款子图中删除该字段及其解析器:

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    - amount: Int!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int! @override(from: "Payments")
    }

    在此更改后,重新部署 Payments 子图并发布其更新后的规范。

    注意

    由于router已经预先忽略 Payments 子图中的Bill.amount(得益于@override),您可以安全地按任何顺序发布更新后的规范或部署子图。

  4. 从 Billing 子图中移除@override指令,因为其不再有任何效果:

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    - amount: Int! @override(from: "Payments")
    + amount: Int!
    }

随着您部署 Billing 子图并发布此最终规范更改,您已成功实现了Bill.amount到 Billing 子图的迁移,且无中断服务。

安全使用渐进式 @override

使用渐进式 @override 时,单个 可能会导致多个 。路由器会缓存查询计划,其中唯一的、被覆盖的标签组成为缓存密钥。

在渐进式 @override 之前,为给定的操作生成了一个查询计划。使用渐进式 @override,操作 "路径" 中的每个唯一标签都将使查询计划数量加倍。

缓解此问题的一些策略

  • 不要无限期地保留渐进式 @override。尽快将字段和从 @override 指令中移除 label 参数迁移。
  • 在迁移在一起的字段间共享标签。例如,如果您正在一起迁移 Bill.amountBill.payment,为这两个字段使用相同的标签。这将确保迁移不会导致查询计划数量增加。
  • 使用小而已知的标签集合(例如 percent(5)percent(25)percent(50))。

使用功能标志服务自定义渐变@override行为

直接使用时,该router支持根据给定百分比解析标签的percent(x)语法。不幸的是,更新此数字需要发布一个subgraph并重新部署router。为了避免这种情况,您可以使用功能标志服务动态更新标签值。

router为协处理器和Rhai脚本提供了一个接口,用于解析任意标签。这允许您在上传无需发布subgraph的情况下调整或禁用标签的上线状态。实现此功能的协处理器或Rhai脚本应采取以下步骤:

  1. 实现SupergraphService
  2. 检查apollo_override::unresolved_labels上下文键以确定哪些标签在模式中尚未由router解析。
  3. 使用您的功能标志服务(或其他机制)解析标签。
  4. 将解析后的标签添加到apollo_override::labels_to_override上下文键。

注意

未解析的标签是该模式中尚未由router解析的标签。它们可能并非都与传入的operation相关。作为最后一步,该router将过滤解析的标签。它将仅保留与该操作相关的标签。这样,它最小化了查询计划缓存键中标签的集合。协处理器或Rhai脚本应解决模式中的所有标签,而不仅仅是与操作相关的标签。

有关使用Darkly解决标签的协处理器的示例实现,请参阅,请参阅router存储库中的示例

使用手动组合优化频繁部署

⚠️ 警告

该方法需要在subgraphrouter更新之间进行仔细协调。如果没有严格控制部署和模式更新的顺序,可能会导致中断。对于大多数用例,Apollo建议使用上面的@override方法。

使用@override迁移entity字段field允许我们以零停机时间增量迁移字段。然而,这样做需要三个单独的模式发布。如果您使用手动组合,则每项模式更改都需要重新部署router。在仔细协调的情况下,您可以使用单个router重新部署执行相同的迁移。

  1. 在计费 子图 中,定义 Bill 实体及其对应的 。这些新的解析器应与被替代的支付 子图 解析器表现相同。

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int!
    }
  2. 将更新后的计费 子图 部署到您的环境中,但还不需要发布更新后的模式。

    • 此时,计费 子图 可以成功解析 Bill 对象,但因为其 超图模式 尚未更新,所以路由器尚不知情。发布模式将导致 错误。
  3. 在支付 子图 中,从 Bill 实体及其相关的 解析器 中删除迁移的字段(但尚未部署此更改):

    Payments子图
    type Bill @key(fields: "id") {
    id: ID!
    payment: Payment
    }
    type Payment {
    # ...
    }
    计费子图
    type Bill @key(fields: "id") {
    id: ID!
    amount: Int!
    }
  4. 使用 rover supergraph compose 以您常用的配置组成更新的 超图模式

    • 该更新后的 超图模式 表明计费 子图 可解析 Bill.amount,而支付 子图则不解析。
  5. 假设 CI 成功完成,使用新超图模式部署您的 router 的更新版本。

    • 当此部署完成后, router 将开始在计费 子图中解析 Bill 字段,而不是支付子图。

    • 当您的新 router 实例正在部署时,您可能会遇到两种不同的 Bill.amount 字段解析方式(旧实例仍从支付中解析它)。两个 子图 必须以完全相同的方式解析该字段,否则在过渡期间您的客户端可能会看到不一致的数据。

  6. 部署不带迁移字段的更新后的支付 子图

    • 此时可以安全地删除此定义,因为您的 router 实例正在专用计费 子图中使用。

就这样!迁移的字段已移至新的 子图,只有一个 router 重部署。

上一页
实体接口
下一页
共享类型(值类型)
评分文章评分在GitHub上编辑编辑论坛Discord

©2024Apollo Graph Inc.(简称Apollo GraphQL)。

隐私政策

公司