31 KiB
头程国内、尾程海外的跨区域微服务部署方案
更新时间:2026-07-29
依据:当前 D:/baiyue Spring Cloud Alibaba 微服务、悦/头程物流流程图.svg、头程下单原型和货代后台原型。
审核状态:待用户审核。本文是项目拆分、部署和迁移的实施方案;文中目标架构、海外资源和切流步骤不代表已经完成生产部署。当前生成的部署目录仅是同一 Git 仓库内的 Maven 聚合和配置骨架。
1. 结论
推荐采用“国内业务单元 + 海外业务单元 + 跨区域可靠事件桥”,不要把同一套 Nacos、MySQL、Redis 或一个微服务调用链直接横跨国内外服务器。
这里的“国内业务单元、海外业务单元”首先是代码、数据库和数据所有权边界,不等于一期必须立即购买海外服务器。当前项目应立即按两个部署单元拆分配置、服务职责和事件契约,但一期允许所有服务都部署在国内同一机房:lastleg-service、海外仓实例和海外集成实例先以 REGION_CODE=CN 运行。待事件链路、鉴权和对象存储满足迁移门槛后,再把尾程写入单元迁到海外,不需要重新拆项目。
国内单元:客户、订单、头程、国内仓、认证和权限的主数据
海外单元:尾程、海外仓、清关、提柜、派送、POD、Amazon SP-API
跨区交接:本地事务 Outbox -> HTTPS/mTLS 事件中继 -> Inbox 去重 -> 处理回执
统一轨迹:海外发布里程碑事件,国内保存只读投影供客户查询
这一方案符合原型的业务边界:
- 头程在国内完成“下单 → 到仓 → 出仓 → 装船发运”。
- 尾程在海外完成“到港前 → 到港 → 到仓 → 出仓 → 签收”。
- “装船发运”是两个区域的数据所有权交接点。
1.1 当前已生成的部署骨架
| 路径 | 当前用途 | 当前状态 |
|---|---|---|
D:/baiyue/deployments/cn |
国内部署单元 Maven 聚合、环境变量示例和构建脚本 | 已生成,待审核;一期实际部署入口 |
D:/baiyue/deployments/overseas |
海外部署单元 Maven 聚合、环境变量示例和构建脚本 | 已生成,待审核;暂不代表海外服务器已部署 |
D:/baiyue/common-event-contract |
国内外共享的事件信封、类型和区域契约 | 已生成基础源码,6 个单元测试通过;尚未接入业务事件链路,不得视为可用于生产 |
D:/baiyue/event-bridge-service |
跨区事件接收幂等、待发送事件和投递尝试的独立服务边界 | 已生成基础骨架,8 项测试通过;内部令牌、目标区域校验和 Inbox 幂等接收已实现,生产传输开关为关闭 |
两个部署目录引用根仓库现有模块,不复制业务源码,也不建立第二个 Git 仓库。构建命令为:
国内和海外聚合均已包含 common-event-contract 与 event-bridge-service。国内默认构建为 18 个 Reactor 模块;一期尾程临时在国内运行时,使用 phase1-domestic-lastleg Profile 构建 19 个 Reactor 模块并包含 lastleg。
cd D:\baiyue\deployments\cn
.\build.ps1
# 一期尾程临时部署在国内
.\build.ps1 -IncludePhase1Lastleg
cd D:\baiyue\deployments\overseas
.\build.ps1
只校验默认聚合关系时,在对应目录执行 mvn -f pom.xml -DskipTests validate;校验一期国内尾程兼容聚合时执行 mvn -f pom.xml -Pphase1-domestic-lastleg -DskipTests validate。事件契约可在根目录执行 mvn -pl common-event-contract -am test。以上构建通过只说明代码依赖和测试通过,不等于生产部署、网络连通或数据迁移验收通过。
2. 当前代码现状判断
| 模块 | 当前情况 | 对跨区部署的影响 |
|---|---|---|
gateway |
已按服务名走 Nacos 和 lb:// 路由 |
可以分别部署国内、海外 Gateway,但必须连接各自区域的 Nacos |
auth-service |
国内统一登录,HS256 JWT | 可先放国内;正式跨区前建议改为 RS256/ES256 + JWKS |
iam-service |
租户、角色、菜单、按钮权限 | 主库建议放国内,海外通过 Token 权限快照工作,不应每次跨区查询 IAM |
order-service |
已有下单和状态机,也有 ord_outbox_event |
Outbox 只是表和写入逻辑,尚缺可靠发布器、MQ/中继和跨区消费者 |
firstleg-service |
目前只有健康检查、任务分配等少量能力 | 原型中的到仓、测量、排柜、订舱、装柜、报关等还需实现 |
lastleg-service |
当前基本只有健康检查 | 还没有到港前、清关、提柜、海外仓、派送、POD 的业务闭环 |
warehouse-service |
当前是一个服务边界 | 需要区分国内仓实例和海外仓实例,各自独占区域数据库 |
file-service |
当前默认使用本地磁盘 | 跨区域部署不能继续依赖单机 D:/...,需要迁移到 OSS/S3 类对象存储 |
integration-service |
已预留百度 OCR、Amazon SP-API 配置 | 国内实例启用百度 OCR;海外实例启用 Amazon SP-API 和当地承运商接口 |
event-bridge-service |
已有端口 9300、独立库和三张基础表;内部服务令牌、目标区域、事件信封与摘要校验及 Inbox 幂等已实现,8 项测试通过 | mTLS、来源白名单、RocketMQ、真实跨公网 HTTP 投递、Outbox 扫描调度和业务消费者尚未实现,不能用于生产交接 |
因此现在可以先搭好部署骨架和事件契约,但不能把 lastleg-service 部署到海外后就认定尾程业务已经完成。
3. 推荐部署拓扑
flowchart LR
FE[客户/平台前端] --> EDGE[统一域名 + CDN/WAF/全局路由]
subgraph CN[国内业务单元]
CNGW[gateway-cn]
AUTH[auth-service]
IAM[iam-service]
ORDER[order-service]
FIRST[firstleg-service]
CNWMS[warehouse-service CN]
CNFILE[file-service CN]
CNOCR[integration-service Baidu OCR]
CNDB[(国内独立 MySQL)]
CNREDIS[(国内 Redis)]
CNNACOS[Nacos prod-cn]
CNOUT[Outbox Publisher]
CNPROJ[统一轨迹投影]
end
subgraph OS[海外业务单元]
OSGW[gateway-overseas]
LAST[lastleg-service]
OSWMS[warehouse-service OVERSEAS]
OSFILE[file-service OVERSEAS]
OSINT[integration-service Amazon/海关/承运商]
OSDB[(海外独立 MySQL)]
OSREDIS[(海外 Redis)]
OSNACOS[Nacos prod-overseas]
OSIN[Inbox Consumer]
OSOUT[Outbox Publisher]
end
EDGE -->|Auth/IAM/Order/First-leg| CNGW
EDGE -->|Last-leg/海外仓作业| OSGW
CNGW --> AUTH & IAM & ORDER & FIRST & CNWMS & CNFILE
OSGW --> LAST & OSWMS & OSFILE & OSINT
FIRST --> CNOUT
CNOUT -->|HTTPS 443 + mTLS| OSIN
OSIN --> LAST
LAST --> OSOUT
OSOUT -->|里程碑/回执 HTTPS 443 + mTLS| CNPROJ
3.1 国内部署的服务
| 服务 | 是否国内主部署 | 说明 |
|---|---|---|
gateway |
是 | 国内客户、平台后台入口 |
auth-service |
是 | 账号登录、刷新、退出的唯一写入口 |
iam-service |
是 | 企业、成员、角色、菜单和按钮权限主数据 |
order-service |
是 | 商户下单、审核、受理以及订单主档 |
firstleg-service |
是 | 到国内仓、测量差异、排柜、订舱、拖车、装柜和国内报关 |
warehouse-service |
是 | 国内仓资料和国内仓作业数据 |
file-service |
是 | 企业资质、国内报关资料、装柜照片等国内文件入口 |
integration-service |
是 | 百度 OCR、国内报关代理或港务接口适配 |
audit-service |
是 | 国内业务审计主记录 |
print-service |
按需 | 国内标签、箱唛、作业单打印 |
3.2 海外部署的服务
| 服务 | 是否海外部署 | 说明 |
|---|---|---|
gateway |
是 | 海外运营后台、海外 PDA 和承运商回调入口 |
lastleg-service |
是 | 到港前、清关、提柜、到仓、派送、签收和异常主服务 |
warehouse-service |
是 | 海外仓预约、开柜、清点、打托、拣货和装车 |
file-service |
是 | BOL、DO/PU、开柜照片、POD 等海外文件 |
integration-service |
是 | Amazon SP-API、FBA 预约、海关、码头和海外承运商适配 |
audit-service |
是 | 海外操作本地审计;摘要可异步回传国内 |
print-service |
按需 | BOL、派送单、海外标签和仓内作业单 |
海外不部署 order-service 和 firstleg-service 的写实例,国内也不部署 lastleg-service 的写实例,避免同一业务聚合在两个区域同时写入。
3.3 一期与目标物理归属
| 服务 | 一期物理位置 | 后期主写位置 | 迁移说明 |
|---|---|---|---|
auth-service、iam-service |
国内 | 国内 | 统一登录和权限主数据保持国内唯一写入 |
order-service、firstleg-service |
国内 | 国内 | 订单和头程事实保持国内唯一写入 |
lastleg-service |
国内 | 海外 | 一期先在国内运行;后期只把新创建的尾程聚合切到海外,旧单在国内排空 |
warehouse-service |
国内单实例 | 国内仓实例在国内,海外仓实例在海外 | 同一代码按区域配置部署,数据库完全隔离 |
file-service |
国内 | 国内、海外各一套 | 文件元数据和对象桶按数据产生区域归属,按业务需要复制 |
integration-service |
国内 | 国内、海外各一套 | 国内启用 OCR/港务适配,海外启用 Amazon/海关/承运商适配 |
audit-service、print-service |
国内 | 按区域各自部署 | 本地操作本地留痕和打印,不跨区同步调用 |
gateway、Nacos、Redis |
国内 | 国内、海外各一套 | 两区互不注册、互不直接访问 Redis |
4. 原型节点与服务归属
4.1 国内头程
| 原型阶段 | 原型动作 | 主要服务 |
|---|---|---|
| 下单 | 客户下单、委托下单、快速下单、换标下单 | order-service;一期仅实现普通头程订单,不扩展快速/换标完整产品 |
| 到仓 | 预约取货、送货上门 | firstleg-service + 国内 warehouse-service |
| 到仓 | 入库测量、差异核对、指定库位 | 国内 warehouse-service,结果事件回写 firstleg-service |
| 出仓 | 智能排柜、订舱、预约拖车 | firstleg-service |
| 出仓 | PDA 拣货、装柜、柜照和铅封照 | 国内 warehouse-service + file-service |
| 出仓 | 报关资料、代理报关、回执 | firstleg-service + 国内 integration-service + file-service |
| 出仓 | 港务信息、预计开船、到港 | firstleg-service + 船司/港务适配器 |
| 交接 | 装船发运 | firstleg-service 生成不可变交接快照并写 Outbox |
4.2 海外尾程
| 原型阶段 | 原型动作 | 主要服务 |
|---|---|---|
| 到港前 | FBA 仓预约、BOL 预清货、清关资料、货物中转备注 | lastleg-service + 海外 integration-service |
| 到港 | 清关放行、DO/PU、通知码头车队提柜 | lastleg-service |
| 到仓 | 开柜拍照比对、PDA 打托、派送车队预约 | lastleg-service + 海外 warehouse-service + file-service |
| 出仓 | BOL 送货、PDA 拣货装车、整柜派送、自提出仓 | lastleg-service + 海外 warehouse-service |
| 签收 | 私人仓/FBA 签收回执、送仓异常 | lastleg-service + file-service + Amazon/承运商适配器 |
5. 跨区交接设计
5.1 正确交接点
当前 order-service 在订单 APPROVED 时写 FIRST_LEG_ORDER_APPROVED,这不是尾程交接事件。尾程只能在真实“装船发运”完成后建立预到港任务。
建议新增:
FirstLegShipmentDeparted.v1
LastMileHandoffAccepted.v1
LastMileHandoffRejected.v1
LastMileMilestoneChanged.v1
LastMileCompleted.v1
5.2 交接事件示例
{
"eventId": "01J...ULID",
"eventType": "FirstLegShipmentDeparted",
"eventVersion": 1,
"occurredAt": "2026-07-29T16:30:00+08:00",
"traceId": "trace-xxx",
"sourceRegion": "CN",
"operatorTenantId": 10001,
"customerTenantId": 20001,
"aggregateId": 90001,
"aggregateVersion": 7,
"handoverVersion": 1,
"payload": {
"firstLegOrderIds": [80001, 80002],
"containerNo": "MSCU1234567",
"sealNo": "SEAL123456",
"vesselName": "EXAMPLE VESSEL",
"voyageNo": "V001",
"mblNo": "MBL001",
"hblNos": ["HBL001"],
"etd": "2026-07-30T10:00:00+08:00",
"eta": "2026-08-18T09:00:00-07:00",
"destinationPortCode": "USLAX",
"destinationWarehouse": {
"type": "FBA",
"code": "LGB8"
},
"cargoSnapshot": [],
"documentRefs": [],
"checksum": "sha256:..."
}
}
文件正文不要放进消息,只传文件 ID、版本、SHA-256 和一次性下载凭证。海外确认保存后再返回 LastMileHandoffAccepted。
5.3 可靠性规则
- 头程状态更新、状态历史和 Outbox 必须在一个国内 MySQL 本地事务中完成。
- 国内发布器轮询
PENDING/RETRYOutbox,使用 HTTPS 443 + mTLS 投递到海外事件入口。 - 海外先按
eventId写 Inbox,唯一索引去重,再创建尾程交接记录。 - 消费失败时不确认;重复投递必须返回相同业务结果。
- 海外校验通过后写本地 Outbox,异步回传 Accepted/Rejected 回执。
- 国内收到 Accepted 后才把交接状态标记为
ACCEPTED,但不能回滚已经真实发生的装船事实。 - 修改交接数据要发布更高
handoverVersion的新事件,不能覆盖旧快照。 - 跨区断网时,两个区域本地业务继续运行;Outbox 积压告警,网络恢复后自动补投。
不建议让 firstleg-service 通过 OpenFeign 跨公网同步调用 lastleg-service 创建尾程单。国际链路一次超时就会把真实装船操作拖入不确定状态。
5.4 Topic、事件桥和订单通知
一期不强制引入跨区 MQ,可由 Outbox 发布器直接通过 HTTPS/mTLS 投递;引入 RocketMQ 后,国内和海外各使用独立集群,禁止一个 Broker 集群横跨两区。建议 Topic 如下:
| Topic | 方向 | 主要事件 |
|---|---|---|
shipment-handover-cn |
国内 → 海外 | FirstLegShipmentDeparted.v1 |
shipment-handover-result-os |
海外 → 国内 | LastMileHandoffAccepted.v1、LastMileHandoffRejected.v1 |
shipment-milestone-os |
海外 → 国内 | LastMileMilestoneChanged.v1、LastMileCompleted.v1 |
security-session-cn |
国内 → 海外 | 会话撤销、账号禁用、权限版本变化 |
同一尾程聚合以 aggregateId 作为顺序键;只能保证同一聚合有序,不追求全局有序。事件入 Inbox 并提交本地事务后才返回成功,失败采用有上限的指数退避,超过阈值进入死信并告警。
短信、邮件、站内信和企业微信等客户通知不得放在订单事务内同步发送。国内 notification-service 或通知消费者订阅国内订单事件及海外回传的里程碑事件,按 eventId + channel + recipient 幂等发送;承运商回调在海外本地处理,再通过里程碑事件回传国内。
6. Gateway 与流量路由
建议对外保持一个域名,例如 api.example.com,由 CDN/WAF/全局流量入口按路径转发:
| 路径 | 目标区域 |
|---|---|
/api/auth/** |
国内 Gateway |
/api/platform/v1/iam/**、/api/merchant/v1/iam/** |
国内 Gateway |
/api/merchant/v1/orders/**、/api/platform/v1/orders/** |
国内 Gateway |
/api/merchant/v1/first-leg/**、/api/platform/v1/first-leg/** |
国内 Gateway |
/api/merchant/v1/last-leg/**、/api/platform/v1/last-leg/** |
海外 Gateway |
| 海外仓/PDA 专用路径 | 海外 Gateway |
国内 Gateway 只通过国内 Nacos 发现本地服务;海外 Gateway 只通过海外 Nacos 发现本地服务。跨区内部事件入口不暴露在普通业务 Gateway 上,应使用独立内部域名、WAF 白名单、mTLS 和消息签名。
如果暂时没有全局流量产品,可以先使用两个域名:
https://api-cn.example.com
https://api-us.example.com
前端通过同一个 API SDK 根据业务域选择基础地址,不要让浏览器知道 Nacos 服务名。
一期即固定对外域名和证书,域名先指向国内 WAF/负载均衡;计划切换前至少 7 天把 DNS TTL 调整到 300 秒。后期统一域名由全局流量入口按路径转发,auth/iam/order/first-leg 固定国内,last-leg 才允许按灰度规则转发海外。DNS 只负责稳定入口,不用 DNS 权重承担租户或订单级灰度,因为 DNS 缓存无法保证同一业务聚合始终进入同一区域。
灰度期可先使用 api-us-canary.example.com 供指定运营账号和租户验证,正式流量由 Gateway 根据可信的 execution_region 路由。Gateway 必须删除客户端伪造的区域头。若前端需要访问两个域名,CORS 只允许明确的生产前端域名、必要方法和请求头;启用 Cookie 时禁止 Access-Control-Allow-Origin: *,并统一处理预检请求。优先使用同一对外域名,减少浏览器跨域和登录态问题。
7. Nacos 设计
不要使用一个 Nacos 集群横跨国内和海外,也不要让海外服务连接国内 8848。
| 区域 | Nacos | Namespace | Group | 注册服务示例 |
|---|---|---|---|---|
| 国内 | nacos-cn.internal |
prod-cn |
BAIYUE |
gateway、auth、iam、order、firstleg、国内 warehouse/file/integration |
| 海外 | nacos-overseas.internal |
prod-overseas |
BAIYUE |
gateway、lastleg、海外 warehouse/file/integration |
两个区域可以保留相同服务名,例如都叫 warehouse-service,因为它们位于不同 Nacos 集群。配置必须增加:
REGION_CODE=CN / OVERSEAS
DEPLOYMENT_CELL=prod-cn / prod-overseas
DATA_RESIDENCY=CN / OVERSEAS
当前各服务的 spring.config.import 固定读取 group=BAIYUE,所以两个区域先保持相同 Group,通过独立集群和 Namespace 隔离。若后续希望使用 BAIYUE-CN/BAIYUE-US,必须先把所有服务配置导入 URI 中的 Group 改成环境变量。
生产密钥不得放进 Nacos 明文配置,应进入云 KMS、Secret Manager 或主机受限环境变量。
8. 数据库、Redis 和文件边界
8.1 数据库
- 国内 MySQL:
baiyue_auth、baiyue_iam、baiyue_order、baiyue_firstleg、baiyue_warehouse_cn、baiyue_file_cn、baiyue_integration_cn、baiyue_audit_cn、baiyue_print_cn。 - 一期尾程仍在国内使用
baiyue_lastleg_cn,库名提前带区域后缀,避免迁移时混淆数据所有权。 - 海外 MySQL:
baiyue_lastleg_os、baiyue_warehouse_os、baiyue_file_os、baiyue_integration_os、baiyue_audit_os、baiyue_print_os。 - 禁止跨区数据库外键、跨区事务和双写。
- 国内只保存海外状态的只读轨迹投影;海外仍是尾程事实的唯一写入者。
- ID 继续使用应用生成的雪花 ID/ULID,避免区域数据库自增 ID 冲突。
数据库迁移优先采用“旧单排空、新单切换”,不移动执行中的尾程聚合。确需迁移历史数据时,先全量复制,再用 Binlog/CDC 追平;切换前短暂停止对应聚合写入,确认延迟为零、行数和关键字段校验一致后,才允许海外库转为主写。国内旧库在回滚观察期保持只读,不得与海外库同时写入。
8.2 Redis 与登录会话
当前各 Servlet 服务会访问 Redis 检查 Access Token 的 jti 会话键。若海外 lastleg-service 直接读取国内 Redis,跨区断网会导致海外所有请求鉴权失败。
推荐目标方案:
- Auth 使用 RS256/ES256 签发短期 Access Token,海外 Gateway/服务通过 JWKS 本地缓存验签。
- Access Token 有效期缩短到 10~15 分钟。
- 登录、撤销、禁用账号发布
SessionIssued/SessionRevoked/AccountDisabled事件,复制到海外本地 Redis。 - 海外服务只访问海外 Redis,不访问国内 Redis。
以上改造是海外影子环境上线前置条件,不应放到海外正式切流之后。当前代码仍使用 HS256,并要求通过 Redis 中存在 jti 才允许访问;迁移时先支持带 kid 的 RS256/ES256 Token 和 JWKS 本地缓存,再将海外校验改为“本地验签 + 短有效期 + 本地撤销集合”。私钥只保存在国内 Auth,海外只持有公钥。过渡期国内可短暂兼容旧 Token,但海外灰度账号必须重新登录取得新 Token,稳定后移除 HS256。
PoC 阶段可以通过专线/VPN临时读取国内 Redis,但不能作为正式生产方案;Redis 的 6379 绝不能暴露公网。
8.3 文件
当前本地磁盘文件存储不适合双区域。建议:
- 国内文件进入国内 OSS/COS/S3 兼容桶。
- 海外文件进入海外区域对象存储桶。
- 只复制尾程履约必需的报关资料、BOL、箱单和授权照片。
- 文件下载使用短期预签名 URL,跨区域复制前做病毒扫描、MIME/魔数和 SHA-256 校验。
- POD 等海外原始文件保留在海外,国内保存合规副本或文件引用。
跨境传输企业、联系人、收货地址和报关资料前,应完成数据分类、最小化、访问审计和适用地区的合规评估。
9. 统一客户轨迹
客户不应为了看完整物流轨迹分别查询国内、海外两套数据库。建议国内新增“统一轨迹只读投影”,可以先放在 order-service,后续独立为 tracking-query-service。
头程本地状态 -> 国内轨迹投影
海外 LastMileMilestoneChanged -> 跨区事件 -> 国内轨迹投影
客户 GET /api/merchant/v1/orders/{id}/timeline -> 只查国内投影
轨迹投影允许最终一致,目标延迟 P95 小于 30 秒。页面应展示“最后同步时间”,跨区中断时显示“海外轨迹同步延迟”,不能把旧状态误报成业务失败。
10. integration-service 的区域部署
现有 integration-service 不需要再增加 common-sdk。同一模块按区域配置不同适配器:
| 国内实例 | 海外实例 |
|---|---|
BAIDU_OCR_ENABLED=true |
BAIDU_OCR_ENABLED=false |
AMAZON_SP_API_ENABLED=false |
AMAZON_SP_API_ENABLED=true |
| 国内港务/报关代理适配器 | Amazon SP-API、海外海关、码头、车队/承运商适配器 |
各业务服务只调用内部抽象接口,不直接依赖百度或 Amazon SDK。第三方回调必须校验签名、保存原始回调摘要,并按第三方事件 ID 幂等处理。
11. 网络和安全
- 国内与海外通过站点到站点 VPN、云企业网或专线连接;跨区业务事件只开放 HTTPS 443。
3306、6379、8848、MQ Broker 端口不得暴露公网。- 跨区事件入口使用 mTLS、IP 白名单、时间戳、nonce 和 HMAC/数字签名,防重放。
- Gateway 清除外部伪造的
X-User-Id、X-Tenant-Id、X-App-Code等内部头。 - 国内和海外使用不同数据库账号、Redis密码、内部服务 Token 和对象存储凭证。
- 所有交接、清关放行、提柜、装车、签收和人工覆盖动作写不可篡改审计日志。
- 跨区链路设置独立限流、超时、熔断和重试策略,禁止无限重试。
12. 高可用与灾备规格
12.1 正式生产推荐
每个区域至少:
- 2 个应用节点,前置负载均衡/WAF。
- 3 节点 Nacos 集群或云托管注册配置中心。
- MySQL 主备/托管高可用,开启 Binlog 和时间点恢复。
- Redis 高可用或托管版。
- 区域本地 MQ/事件中继服务。
- 区域对象存储和跨可用区备份。
目标建议:核心写接口可用性 99.9%,数据库 RPO ≤ 5 分钟、RTO ≤ 60 分钟,跨区事件 P95 ≤ 30 秒。
12.2 低成本一期过渡
可以先使用国内、海外各一台应用服务器加托管 MySQL/Redis/对象存储,但必须接受单机故障风险,并至少做到:
- Docker Compose 或 systemd 自动拉起。
- 每日全备、持续 Binlog、异地备份。
- HTTPS、WAF/安全组、只开放 80/443。
- Outbox/Inbox、失败重试和人工补投工具先完成。
- 上线前做跨区断网 30 分钟并恢复补投的演练。
13. 分阶段实施顺序
阶段 A:国内完成逻辑拆分并上线
- 所有服务仍可只部署国内,但按
CN/OVERSEAS部署单元拆分 Nacos 配置、库名、对象存储目录和服务启动清单。 - 为尾程聚合增加不可变的
execution_region,创建时确定归属,执行过程中不允许改变。 - 实现尾程五个阶段的国内版本,并将本地磁盘文件迁到国内对象存储。
- 国内先使用独立
baiyue_lastleg_cn,禁止尾程表与订单、头程或仓储跨库联表。
阶段 B:在国内打通可靠事件
- 实现
FirstLegShipmentDeparted.v1、交接回执和里程碑事件。 - 完成 Outbox 发布器、Inbox 幂等、聚合版本检查、重试、死信、人工补投和通知消费者。
- 事件桥先在国内回环运行,验证跨服务契约,不把第一次验证留到跨国网络。
- 完成重复投递、乱序、30 分钟断网、文件复制失败和恢复补投演练。
阶段 C:建立海外影子环境
- 建立独立海外 Nacos、Gateway、MySQL、Redis、对象存储和监控,不注册到国内 Nacos。
- 在切流前完成 RS256/ES256 + JWKS、海外本地撤销集合以及对象存储按需复制。
- 海外服务先只消费脱敏测试事件或生产镜像事件,禁止产生真实外部操作和业务回执。
- 对比国内结果与海外影子结果,连续 7 天满足数据、权限、性能和事件延迟门槛后才能灰度。
阶段 D:按新尾程聚合灰度
- 先选择内部测试租户,再按
1% → 10% → 30% → 100%放量,每档至少观察一个完整业务周期。 - 只有新创建的尾程聚合进入海外并永久写入
execution_region=OVERSEAS;已经在国内执行的旧单继续留在国内直至完成。 - Gateway 按聚合归属路由,不按一次请求随机分流;国内订单和统一轨迹查询入口保持不变。
- 每档验证交接成功率、事件积压、鉴权失败率、文件可用率和租户隔离后再继续放量。
阶段 E:旧单排空与正式收口
- 国内停止创建新的尾程聚合,只保留旧单处理、查询和应急能力。
- 旧单全部完成并超过售后观察期后,将
baiyue_lastleg_cn改为只读归档。 - 停止临时兼容路由和 HS256,海外成为尾程唯一写入单元;完成灾备和回滚演练后收口。
14. 上线验收门槛
- 国内 Nacos 停止海外注册后,国内服务仍能正常下单和执行头程。
- 国际链路断开时,真实装船操作成功且事件保留在 Outbox,不产生半完成尾程单。
- 网络恢复后,同一事件重复投递 10 次只创建一条尾程交接记录。
- 海外拒绝不完整交接时,国内能收到结构化拒绝原因并进入人工处理。
- 海外里程碑乱序到达时,较旧版本不能覆盖较新状态。
- 海外 MySQL/Redis短暂不可用时,不影响国内订单和头程。
- 商户 A 不能访问商户 B 的交接、柜、货物、文件和 POD。
- 未授权用户即使直接调用清关放行、装车、签收接口也返回 403。
- POD、清关资料和装柜照片下载均使用短期授权并留下审计记录。
- 跨区事件积压、死信、延迟和回执缺失均有告警和补投手册。
14.1 灰度继续和回滚阈值
- 继续放量:跨区事件 P95 小于 30 秒、P99 小于 2 分钟,交接成功率不低于 99.9%,Inbox 重复创建业务记录为 0,必需文件 SHA-256 校验通过率 100%。
- 暂停放量:最老 Outbox 积压超过 5 分钟、海外接口 P95 比国内基线升高 30%、新增 401/403 比基线升高 0.2 个百分点,或出现无法自动补投的死信。
- 立即回滚:连续 5 分钟 5xx 超过 1%、发现跨租户访问、数据丢失/重复写入、错误业务状态推进或关键文件不可恢复。
- 回滚先停止创建新的海外聚合,已有海外聚合原则上继续由海外处理,不能直接路由到国内旧库。若海外无法继续写入,必须先冻结写入,通过反向事件或 CDC 补齐国内应急库并校验后再切回;禁止两区同时写同一聚合。
- 国内旧库、旧版本应用和路由配置至少保留 7 天回滚观察期。每次切换和回滚均记录审批人、时间点、数据校验结果和路由版本。
15. 近期 P0 清单
当前 P0 基线:部署聚合入口、公共事件契约和事件桥 Inbox 幂等基础骨架已经生成;头程真实发运、尾程聚合、可靠发布传输、统一轨迹和通知仍未闭环。
P0-01:冻结装船发运交接点和FirstLegShipmentDeparted.v1字段,给尾程聚合增加不可变execution_region、聚合版本和唯一幂等键。验收:重复交接只创建一个聚合,旧版本不能覆盖新版本。P0-02:完成头程到仓、测量、排柜、订舱、装柜、报关和装船发运最小流程,生成带版本与摘要的不可变交接快照。验收:前置条件不满足不能发运,关键证据可审计。P0-03:在现有event-bridge-service基础上补齐 Outbox 扫描和发布状态机、有限重试、死信、人工补投及指标。验收:业务提交和事件不丢失,进程重启后可继续投递。P0-04:实现 Inbox 到尾程业务消费者和接受/拒绝回执,并完成尾程到港前、到港、到仓、出仓、签收五阶段。验收:重复、乱序、坏摘要和非法状态流转均有自动化测试。P0-05:先在国内回环打通事件桥,完成事件签名、来源白名单和 mTLS;RocketMQ 发布消费与真实跨区 HTTPS 投递按最终传输选型实现。验收:断网 30 分钟后可自动恢复补投,链路无跨库和同步跨区 Feign。P0-06:将文件存储抽象为对象存储,完成版本、病毒扫描、SHA-256 和短期下载授权。验收:交接所需文件可按清单受控复制且下载有租户审计。P0-07:把 JWT 改为 RS256/ES256 + JWKS,移除海外服务对国内 Redis 正向会话键的依赖。验收:海外断开国内 Redis 后仍可校验短期令牌和本地撤销信息。P0-08:建立CN/OVERSEAS配置模板、区域化数据库名和REGION_CODE/DEPLOYMENT_CELL/DATA_RESIDENCY启动校验。验收:区域错配时服务拒绝启动,两区不共享 MySQL、Redis 和 Nacos。P0-09:实现国内统一轨迹投影和异步订单通知。验收:重复不新增、乱序不回退、通知失败不回滚业务且可死信补投。P0-10:建立覆盖断网、重复、乱序、跨租户、文件失败和回滚的自动化验收。验收:国内回环全部通过后才允许建设海外影子环境。
16. 最终建议
现在最合适的落地路线不是立即购买很多服务器,而是先完成三个基础能力:
- 把
firstleg-service的真实“装船发运”节点做出来。 - 把现有 Outbox 表补成可发布、可重试、可告警的可靠事件链路。
- 在国内先为
lastleg-service实现 Inbox + 交接回执并验证五个尾程阶段,再将同一部署单元迁到海外影子环境。
完成这三项后,国内和海外才能真正成为两个可以独立运行、网络中断后仍可恢复的业务单元。