Google Apigee:Proxy Revision、Flow Policy 与混合运行治理
一次订单 API 发布中,流水线成功导入了新的 proxy bundle,也拿到了 revision R2。管理接口随后返回部署成功,值班人员便把变更标成完成;真实请求却有时返回 R1 的响应标记,有时直接落到另一个 environment 中同 base path 的代理。团队看到的是三个被混在一起的状态:revision 存在、revision 部署到 environment、承载该 environment 的运行实例已经收敛并真正接到流量。
另一次故障更隐蔽:身份 Policy 抛错后,请求仍然到达了后端。原因不是 Policy 没有执行,而是 continueOnError=true 让错误留在正常 Flow 中,后续又没有显式检查 fault variable。Apigee 的资源关系与 Flow 都是可执行程序,不能靠控制台绿色图标、一次 200 或一张 Analytics 图表替代运行证据。
Revision 已部署,为什么请求仍然命中旧逻辑
Apigee Organization 是 API 管理资源的根,并与一个 Google Cloud project 对应。API proxy、environment、API product、developer、app 等对象都归属 Organization,但它们不是同一棵“目录树”里的文件夹。读写这些对象的是管理面;客户端请求不会为了每次路由都同步查询管理 API。
Environment 是 proxy revision 的部署与运行隔离边界。一个 revision 部署到 test,并不意味着它也在 prod;同一个 proxy 可以把不同 revision 部署到不同 environment。环境还承载 KVM、target server、keystore 等依赖的作用域,因此“重新部署旧 revision”只有在这些外部依赖仍然存在时才算可回滚。
Environment Group 把 hostname 绑定到一个或多个 environment。外部调用 URL 由 group hostname、ProxyEndpoint base path 和资源路径组成,environment 名与 group 名通常不直接出现在 URL 中。同组多个 environment 若出现相同 hostname/base path,部署对象可能都存在,流量却只会按实际路由规则到达其中一个;发布前要用 deployment change report 发现冲突。
托管 Apigee 的 Instance 是区域级运行单元。Environment 必须 attached 到至少一个 Instance,Instance 才会加载并服务该环境的部署。多区域运行意味着同一 Environment 关联多个区域 Instance,并为 northbound 入口设计相应的负载均衡与故障切换,不是简单地多建一个 Environment。
因此,上线证明至少包含四项:Environment Group 的 hostname 指向预期入口、Environment 与 Instance attachment 正确、目标 revision 在 Environment 中完成部署、真实请求返回目标 revision 标记并在后端留下关联记录。少一项,都只能说明控制链中的局部状态。
Proxy bundle 是发布源,不是组织备份
API proxy 以 apiproxy/ 为顶层目录。ProxyEndpoint 定义客户端入口与 base path,TargetEndpoint 定义后端连接,Policies 保存可附着的策略,资源目录保存 JavaScript、Java、XSL 等扩展文件。一个最小 bundle 可以这样组织:
apiproxy/
├── orders.xml
├── proxies/
│ └── default.xml
├── targets/
│ ├── blue.xml
│ └── green.xml
└── policies/
├── AM-Revision-Marker.xml
├── RF-Require-Lab-Key.xml
├── RF-Unknown-Path.xml
└── SA-Request-Id.xmlorders.xml 是 proxy 描述文件,ProxyEndpoint 和 TargetEndpoint 则决定真实请求链。Policy 文件只是定义;只有在 Endpoint 的 <Step> 中附着,并且所在 Flow 与 Step Condition 命中时,它才会执行。目录结构与可用元素应以 API proxy 配置参考 为准。
下面的 ProxyEndpoint 用条件 Flow 决定哪些 Policy 执行,再用同级 RouteRule 选择 blue 或 green 上游。两者不能混写:Flow 是策略执行位置,RouteRule 是请求 Flow 全部结束后的目标选择器。多个 RouteRule 自上而下匹配,因此带条件的 green 必须放在无条件 blue 前面;UnknownPath 则在路由发生前用 RaiseFault 拒绝不认识的路径。演示中的 endpoint、域名和身份都应替换为专用测试资源,不能指向生产消费者或客户后端。
<ProxyEndpoint name="default">
<PreFlow name="PreFlow">
<Request>
<Step><Name>SA-Request-Id</Name></Step>
</Request>
<Response>
<Step><Name>AM-Revision-Marker</Name></Step>
</Response>
</PreFlow>
<Flows>
<Flow name="BlueProbe">
<Condition>(proxy.pathsuffix MatchesPath "/blue") and (request.verb = "GET")</Condition>
<Request>
<Step><Name>RF-Require-Lab-Key</Name></Step>
</Request>
</Flow>
<Flow name="GreenProbe">
<Condition>(proxy.pathsuffix MatchesPath "/green") and (request.verb = "GET")</Condition>
<Request>
<Step><Name>RF-Require-Lab-Key</Name></Step>
</Request>
</Flow>
<Flow name="UnknownPath">
<Condition>not ((proxy.pathsuffix MatchesPath "/blue") or (proxy.pathsuffix MatchesPath "/green")) or (request.verb != "GET")</Condition>
<Request>
<Step><Name>RF-Unknown-Path</Name></Step>
</Request>
</Flow>
</Flows>
<HTTPProxyConnection>
<BasePath>/apigee40/orders</BasePath>
</HTTPProxyConnection>
<RouteRule name="green">
<Condition>proxy.pathsuffix MatchesPath "/green"</Condition>
<TargetEndpoint>green</TargetEndpoint>
</RouteRule>
<RouteRule name="blue"><TargetEndpoint>blue</TargetEndpoint></RouteRule>
</ProxyEndpoint>RF-Unknown-Path 应是返回 404 的 RaiseFault,RF-Require-Lab-Key 应是从专用 Header 读取合成 key 的 VerifyAPIKey;blue.xml 与 green.xml 的 <HTTPTargetConnection><URL> 分别指向两个合成 HTTPS 后端。AM-Revision-Marker 只在响应上写入不含组织、实例或内部地址的发布标记。导入前必须确认这些引用文件全部存在、XML 可解析且 ZIP 顶层只有 apiproxy/;缺一个文件时,预期证据应是导入失败,而不是让流水线跳过策略。
生产 bundle 不应把后端凭据、私钥、KVM value 或真实 hostname 固化进 Git。仓库保存 XML、无密配置、依赖资源名称和 bundle hash;Secret 通过 keystore、KVM、Secret Manager 或目标环境支持的安全引用注入。bundle 可移植,但 Environment attachment、API product、developer/app、credential、KVM value、证书、IAM、PSC、DNS、Analytics 历史都不在其中。
用专用测试组织跑通两个上游
Apigee 没有一个不依赖租户、网络与计费的本地单进程替代品。学习实验应使用专用 Google Cloud project 和 Apigee Organization,准备两个由团队控制、可区分响应的合成 HTTPS 后端,例如返回 upstream=blue 与 upstream=green。执行者需要 Google Cloud CLI、curl、zip、读取目标拓扑的权限,以及只覆盖导入、部署和查看测试 Environment 的最小 IAM。
在专用租户执行时,先固定当前主体和资源身份,并把原始输出保存在受控证据库;project number、service account、IP、hostname 和 token 在分享前都要脱敏。下文只给出执行后应看到的判据,不把未开通租户的命令写成已经成功运行。
set -euo pipefail
export PROJECT_ID='<lab-project-id>'
export ORG='<lab-apigee-org>'
export ENV='<lab-environment>'
export ENVGROUP='<lab-envgroup>'
export INSTANCE='<lab-instance>'
export API='orders-lab'
export HOSTNAME='api-lab.example.invalid'
gcloud version
gcloud config set project "$PROJECT_ID"
gcloud auth list --filter=status:ACTIVE
gcloud apigee organizations describe "$ORG" --format=json
gcloud apigee environments describe "$ENV" --organization="$ORG" --format=json然后用 REST API 把 group、Environment、Instance attachment 和 deployment 放到同一张关系表。Access token 只放在当前进程内,不能写入脚本、命令历史或日志归档;共享执行机还要防止其他进程读取环境变量,优先使用短时 impersonation、隔离 runner 和任务结束即销毁的凭据上下文。
export TOKEN="$(gcloud auth print-access-token)"
export APIGEE="https://apigee.googleapis.com/v1/organizations/$ORG"
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$APIGEE/envgroups/$ENVGROUP"
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$APIGEE/envgroups/$ENVGROUP/attachments"
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$APIGEE/instances/$INSTANCE/attachments"
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$APIGEE/environments/$ENV/deployments"正向结果不是“四个请求都返回 200”,而是 group attachment 与 instance attachment 都明确引用 $ENV,hostname 与预期入口一致,deployment 列表可以关联 proxy name 与 revision。404 先检查 Organization、资源名和 API 路径;403 先检查当前 principal 的 permission、project 选择与组织策略,不要用 Owner 角色掩盖最小权限缺口。完成关系查询后执行 unset TOKEN;后续每个管理阶段都重新获取短期 token,避免把长寿命 shell 会话变成隐形凭证缓存。下面导入命令执行前必须重新获取,任务结束立即撤销当前 shell 中的变量。
在 bundle 根目录打包时,ZIP 顶层必须是 apiproxy/:
zip -qr orders-lab.zip apiproxy
sha256sum orders-lab.zip
export TOKEN="$(gcloud auth print-access-token)"
curl -fsS -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: multipart/form-data" \
-F "file=@orders-lab.zip" \
"$APIGEE/apis?name=$API&action=import" \
| tee import-response.json
unset TOKEN导入响应应返回 proxy 名与新 revision。流水线必须从响应读取 revision,不能假设每次都是 1,也不能把文件名中的数字当 revision。导入只创建发布候选,不会让入口自动可调用。
VerifyAPIKey 不是“Header 中有字符串就通过”。运行时会沿 consumer key 找到 Developer App,再检查 key、App、Developer、API Product 的状态,以及 Product 是否包含目标 Environment、Proxy 和资源路径。因此部署测试 revision 后,还要在专用租户创建最小 API Product,将 $ENV、$API 和 /blue 资源纳入 Product;创建虚构 Developer 与 App,把 Product 关联到 App,并只在受控 Secret 存储中接收生成的 consumer key。/green 若不在 Product 资源中,即使使用同一个有效 key,也应被拒绝。
这条授权链至少做四次请求:有效 key 调 /blue 成功;同一 key 调未授权 /green 失败;不存在的 key 失败;撤销 App credential 后旧 key 持续失败。每次都同时检查 target 日志,证明拒绝发生在 Apigee 而不是后端。实验结束删除 Developer/App 前先撤销 credential,并确认 VerifyAPIKey 不再产生成功的 app、developer 与 product flow variable。API Product、Developer、App 和 credential 不在 proxy bundle 中,发布与回滚清单必须单独保存它们的标识、状态和依赖关系。
export REV='<revision-from-import-response>'
gcloud apigee apis describe "$API" \
--organization="$ORG" --verbose --format=json
gcloud apigee apis deploy "$REV" \
--api="$API" \
--environment="$ENV" \
--organization="$ORG"
gcloud apigee deployments describe \
--api="$API" \
--environment="$ENV" \
--organization="$ORG" \
--format=json部署状态收敛后才发真实请求。不要关闭 TLS 校验,也不要只打一次请求;从每条 northbound 路径发一组带合成 correlation ID 的请求,同时保存响应、入口日志与两个后端日志。
# APIGEE_LAB_KEY 由 Secret 系统注入,只关联专用测试 App。
for i in 1 2 3 4 5; do
curl --fail-with-body --show-error \
-H "x-apikey: $APIGEE_LAB_KEY" \
-H "X-Lab-Correlation: apigee40-r${REV}-${i}" \
"https://$HOSTNAME/apigee40/orders/green"
done若当前 Product 只授权 /blue,这组路由探测必须使用不依赖 Product 的专用合成身份,或临时把 /green 明确加入测试 Product;不能拿预期会被 Product 拒绝的请求证明 green 路由。正向判据是每次都命中 green,响应中的 revision marker 等于 $REV,后端日志存在同一个 correlation ID,并且 deployment 与 attachment 仍指向目标 Environment。错误凭据访问 /blue 应在 Apigee 层得到受控 4xx,blue 后端没有对应请求;未知路径应命中明确的拒绝路径,而不是悄悄落到 fallback target。
Revision 切换要观察最终一致窗口
Revision 是不可变发布候选,而不是公共 API Version。对 bundle 的任何修改都应导入为新 revision;消费者不会在 URL 中看到 revision 编号。把 R1 的响应 marker 改为 R2,重新导入后,先生成 deployment change report,核对 base path、Environment Group 冲突和将被替换的部署。
目标 Environment 已部署旧 revision 时,CLI 用 --override,REST API 用 override=true。这个动作会先部署新 revision,再撤下旧 revision,但运行面的 Message Processor 仍需要时间收敛。
gcloud apigee apis deploy "$REV2" \
--api="$API" \
--environment="$ENV" \
--organization="$ORG" \
--override
while true; do
gcloud apigee deployments describe \
--api="$API" --environment="$ENV" --organization="$ORG" \
--format='json(revision,state,instances)'
sleep 5
done示例中的 while true 便于人工观察,不能原样放进 CI。流水线应设置总超时,在每轮保存 deployment JSON,并按返回的 instance/runtime 状态判断目标 revision 是否已被所有报告单元加载;超时必须失败并停止放量,不能继续等待到作业配额耗尽。轮询同时运行受控请求,记录 T0 前的 R1、切换窗口中的实际 marker、首次全部 R2 和稳定后持续 R2;“CLI 已退出”不是所有运行单元一致的证据。若多个 region 通过不同入口服务,还要分别探测,不能只测离发布机最近的入口。
回滚不是编辑 R2,而是重新部署已知良好的 R1:
gcloud apigee apis deploy "$REV1" \
--api="$API" --environment="$ENV" --organization="$ORG" --override
gcloud apigee deployments describe \
--api="$API" --environment="$ENV" --organization="$ORG" --format=json随后重复正确凭据、错误凭据、blue/green、未知路径和后端不可达五组请求。若 R1 依赖的 KVM、target server、shared flow 或证书已经被删除,部署旧 revision 仍可能产生运行故障;所以发布制品必须同时记录依赖清单和版本,而不是只保存 ZIP。
Flow 与 Fault 决定请求在哪一层停止
请求进入 ProxyEndpoint request 后,通常依次经过 PreFlow、首个命中的条件 Flow、PostFlow,再进入 TargetEndpoint request;响应按 TargetEndpoint response、ProxyEndpoint response 返回。PostClientFlow 在响应发给客户端后执行,适合部分异步记录动作,却不能再修改已经发出的响应。
每个 <Step> 都可以带 Condition。Policy 默认 continueOnError=false,失败会终止正常 Flow 并进入 error state,之后只在发生错误的 Endpoint 中查找 FaultRule。ProxyEndpoint 的多个 FaultRule 自下而上寻找首个匹配项,TargetEndpoint 则自上而下;统一错误模型需要分别覆盖两侧。
<FaultRules>
<FaultRule name="TargetTimeout">
<Step><Name>RF-Target-Unavailable</Name></Step>
<Condition>(fault.name = "ResponseCodeError") or (fault.name = "TargetTimeout")</Condition>
</FaultRule>
</FaultRules>
<DefaultFaultRule name="DefaultFaultRule">
<Step><Name>RF-Internal-Error</Name></Step>
<AlwaysEnforce>true</AlwaysEnforce>
</DefaultFaultRule>一个稳定的反向实验应至少触发四类错误:错误 API key、Quota 耗尽、target timeout/503、显式 RaiseFault。对每次请求保存最终状态码、fault.name、命中的 Endpoint/FaultRule、后续 Step 是否执行、target 是否收到请求。这样才能区分“在网关被拒绝”和“后端失败后由网关改写响应”。
continueOnError=true 只适合团队明确允许降级的非安全步骤。它不会自动进入 FaultRule,必须在后续 Flow 中检查对应 fault variable 并决定 fail-open 还是 fail-close。VerifyAPIKey、VerifyJWT、VerifyIAM、配额和关键 ServiceCallout 不应为了“可用性”随意改成 fail-open。
Shared Flow 通过 FlowCallout 复用逻辑,并拥有独立 revision 与 deployment。升级共享身份 Flow 前要列出所有调用 proxy、目标 Environment 与回滚 revision;否则一个小改动会同时改变大量入口。Policy 类型也会影响 proxy 类型与环境资格,使用 Extensible Policy 前应从当前 Policy 参考 核对目标 Environment 类型、订阅 entitlement 与成本影响。
把 Proxy 接进项目流水线
项目仓库应把 bundle source、环境无关配置、依赖清单、测试请求与预期 fault 一起评审。环境差异通过受控参数、KVM/target server、证书引用和 IaC 表达,不应复制三份逐渐漂移的 XML。发布流水线可以按下面的状态机组织:
校验 ZIP 顶层、XML 可解析、Policy 引用存在,生成 bundle SHA-256。对照目标 Environment 的 Policy 资格、limits、IAM、attachment 与网络依赖。导入新 revision,保存 import 响应与 revision ID。
运行 change report,阻断 hostname/base path 冲突。部署到隔离 Environment,执行正向与反向请求。将同一 bundle hash 提升到下一 Environment,而不是重新打包。
观察 deployment 收敛、真实 marker、后端日志和 Analytics 延迟。超过变更预算即重新部署旧 revision,并恢复对应依赖。
Terraform 适合声明 Environment、Environment Group、Instance attachment 和 revision deployment,但它不会替代真实请求验收。已有组织首先要 import 进 state,避免把共享资源误当新对象创建;计划文件也可能含 hostname、service account 和网络信息,应按敏感制品保护。
resource "google_apigee_environment" "lab" {
org_id = "organizations/${var.org_id}"
name = var.environment
display_name = "Apigee isolated lab"
}
resource "google_apigee_instance_attachment" "lab" {
instance_id = var.instance_id
environment = google_apigee_environment.lab.name
}
resource "google_apigee_environment_api_revision_deployment" "orders" {
org_id = var.org_id
environment = google_apigee_environment.lab.name
api = var.proxy_name
revision = var.proxy_revision
override = true
sequenced_rollout = true
depends_on = [google_apigee_instance_attachment.lab]
}实际采用的 Google Provider 版本应锁入 dependency lock file,并从当前资源文档确认字段与删除语义。流水线依次运行 terraform fmt -check、terraform validate、只读 terraform plan 和人工审批后的 apply;apply 后仍须查询 deployment、attachment 并请求真实 hostname。对运行中 attachment 和 Environment 设置删除保护,清理实验时通过单独变更显式解除,避免普通重构触发停流。
Analytics、Debug、Monitoring 与日志各回答一个问题
Analytics 适合观察聚合指标与维度,例如 Environment、proxy、target、developer 或 app 的流量和延迟。它不是实时逐请求审计日志,写入会有处理延迟;刚发完请求查不到数据,既可能是延迟,也可能是维度、时间窗口或采集链错误。
Debug session 适合看单次请求经过了哪些 Flow、Policy 和 flow variable。它能回答“为什么进入 FaultRule”,却不适合长期保存每个生产请求。Debug 可能包含 Header、payload、token、KVM 和业务字段,还会受截断限制;生产会话必须限制 filter、持续时间、操作者和下载位置,并配置 data mask。
API Monitoring 与 Cloud Monitoring 用于运行趋势和告警,ingress/access/target application log 用于逐事件关联。排障时给一批合成请求写入 correlation ID,并同时保存:
| 证据 | 能回答的问题 | 不能单独证明什么 |
|---|---|---|
| Deployment/attachment | 哪个 revision 应该由哪些运行单元加载 | 请求确实命中该 revision |
| Debug session | 单次请求命中哪些 Flow、Policy 和 fault | 长期趋势与完整审计 |
| Analytics | 哪类流量、延迟和错误在聚合窗口内变化 | 某一请求的实时执行细节 |
| Access/target log | 请求是否到达入口与后端 | 控制面配置为何如此 |
| HTTP 响应 marker | 客户端实际看到哪个行为 | 所有 region 和消费者都已收敛 |
DataCapture Policy 增加自定义维度前,要审查敏感性、基数、保留和查询成本。不要采完整 token、Cookie、query 或请求体;request ID 也要区分客户端自带值与网关生成值,防止伪造审计关联。Environment 级 data mask 默认并未启用,而且只作用于新建 Debug session 中传往控制面的调试数据;它不会修改发给 target/client 的内容,也不会自动清洗 Analytics、Cloud Logging 或应用日志。每个出口都要有独立的允许列表与反向泄露检查。
Analytics export 是异步任务,单个导出日期窗口只能跨一天,并有调用频率、存储目标和权限约束。长期保留或厂商退出应把单日导出持续写到客户控制的 Cloud Storage 或 BigQuery,轮询 enqueued、running、completed、failed 状态,核对行数与 Environment,再应用加密、生命周期和删除策略。Analytics 通常存在处理延迟;Pay-as-you-go 的 Analytics add-on、停用后的数据窗口与保留权利还会影响能否查询和导出。Dashboard 截图不是历史数据备份。
托管 Apigee 与 Hybrid 改变的是责任面
官方当前多数页面把托管形态称为 Apigee,很多团队仍称其为 Apigee X。它的 management plane 与 runtime 基础设施由 Google 管理,客户仍负责 Organization、Environment、proxy、Policy、IAM、网络入口、后端、证书、数据分类、容量、成本和退出证据。
Apigee hybrid 由 Google 托管 management plane,客户在受支持的 Kubernetes 平台运行 runtime plane。Synchronizer 拉取 environment contract,Message Processor 使用本地 contract 代理请求;Cassandra 保存 KMS、OAuth、KVM、quota、cache、API product、developer app 等运行数据,MART 通过受认证的管理链路读写这些状态。
管理面连接短时中断时,已有 contract 可能继续服务旧流量;新 proxy、产品、证书和配置却不能据此保证下发。Hybrid 的故障演练要同时证明“旧请求仍可代理”和“新 revision 无法正常收敛”,恢复后再观察 contract、deployment status 与真实流量。断连可用不是完整离线控制面。
Hybrid 客户还负责 Kubernetes、节点、Ingress、StorageClass、Cassandra 容量、证书、出站代理、备份、恢复、升级和安全加固。目标版本必须从 支持平台矩阵 与对应 upgrade page 共同选择,固定 Helm chart、镜像 digest、Kubernetes 版本和 overrides;不能把“最新”当可复现版本。
网络与身份要分四条链验收
Northbound 是客户端到 Apigee。托管形态使用 PSC 时,客户侧通常由 Application Load Balancer、PSC NEG、DNS 和证书连接 Apigee service attachment。入口是外部还是内部、是否启用 Cloud Armor、跨区域如何切换,都由实际拓扑决定。资源 ACTIVE 只证明控制对象存在,还要从允许与不允许的来源分别验证 TLS、hostname、路由和拒绝点。
Southbound 是 Apigee 到 target。PSC 模式由 target VPC 暴露 service attachment,Apigee 侧创建 endpoint attachment。验收要同时看资源 state、connection state、region/global access、端口、DNS/TLS 和 target log。故意改错端口后,预期是 Apigee 返回可识别的连接 fault,target 没有请求;如果 target 仍有日志,错误可能发生在更后面的协议或应用层。
管理面身份使用 Google Cloud IAM。Project 级角色会被 Environment 继承,Environment scoped role 与 Project role 是权限并集,不存在用窄 Environment role 覆盖宽 Project role 的效果。测试最小权限时,先移除意外的 Project 宽角色,再分别验证只读、导入、部署、Debug 和删除动作。API Admin 适合管理 proxy、KVM 与 shared flow,Environment Admin 才承担部署与撤部署职责;不要为了让一条流水线同时导入和部署就授予 Organization Admin。对只读主体、发布主体和删除主体分别调用 Environment testIamPermissions,再用真实动作确认允许与拒绝,因为拥有某个角色名称并不能证明条件绑定、继承与组织策略后的有效权限。
调用面身份与管理面身份不同。托管 Apigee 可以在 Flow 中使用 VerifyIAM,并要求调用 principal 获得 invocation permission、携带有效 access token;Hybrid 不能照搬这个能力。API key、JWT/OAuth、mTLS、Google principal 与业务授权还要分别建模,网络可达绝不等于调用授权。
Proxy 调用 Google API 的 service account、provisioning service agent、Hybrid Synchronizer/MART 身份和人工管理员也不是同一个 principal。权限台账应按“谁在什么资源上执行什么动作、token audience/scope、如何轮换与撤销”记录。自动化使用短期联合身份或专用 service account;人员离开、流水线退役或 Environment 下线时单独撤销,并用旧身份持续失败来证明回收完成。
Quota、SpikeArrest、技术 limits 与合同不是一回事
Quota Policy 维护某个时间窗口内的消费计数,identifier 可以来自 app、developer、API product 或自定义变量。Distributed、Synchronous、counter scope、Policy name 与 identifier 共同决定计数共享边界。同步分布式计数更接近硬限制,却会增加协调成本并可能降低吞吐;它仍不应被描述成财务级绝对封顶。
SpikeArrest 用于平滑短时突发,Quota 用于较长窗口的消费配额。二者都不等于后端并发隔离、WAF、DDoS 防护或业务防滥用。最小容量实验要在相同总请求数下分别制造短突发与窗口耗尽,保存 fault、flow variable、后端到达数和延迟;多 region 或多 Message Processor 下还要观察超发,而不是复制单节点结果。
Product limits 是技术配置边界,Service Quotas/PSC 等依赖服务有自己的配额,Environment 类型和订阅 entitlement 又决定 Policy 资格、部署与商业权利。实施评审应为每项记录“目标形态、Environment 类型、当前 limit、是否强制、能否提升、依赖服务配额、压测结果和合同约束”。这些值会变化,应从目标组织、limits 页面 与订单重新获取,不能写进长期模板。
容量模型至少拆成请求吞吐与并发连接、Policy CPU/延迟、payload、配置对象规模、Analytics/Debug/日志出口、PSC/LB、Hybrid Cassandra/storage,以及故障时的 N-1 余量。压测必须带真实 TLS、身份 Policy、典型 payload 和目标延迟;一个无 Policy 的 200 回显吞吐不能代表生产容量。
成本同样不是一个 API call 单价。托管形态要合并 Environment/部署单元、调用、区域、LB、PSC、网络出口、Logging、Storage/BigQuery、Analytics 或安全附加能力与支持;Hybrid 还要加 Kubernetes 节点、存储、跨区流量、备份和运行团队。Pay-as-you-go 的计量维度包括附加的 Environment、API 调用与 proxy deployment,多区域 Environment 还会形成区域维度费用;订阅模式则受预购 entitlement 与超额规则约束。价格与套餐从 Apigee 价格入口 和目标合同动态重算,并按团队、Environment、proxy 类型和 region 标记成本归属。
排障先找请求停止在哪一层
拿到同一个 correlation ID 后,按入口、路由、Policy、target、响应、聚合数据的顺序收证,不要先清缓存或重新部署。下面的分型比“重启试试”更快定位责任层:
| 现象 | 第一证据 | 常见原因 | 修复后的反证 |
|---|---|---|---|
| hostname 无法连接或 TLS 错误 | DNS、LB/PSC backend、证书、来源网络 | northbound 拓扑、证书或 consumer allowlist 错误 | 允许来源成功,禁止来源仍失败 |
| Apigee 404 且 target 无日志 | Environment Group、base path、deployment/change report | group attachment 错、base path 冲突、revision 未加载 | 每个入口都命中预期 revision marker |
| 身份 4xx 且 target 无日志 | Debug 中 Verify Policy、principal/app、fault.name | token/key 错、audience 错、权限已撤销 | 正确身份成功,错误与旧身份继续失败 |
| 429 或配额 fault | Quota/SpikeArrest flow variable、identifier、counter scope | 计数范围错、窗口耗尽、突发被平滑 | 边界前后行为符合配置且后端到达数可解释 |
| 502/503 | TargetEndpoint、endpoint attachment、DNS/TLS、target log | southbound 网络、端口、证书、无健康后端 | 直连基线与经 Apigee 请求都恢复 |
| 504 或客户端超时 | target latency、连接 fault、超时与重试预算 | 后端慢、连接池/容量耗尽、重试放大 | 总耗时落在预算内且尝试次数可解释 |
| 部分流量仍是旧 marker | deployment instance status、region 入口、真实请求序列 | 最终一致未收敛、某 attachment/region 异常 | 所有入口在稳定窗口持续只返回目标 marker |
| Analytics 暂无数据 | 请求日志、Analytics 时间窗与处理状态 | 聚合延迟、维度错误、采集链问题 | 原始请求可关联,聚合在合理窗口后出现 |
若错误凭据仍到达 target,优先查看 Policy 是否真正附着、Condition 是否命中、continueOnError 与 Flow 顺序。若部署成功但请求 404,优先看 group/attachment/base path 与 revision marker。若 Analytics 有 5xx 而 target 无日志,错误多半发生在 target 连接之前;如果 target 明确返回 503,则要保留原始后端状态,避免 FaultRule 把所有错误都改成无法分型的 500。
升级、迁移与退出要保存可回退状态
托管 Apigee 的基础设施升级由 Google 管理,但客户仍要跟踪 release notes、Policy 行为、limits、网络能力和 API 变更。Proxy 发布升级继续走新 revision、隔离 Environment、正反测试、逐入口收敛与旧 revision 回滚,不要把平台托管误解为应用配置无需兼容验证。
Hybrid 升级要先固定源/目标发行线、受支持 Kubernetes、Helm chart、镜像 digest、Cassandra 与 overrides,再按目标 upgrade page 的允许路径和 guardrail 执行。多集群生产形态宜先停一部分流量、升级隔离集群、验证 management change、revision deployment、runtime data 与备份兼容,再逐集群推进。回滚条件必须在 Cassandra schema 或不可逆步骤前确定;换回旧镜像不保证能恢复已经迁移的数据。
Hybrid 备份不能只保 Cassandra。它还应覆盖 overrides.yaml、Helm values、Secret/Certificate/ConfigMap 清单、外部密钥引用和镜像清单。Cassandra restore 是整集群灾难恢复,必须在隔离的新集群中使用与备份相容的版本验证 app、credential、KVM、OAuth、quota 与真实 proxy 请求;它不能 cherry-pick 单个误删对象。
迁移到另一 Organization、另一运行形态或另一厂商时,把工作拆成五条轨道:
Config plane:proxy/shared flow、Environment、product、target server、KVM schema 与部署关系。Runtime data:developer/app、credential、OAuth、quota/cache 和 Hybrid Cassandra 状态。Network/identity:hostname、证书、LB/PSC、IAM、service account 与 Secret。
Traffic cutover:双跑、shadow/合成请求、DNS/LB 小流量切换和可回退窗口。Analytics history:持续导出、查询验证、保留、删除与审计证据。
双跑期间为源和目标写入明确但不泄露内部信息的 revision marker,比较正确身份、错误身份、两个上游、超时、配额、变换和 Fault 响应。切流从受控消费者开始;任何不可解释的状态码、延迟或计数差异都应停止扩大,而不是用平均成功率掩盖。
清理实验资源并核销费用残留
清理先保存脱敏证据和 bundle hash,再按引用逆序执行。首先停止测试流量并确认 access/target log 在观察窗口内归零;随后撤销测试 app credential 和临时 IAM,undeploy proxy,删除不再引用的 revision,最后才处理 Environment Group attachment、Instance attachment、Environment 与 Instance。
gcloud apigee apis undeploy \
--api="$API" --environment="$ENV" --organization="$ORG"
gcloud apigee deployments describe \
--api="$API" --environment="$ENV" --organization="$ORG" --format=json
curl -fsS -H "Authorization: Bearer $TOKEN" \
"$APIGEE/environments/$ENV/deployments"undeploy 后,真实 hostname 应不再返回测试 proxy,目标后端也不应出现新请求。删除 Environment 或 Instance 是更高风险动作,只能在资源清单证明它们专属于实验、无其他 deployment/attachment、账单 owner 确认后执行。不要在共享 Organization 中用批量脚本按名称前缀删除。
Terraform 管理的资源先执行并评审 destroy plan,核对每个完整 resource ID;若 deletion protection 阻止删除,应通过受审变更解除,而不是手工改 state。API 创建、Terraform state 和真实云资源三方不一致时,先 import/refresh 并查清 owner,再决定删除或保留。
Hybrid 退出还要在每个 runtime cluster 中停止入口、备份并验证可恢复性、删除对应 Helm release、按官方 decommission 流程清理 Cassandra Organization 数据,最后处理 Cloud Organization 与 entitlement。只删 namespace 会留下云端、存储、DNS、LB、镜像、备份或费用;只删 Cloud Organization 又可能留下客户集群里的敏感运行数据。
托管 Organization 删除、runtime resource 删除和商业 entitlement 终止是三个动作。执行前重新确认 soft-delete/恢复规则、计费停止条件和支持流程,并确保 proxy source、配置清单、consumer/runtime data、Analytics 导出和 DNS 回退都已落到客户可控位置。
上线前用证据而不是绿色状态收口
Organization、Environment Group、Environment、Instance attachment 与 hostname 已形成可查询关系,且每个 region 的真实请求都能关联目标 revision。bundle hash、revision、deployment、依赖资源版本和回滚 revision 同时进入发布记录;旧依赖没有被提前删除。正确身份命中两个可区分上游,错误身份、未知路径、Policy fault 与 target fault 都在预期层停止。
Flow 顺序、Step Condition、continueOnError、ProxyEndpoint/TargetEndpoint FaultRule 已通过 Debug 和 target 日志反向证明。Analytics、Debug、Monitoring、access log 各自用途明确,敏感字段经过允许列表、掩码、采样、保留与访问控制。Northbound、southbound、管理面 IAM、调用面身份分别验收;Project 宽角色不会意外扩大 Environment 权限。
Quota、SpikeArrest、技术 limits、依赖服务配额与商业 entitlement 分开建模,容量和成本来自目标形态的真实基线。托管与 Hybrid 的集群、存储、备份、升级和安全 owner 已写进责任矩阵,管理面断连测试没有被误判成完整离线能力。迁移能够重建 bundle 之外的 product、app/credential、KVM、证书、网络和 Analytics,切流步骤保留可回退窗口。
清理后测试凭据持续失败、proxy 不再可达、attachment/存储/日志导出按计划处置,账单与 entitlement 由明确 owner 核销。
