一份策略,两个执行点

流量路由策略中心

说明策略如何由配置发布链路提供,并分别指导入口地域与认证后后端的选择。

说明策略如何由配置发布链路提供,并分别指导入口地域与认证后后端的选择。

7. 路由与多地域设计

7.1 路由模型

每条路由配置至少包含以下信息:

路由发布前必须通过静态校验:路由无冲突、required scope 存在、目标服务已注册、写请求明确声明幂等策略、超时有上限。

7.1.1 流量路由策略中心决策逻辑

流量路由策略中心维护一份版本化策略,但在两个位置执行。第一执行点位于全局入口,只负责选择入口地域;第二执行点位于地域网关,在 API Key 验证和路由匹配完成后选择后端。入口阶段使用的商户或平台提示未经认证,只能缩小入口候选集,不能授予权限;进入地域后必须以已验证身份复核,不一致时重新选择合格后端或拒绝请求。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB PUBLISHED["已发布策略<br/>primary_region · allowed_regions<br/>服务能力 · failover_mode"] --> CENTER["流量路由策略中心<br/>编译版本化策略与运行状态视图"] RUNTIME["运行信号<br/>地域 / 后端健康 · 复制延迟 · writer 状态"] --> CENTER HINT["未认证路由提示<br/>仅用于选入口 · 不授予权限"] --> EDGE_FILTER["执行点 1 · 入口候选过滤<br/>allowed_regions · 合规 · 地域健康"] EDGE_FILTER --> MODE{"已配置策略模式"} MODE --> FIXED["设计基线 · 固定首选<br/>不自动切换"] MODE --> FAILOVER["设计基线 · 主备<br/>仅向合格备用地域切换"] MODE --> MULTI["建议选项 · 默认关闭<br/>allowed_regions 内权重 / 就近<br/>仅无状态读取"] FIXED --> ENTRY["入口地域决定<br/>失败时停止解析或返回 503<br/>取决于全局流量产品"] FAILOVER --> ENTRY MULTI --> ENTRY ENTRY --> AUTH["地域入口<br/>API Key 验证 + 路由匹配"] AUTH --> CONTEXT["已验证商户<br/>route + request_class"] CANDIDATES["执行点 2 · 认证后候选过滤<br/>服务已部署 · 健康<br/>配置按第 10.4 节有界陈旧"] CONTEXT --> CLASS{"请求类型"} CANDIDATES --> CLASS CLASS -->|"读取"| READ_GATE["读取门禁<br/>复制延迟不超过阈值<br/>状态信号未过期"] CLASS -->|"写入"| WRITE_GATE["写入门禁<br/>当前 writer 优先<br/>跨地域需全局幂等 · 唯一约束 · 显式切主"] READ_GATE --> ELIGIBLE{"过滤后有候选?"} WRITE_GATE --> ELIGIBLE ELIGIBLE -->|"是"| DECISION["输出路由决定<br/>target · reason_code · policy_version"] ELIGIBLE -->|"否"| REJECT["失败关闭<br/>返回 503"] CENTER -.->|"入口策略与状态视图"| EDGE_FILTER CENTER -.->|"地域内策略与状态视图"| CANDIDATES classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef policy fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef baseline fill:#EAF2FF,stroke:#1264D6,color:#12345B,stroke-width:1.5px classDef proposed fill:#FFF7E8,stroke:#B7791F,color:#62420F,stroke-width:1.5px classDef runtime fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef reject fill:#FFF2EC,stroke:#C7582B,color:#6B2812,stroke-width:1.5px class PUBLISHED,RUNTIME,HINT,CONTEXT input class CENTER,EDGE_FILTER,MODE,CANDIDATES,CLASS,ELIGIBLE policy class FIXED,FAILOVER,ENTRY,AUTH,READ_GATE,WRITE_GATE,DECISION baseline class MULTI proposed class REJECT reject

会议只确认了多地域冗余和路由能力,没有确定具体算法。固定首选与主备模式是当前设计基线;权重或就近多活属于建议选项,默认关闭,只能在商户显式允许的地域集合内用于无状态读取。执行点 1 在认证前无法可靠判断请求类型;如果写请求被送到非 writer 地域,执行点 2 仍必须选择当前 writer 或返回 503,不得产生跨地域盲写。全局流量产品、TLS 终止点和认证前路由提示机制尚未确定,因此入口失败行为与可用输入需要在选型后确认。图中的 reason_code 只写入内部决策日志与审计,不对外披露;对外错误遵循第 6.2 节。

7.2 商户地域归属

为每个商户维护显式的首选地域和可用地域列表。流量路由策略中心把策略发布到两个执行点:全局入口优先把商户请求送到首选地域,地域内网关在认证后根据商户路由分区、服务能力和请求类型选择后端。

商户地域归属不能只依赖 DNS 解析地理位置,因为商户出口、专线接入点和业务数据所在地可能不同。地域策略必须由控制面配置并审计。

7.3 区域故障转移

  1. 网关数据面按多可用区部署,单实例或单可用区故障由区域负载均衡自动摘除。
  2. 流量路由策略中心的入口执行点确认地域不可用后,只把允许故障转移的商户切换到已配置且合格的备用地域。
  3. 每个平台接入时必须声明读取一致性等级、最大允许复制延迟、复制状态信号的采集方式和信号最大有效期。读取请求只有在备用地域上报的复制延迟不超过该路由的最大允许值,且状态信号未过期时才允许自动故障转移。
  4. 支付写请求只有在后端平台提供全局幂等键、唯一约束和明确的写入主地域切换机制时才能跨地域重试。
  5. 后端未满足跨地域写入前提时,网关返回可追踪的 503,禁止同时向两个地域写入。
  6. 区域恢复后采用受控回切,先验证授权配置版本和后端复制状态,再逐步恢复流量。

7.4 后端多数据库边界

会议提到 Zero Confirmation 可能使用三个数据库,BPS 未来也可能采用相似模式。网关只保存“商户或分区应路由到哪个后端服务”的元数据,不直接持有业务分库连接,也不拆分业务 SQL。

每个平台必须自行保证:

  1. 分区映射和业务数据库拓扑的一致性。
  2. 交易写入的唯一约束和幂等语义。
  3. 跨地域复制、恢复点和恢复时间。
  4. 数据库切换完成后向网关发布新的可用服务端点或路由版本。

7.5 控制面容灾

统一控制面采用跨地域主动与备用模式,任何时刻只允许一个控制面地域写入:

  1. PostgreSQL 在主地域内同步复制,在备用地域异步复制 WAL;备用地域复制延迟目标不超过 60 秒。
  2. 控制面版本使用 (epoch, sequence) 二段版本并按字典序比较。正常提交只递增 sequence,主地域切换时先递增 epoch 再从新的 sequence 开始,禁止两个地域产生可比较但分叉的版本。
  3. 主地域提升或备用地域接管前,必须通过托管数据库围栏或共识租约确认旧主节点已失去写权限;无法完成围栏时禁止接管。
  4. 控制面实例只有持有有效单写租约时才能接受管理写入,租约过期立即失败关闭。
  5. 备用地域 WAL 应用延迟超过 60 秒时停止接受普通配置写入并告警;紧急只拒绝操作改走第 10.3 节的 break-glass 通道。
  6. 接管后先恢复未发布 Outbox 事件,再以新 epoch 发布完整配置快照;各地域拒绝旧 epoch 的任何事件。
  7. 控制面建议恢复时间目标为 30 分钟,配置恢复点目标为 1 分钟;这两个目标必须通过季度恢复演练验证。

控制面故障不应中断已加载配置的数据面请求,但会暂停普通 Key 创建、轮换、Scope 变更、IP 变更和路由发布。