XFORCEPLUS · 架构治理

销项(Seller)系统重构方案

基于研发本体湖仓的全域资产盘点、六视角证据调研与两路对抗性核验,形成一套可回溯、可验收、可中途止损的重构路线。本报告的每个数字都可用 SQL 复跑。
定稿 v2.0 数据源:ontoos 研发本体湖仓 调研执行 2026-09-11 ~ 09-13 证据 3093 行 · SQL 161 个 · 核验实跑 44 次 覆盖缺口:源码取证 1/4 · 私有化租户为抽取盲区
45/94
SaaS 生产 workload/副本
20-phoenix-prod
435/595
私有化 workload/副本
5 租户 · SaaS 的 2.92×
≤3400
prod 去重 HTTP 端点
66% POST · 1550 个零契约
17.3TB
销项可见数据量
217 亿行 · 472 张表
19
识别出的架构债
阻塞 5 · 重要 8 · 一般 6
10/12
关键断言被核验推翻
4 条必改项
30月
路线图工期
6 阶段 · 任一刀可止损

0执行摘要

销项系统不是"代码写得差",而是失去了可验证的真相源——改一张表算不出炸到谁,改一个接口答不出谁在调,发一次补丁确定不了覆盖了哪些副本。重构的第一目标不是拆服务,而是把今天不可能的操作变为可能。

最致命的三件事

#事实为什么致命证据
1 开票主链路有 4 个独立写入方,而幂等键已确证缺失。 inv_seller_make_out_request(7 生产副本)、inv_seller_pre_invoice(9 副本) 零唯一索引;inv_seller_invoice 的唯一索引是「发票号码+代码+删除标志」事后约束,不是请求级幂等键。主服务另有 9 处把跨服务调用嵌在 @Transactional 里(1 处吞异常) 开票状态机的一致性不由任何单一服务保证。系统已把"疑似成功重试"与"金额统计订正"当作常态运维手段——这本身就是主流程一致性不可靠的自证。重复开票的结构性风险今天就存在,不是重构引入的 evidence/03 §3.3
code-1 §3.4/§4.4
verify/facts §2
2 系统的真相既不在代码里,也不完整地在配置里。 调用拓扑真值在 Apollo Ribbon listOfServers,但它只覆盖 47.6%(42 个 Feign 目标名中 20 个);PROD 另跑 Eureka,还有 8 处硬编码 URL、36 个 RestTemplate 点。68% 的定时任务(139/204)调度真相只在 XXL-Job 控制台;53% 的 MQ 发送点通道名运行时才确定;前后端契约可验证率 1.5% 任何改动的爆炸半径都算不出来,也无法证明"我没切断谁"。 这不是缺文档,是缺一个可验证的真相源——它使任何重构方案在今天都不具备验收条件 evidence/02 §4.4
evidence/04 §4.4
verify/facts §3
3 私有化比 SaaS 主站大 2.92 倍,且四分之一的副本溯源已断。 私有化 5 个 ns 合计 435 workload / 595 副本,SaaS 三环境 149/217;118 workload / 146 副本源码已从 GitLab 消失;27 条租户定制分支承载 109 副本;华润有 3 套独立销项库实例(含已 EOL 的 MySQL 5.6);反向污染已发生——20-phoenix-fat 跑着 release-huarun 的产物 "在主干修一次,全网生效"是伪命题。 不把租户路径写进方案,主线的一切成果都会在租户侧被永久稀释 evidence/06 §1/§2.3-2.5
verify/executable 断言 9

建议做什么

采用「绞杀者渐进式重构」为骨架(三视角加权 8.10,见 design/scorecard.md):不拆、不重写、不停业;用系统已有的间接层插入双向门面截流,此后每一刀走「影子读 → 双写 → 切读 → 收写 → 拆旧」五步,每步有明确的回滚动作、回滚时间、数据代价与审批人。定点嫁接方案三的零代码止血包、六个 lock 文件与 30 个可 SQL 复跑的度量指标,以及方案一的领域语义判断与 CI 三门禁。

但核验推翻了四处执行机制,必须按§ 四条必改项调整后再执行:GRANT 收权在账号拆分前不可执行;listOfServers 零代码截流只覆盖约 13/45;幂等键已确证缺失须升级为独立前置工程;抬版 2.7.x 与门面机制互斥。

代价与收益

工期30 个月(6 阶段,刻意重叠)+ 幂等前置 3~6 月进基线。可在任一阶段止损,且任一刀完成后停止,系统都比之前更简单,不留双轨
人力常驻 12 FTE(后端 6 · DBA/数据 2 · SRE/平台 2 · 前端 1 · QA/契约 1),峰值 14。累计 ≈387 人月。工期人力估算置信度 low 证据支撑"做什么、什么顺序、怎么验收",不支撑"要多久"
可验收收益公网无 WAF host 15 → 0;公网可达 /ms 端点 638 → 0;核心表写入方 4 → 1;phoenix-script-invoice 写表 231 → 0;销项持有进项库连接 4 → 0;prod workload 45 → ≤30;逐字镜像对 163 → 0;有 OpenAPI 的组件 8/34 → 30/34;调度可见率 20.6% → 100%;事务内远程调用 9 → 0;主库剥离 ≥1.4 TB
不承诺不承诺业务吞吐、响应时延或研发交付速度的直接提升
最大代价并行双轨期的运营成本:双写、影子读、回滚窗口、双份环境,且 30 个月里业务需求不会停。若组织只能投入 6 个月,只做 S0 + 治理刀 + 租户横切止血(约 5 个月),完成后系统严格优于现状且无双轨残留——不要启动 S2 之后的任何一刀

1核验修订总表

草案的 12 条关键断言,交由两路独立 refuter 对抗性核验(事实与遗漏 / 可执行性与风险),共 44 次 ontoos-probe 实跑。规则是默认判否,只有亲自查到正面证据才翻案。结果:10 条被推翻,2 条站得住。这不是形式化意见——其中 4 条直接改变了第一刀的形态与路线图结构。

#草案断言判定核验实测与定稿处置
1核心表多写方,写权收敛先于表族搬迁口径推翻 writer=2 实测 73 张不是 44 张(LIMIT 60 截断);原查询按表名聚合、无库限定,而 GRANT 作用于 db.table → ownership.lock 主键改为 (实例, schema, 表)。动作保留,口径重定
2开票主链路幂等键从未被验证推翻 该问题当场就能查清,答案是否定的:inv_seller_make_out_request(7 副本)、inv_seller_pre_invoice(9 副本) 零唯一索引 → P2 立即改判 FALSE,新增 S0.5 幂等前置工程,工期 +3~6 月进基线
3listOfServers 是东西向唯一地址来源推翻 42 个 Feign 目标名中仅 20 个(47.6%)有 Apollo 键;PROD 另配 Eureka;8 处硬编码 URL;36 个 RestTemplate 点 → 纯配置可截流上限约 13/45;L0 拆为 L0-a(热生效)/L0-b(需重启)
4各服务独立 DB 账号 → 可做表级 GRANT 收权双重推翻 本体有 code_datasources.username(草案称未覆盖);账号是按库不按服务——v4_sellinv_prod 被 4 个 workload 跨 2 个 ns 共用,phoenix-openapi 与 phoenix-seller-invoice 同账号 → S1 步④ REVOKE 必须撤回,新增 S1-b 账号拆分工程
5phoenix-openapi 不在开票同步主链路上推论推翻 字面成立,但它自带开票写入口(bizorder/task/upload-and-issue、invoice/action/generate-redletter-preinvoice、invoice/action/reverse,还有 prod 上的 mock 回调端点)——它是一条独立并行的开票链路,切错即漏票;端点数 290 → 194(斜杠伪影),连带 3701 → ≤3400
6phoenix-seller-open-api 能承接 phoenix-openapi推翻 两者路径命名空间几乎不相交(/st/+/{tenantId}/ vs /open/+/bizorder/);openapi 194 个里 46 个是进项端点,新服务只有 2 个;且替代品 prod 读的是另一台未纳管 PolarDB 的 bill 库、账号 v4_bill_dvlp → 第一刀改为「薄壳保契约」,不做"迁移到新服务"
7/ms 平面存在等价应用层鉴权两路分歧 真相是按 cluster 分裂:xplat-common-config SAAS/default token.decode.enable=true,CRC/CCAG = false → SaaS 侧风险降级、私有化侧升级。更关键:164/212 Feign client 走 /ms 且 SAAS 下解析到公网域名,原定的「/ms 公网 deny」会切断东西向 → 拆两步执行
8CDC 无契约、改表即静默断流站得住 逐条复跑成立,但计数偏低:触达销项数据的 canal 实测 16 个(草案 11),且大量用 库.* 通配 → 失败模式相反:新增列静默外泄而非断流;4 条零可见消费者的 topic 补证前不得动
9私有化是主体,25.9% 已不可改站得住 规模上修:私有化 435 wl / 595 副本 vs SaaS 149/217(2.92×);华润 3 套独立销项库实例(含 MySQL 5.6)比断言更严重。但"源码已消失"降级为"溯源待恢复"——多个失联仓在其它 group 同名在世
10租户 cluster 机制已在产 → 华润 A 档可行推翻 用错了平面:私有化租户各自跑自己的 Apollo(94-local-crc-prod = x-apollo-v1-36905-*),中央 Apollo 的 CRC/CCAG cluster 不是华润读的配置面;SAAS↔CRC 单 app 252 处分叉且 CRC PROD 值已污染 → 降级为「归因可做、归并待证」
11「开票状态」三胞胎 = 三个概念压进一个字段根因判错 枚举原文显示三者是同一概念(单据开票覆盖度)的三份复制,码 0/1/2/4/5/6/7 语义一致,仅码 3 文案漂移 → "拆成三概念"不解决冲突;改为「统一为一份规范码 + 有日落期的翻译层」,日落判据改为 CI 可查三条
12不做 SB 3.x 跨代抬版,目标 2.7.x内部矛盾 前半成立,后半与方案自身冲突:Spring Cloud 2020.0 起 Ribbon 已被移除,抬到 2.7.x 即废掉 listOfServers——而 S1 门面与 L0 回滚杠杆正建立在它上面(实测 137 个 PROD 键、9 个服务在跑 ribbon 2.0.1),且 S1/S2 窗口重叠 → S0 内必须决策

2方案完全未覆盖的在产资产

判据:在产(prod namespace、ready_replicas>0)、与销项核心数据链路直接相关、且在 1058 行草案全文中出现 0 次。这三项的存在使原方案的写方收敛指标分母错误、REVOKE 爆炸半径跨出销项域。
资产实测事实对方案的影响
sa-unify-prod /
unify-maintenance-app

2 副本
连 sellerinvoice(ds0/ds1)、bill、bill_shard、rednotification——与 20-phoenix-prod 完全相同的生产实例;MyBatis 实测对 inv_seller_invoice / inv_seller_pre_invoice / ord_salesbill 均为 read,write;账号 bill_shard_prod 与 phoenix-bill 相同 核心表真实写入方是 4 个不是 3 个 → S1/S4 的写方收敛指标(3→2→1)不可达;S2 逐表 REVOKE 会打掉一个无人知晓的生产维护系统;服务去向表缺一行。同族还有 athena-maintenance-project、athena-maintenance-walmart 各 2 副本
xf-coop-ant-coop-prod /
ant-coop-system-service

2 副本 · 活跃迭代
分支 release-20260519(4 个月前);持 v4_sellinv_prod 连 sellerinvoice——与 phoenix-seller-invoice 同账号同实例同库;无 MyBatis 记录 ≠ 不写(可能走 JPA/JdbcTemplate),权限上能写 REVOKE v4_sellinv_prod 任何权限都会波及它;"销项-进项数据层耦合归零"未涵盖"销项-协同"这条边;两条 ant-coop Feign 边用配置占位符当服务名,门面接管不到
BI 汇聚 topic
tower-invoices

18 canal 共用
janus-prod 里 18 个 canal 实例把销项 + 进项 + 租户中心 + JIRA + 4 个大客户 OQS 专库的 binlog 全推向同一个 topic;sellerinvoice.* 通配 任何 A 级表 DDL 都经此影响下游 BI;它在数据层把销项与进项再次焊死,不会随第一刀消失;通配意味着新增列(含税号、金额、身份信息)自动外流,直接关联合规

3四条必改项(P0)

以下四条若不先改,执行方案会直接导致生产事故或大规模返工。

#必改依据与后果阻塞
1S1 第一刀步④「REVOKE phoenix-openapi 账号」撤回,直到账号拆分完成。新增 S1-b「按服务拆 DB 账号」主线 v4_sellinv_prod / v4_bill_prod 由 3–4 个服务共用(含开票主服务与两个域外系统),执行即开票中断S1④ · S2 全部
2S0「/ms 公网 deny」拆两步:e1 改 SAAS cluster listOfServers 为集群内地址 → e2 才 deny 164/212 Feign client 走 /ms 且 SAAS 下经公网域名回环,直接 deny 会切断东西向调用。回滚级别从 L0 上调,「638 → 0」验收后移S0
3P2「有可靠幂等键」改判 FALSE,新增 S0.5 幂等前置工程 两张请求表零唯一索引已实测确认。在幂等落地前,第一刀只做只读端点,写端点禁止生产流量镜像S1 写路径 · S3 · S4
4S0 内决策 Ribbon 去留:二选一——放弃 2.7.x 抬版保住门面,或改用 Spring Cloud LoadBalancer + 显式地址映射作为截流平面 门面机制(S1)与抬版目标(S2)互斥且窗口重叠。拖到 S2 才发现将导致 S1 全部返工S1 · S2

4现状全景

边界破坏图:数据层的真实耦合

flowchart TB
  subgraph PUB["公网入口 · 32 host 中 15 个不过 WAF"]
    ING["Ingress / ALB
path: / 全量转发"] end subgraph SAAS["20-phoenix-prod · 45 workload / 94 副本"] INV["phoenix-seller-invoice
461 端点 · 94% POST"] BILL["phoenix-bill
调用图枢纽 · 7 条 3-环必经"] CFG["phoenix-seller-config"] NEWAPI["phoenix-seller-open-api"] OLDAPI["phoenix-openapi
停更 21 个月 · 11 库"] SCRIPT["phoenix-script-invoice
单副本 · 231 写表 · 99 job"] end subgraph OUT["名册之外的写入方 · 草案 0 次提及"] UNIFY["unify-maintenance-app
read,write 三张核心表"] ANT["ant-coop-system-service
持 v4_sellinv_prod"] end subgraph DB["共享库 · 17.3 TB / 217 亿行"] SI[("sellerinvoice
9 服务直连")] BL[("bill / bill_shard")] PUR[("进项 pim / purcfg")] end subgraph CDC["CDC 外流 · 无契约"] CANAL["16 canal 实例
库.* 通配"] TOWER["tower-invoices
18 canal 单一出口"] end TAX["taxware 通道
33 wl / 123 副本
4 种寻址写法"] TEN["私有化 5 租户
435 wl / 595 副本
2.92× SaaS"] ING --> INV ING --> BILL ING --> OLDAPI INV --> SI BILL --> BL CFG --> SI NEWAPI --> BL OLDAPI --> SI OLDAPI --> PUR SCRIPT --> SI SCRIPT --> BL SCRIPT --> PUR UNIFY --> SI UNIFY --> BL ANT --> SI SI --> CANAL BL --> CANAL PUR --> CANAL CANAL --> TOWER INV --> TAX OLDAPI --> TAX SI -.-> TEN BILL <--> INV
现状:6 个 SaaS 服务 + 2 个名册外系统共写同一批核心表;phoenix-openapi 与 phoenix-script-invoice 同时触达销项与进项库;16 个 canal 汇入单一 BI 出口——销项与进项在数据层被焊死两次

规模数字(全部可 SQL 复跑)

维度数字证据
SaaS 生产45 workload / 94 副本(20-phoenix-prod)evidence/01 §1
私有化 5 个 ns435 workload / 595 副本 / 1806 GiB = SaaS 三环境的 2.92 倍evidence/06 §1 · verify 实测
prod 去重端点≤3400,其中 66.3% 是 POST(核心服务 92–97%)——不是 REST,是 RPC-over-HTTPevidence/02 §2.2
其中 /ms 内部平面638 个,与 /api 同端口同 Ingress 同公网域名;163 对逐字镜像evidence/02 D1/D2
OpenAPI 契约仅 8 / 34 个 prod 组件有;四大核心服务合计 1550 端点零契约evidence/02 A4
公网无 WAF15 / 32 host,含开票主服务 phoenix-seller-invoice.saas.xforceplus.comevidence/02 A5
Feign 调用图84 条边 / 212 接口 / 48 个目标名;5 个 2-环 + 7 个 3-环 + 1 个自调用evidence/02 §4
数据表472 张表 / 6217 条表引用 / 14 个有 MyBatis 的 prod 服务evidence/03 §3.1
跨服务共写18 张表有 ≥3 个独立部署的写方;73 张有 2 个写方(核验修正,原 44)evidence/03 §3.3 · verify/facts §1
数据量≈17.3 TB / 217 亿行;sellerinvoice 主库 7.2 TB + shard1 3.8 TB,bill 4.9 TBevidence/03 §4.1
最大单表ord_salesbill_item 2193 GB / 24.1 亿行;inv_seller_invoice 184 列 / 1023 GB / 3.94 亿行 / 5 个物理副本evidence/03 §4.2/§4.4
定时任务204 个,其中 139 个(68%)调度真相只在 XXL-Job 控制台;phoenix-script-invoice 以 1 副本承载 99 个evidence/04 §4
MQ5 套中间件并存;receive 具名通道 219 / send 具名仅 27;53% 发送点通道名动态;销项内异步闭环仅 6 条(3.3%)evidence/04 §1.2/§2.1
前端seller-main-fe / seller-config-fe 各 53 条生产菜单,但 code_archives 0 个 archive(OSS 静态托管,机制性不可见);功能散在 ≥12 个前端仓;42 条菜单归属不明evidence/05 F1/F4
交付底座15 种基础镜像,主流是 2022 年已 deprecated 的 openjdk:8-jre(71 个服务);173/173 单阶段构建;prod 跑 12 个 Spring Boot 大版本;CI 绑在停维护的 cibase:0.5.0evidence/06 §5/§6
溯源SaaS prod gitlab_matched 75.6%,华润 prod 4.3%,阳光城/沃尔玛 0;25.9% 的私有化副本溯源已断evidence/06 §1/§2.5

5架构债诊断

分级标准:阻塞级 不解决它,其他任何重构动作都无法验证或无法安全执行;重要 直接产生业务风险或高额持续成本;一般 影响可维护性,可随主线顺带处理。

阻塞级(5 条)

#债量化影响
X1核心表有多个独立写入方,而幂等已确证缺失——inv_seller_invoice / ord_salesbill 各 4 个写方(含 2 个名册外系统),18 张核心表同构;主服务 9 处事务内挂远程调用(1 处吞异常)开票状态机一致性无单一责任方;"疑似成功重试"与"金额订正"是常态运维手段;任何双写窗口都可能产生重复开票
X2拓扑不可发现、不可静态校验——Feign 名真值在 Apollo Ribbon listOfServers 但只覆盖 47.6%;命名有大小写/后缀/拼写/裸 URL 四类不一致;异步侧 53% 发送点动态改一个服务地址要改 N 份 Apollo 配置,没有编译期或部署期保护;任何"先画拓扑再拆"的方案在同步侧漏边、异步侧漏一半
X3契约不存在,且契约面虚高近一倍——1550 端点零 OpenAPI;163 对逐字镜像(靠复制 Ms 前缀 Controller 实现)+ 102 组近似重复;1532/4380 端点定位不到源码类没有契约就无法度量"这一刀切干净了没有";改一处行为要改两处;爆炸半径不可计算
X4改动没有验证面——18 个生产服务无 fat/sit 环境(含 athena 家族 23 副本),且 prod 与 fat 跑不同分支;开票主服务 root 级 skipTests=true、无可见集成测试、12+ SNAPSHOT 直接依赖灰度在这 18 个服务上物理不可行;"改了什么导致线上变化"无法归因
X5私有化是第二条产品线,且四分之一溯源已断——435 workload 对 149;27 条定制分支/109 副本;118 workload/146 副本源码失联;反向污染已发生"改主干即全网生效"不成立;对 146 个副本,"改代码"这个选项不存在

重要(8 条)

#债量化影响
Y1phoenix-script-invoice:单副本 + 全域写权限 + 96 个不可见 cron——234 表 / 231 写表 / 2567 SQL / 275 mapper / 跨 10+ RDS(含进项、中台、蚂蚁、备份库)/ 99 定时任务它出现在 18 张 ≥3 写方表中的 17 张上。只要它还在,任何"按服务拆库"在写路径上一条也落不了地;该 pod 挂掉 96 个 job 全停;handler 名直接带客户名 = 大客户定制逻辑沉淀在无边界无契约的单副本批处理里
Y2/ms 平面在网络层零隔离——638 个内部端点与 /api 同端口、同 Ingress(path: / 全量转发)、同公网 ALB、无 WAF;含 /ms/api/v1/invoice/devOps 运维后门核验确认应用层鉴权按 cluster 分裂:SAAS 有、CRC/CCAG 为 false → SaaS 侧降为架构债,私有化侧仍是安全暴露面
Y3phoenix-openapi 是销项-进项在数据层的焊点——11 个 datasource 横跨销项 5 库 + 进项 purcfg/pim + 跨域 auth/matching;27 张写表含两张主表;停更 21 个月;公网无 WAF它绕过进项服务的任何 API 边界,在数据层把两个域焊死。核验进一步发现它自带完整开票写入口,是并行主链路而非旁路
Y4CDC 外流无契约——inv_seller_invoice 5 个物理副本 + 16 个 canal 实例监听;CANAL_FILTER 写在容器环境变量里逐条枚举,改表名/拆表会静默断流且零审计留痕;大量 库.* 通配则导致新增列静默外泄一次 inv_seller_invoice 的 DDL,影响面 = 4 写服务 + 4 读服务 + 5 物理副本 + 多条 prod CDC 链路 + 其下游 ES/数仓/AI 库 + tower-invoices BI 出口
Y5PreciseShardingAlgorithmImpl 是正在运行的静默数据错置通道——分片键=租户 id,映射 init() 一次性加载内存不刷新,查不到映射静默回落 ds0新增/迁移租户分片必须重启全部 6 副本;配置漏配不报错,会把数据写进错误的库(源码直证)
Y6「开票状态」三胞胎——BillMakeOutStatus(9) / SalesBillMakeOutStatusEnum(8) / BizOrderMakeOutStatusEnum(8) 三仓独立定义核验修正根因:三者是同一概念的三份复制,仅码 3 文案漂移、码 9 只有一方认识 → 不是"三个概念",而是缺少单一权威定义;销项 15 个后端合计 1360 枚举类 / 307 状态枚举
Y7athena-elastic-consumer:分支当部署单元——1 仓 × 5 条分支 = prod 10 workload / 23 副本,身份 100% 由 2 个配置键决定;其 Apollo app_id 拼写错、在 113 个 app 中不存在,真值在 K8s ConfigMap,零审计改错一个值,consumer 会消费另一张表的 binlog 并写进错误的 ES 索引;每个变体暴露相同的 7 个运维端点含无鉴权 /stop
Y8yl-ops-agent-service 爆炸半径最大——2 副本直连 12 个库(销项 6 + 进项 + 中台 + 租户中心),公网域名无 WAF;声明只读却用各库 owner 账号,权限上可写单点拥有跨域写能力且无审计约束;"降权 + 审计化"的第一步其实是换账号而非改代码
一般(6 条)· 展开
#债说明
Z1交付底座断代15 种基础镜像 / 71 服务用已 deprecated 的 openjdk:8-jre / 173 全单阶段构建 / 12 个 SB 大版本 / fastjson 1.2.7 在 10 workload 23 副本 / CI 绑停维护镜像
Z2资源配置无分级26 个 prod workload 的 cpu limit 恰好 = 8.0/8.1(模板默认),而真正的大服务只有 4.0/2.0;私有化侧 65 个容器无 memory limit;10 个 prod workload 无 readiness probe
Z3前端三代 IA 并存2023/2024/2026 三代导航共存,7+ 模块各出现 2 次;seller-main-fe 同仓两代微前端框架并存;42 条菜单归属不明
Z4错误码体系失衡phoenix-seller-invoice 仅 62 个错误码却有 354 throw-literal + 498 log-error;两代 openapi 双份维护 605 + 579
Z5路径与命名规范缺失208 条无前导斜杠路径(123 条与带斜杠版本双注册);6 种不共存的路径前缀体系;51 个 ≥15 op 的巨型 Controller 承载 2051 op
Z6OQS 四胞胎泛化数据面4 个服务各自暴露同一套 67 端点,含 27 个 /bos/{boId}/entities 泛化写接口 + /graphql + /altair + /voyager IDE 在 prod

6目标与路线图

核心机制:每一刀都走同一套五步

flowchart LR
  A["① 影子读
新路径只读
diff 量化覆盖率"] --> B["② 双写
硬上限 90 天
幂等前置为准入"] B --> C["③ 切读
按租户/接口族灰度
可秒级回切"] C --> D["④ 收写
GRANT 物理兑现
需账号拆分完成"] D --> E["⑤ 拆旧
旧路径 30 天零流量
方可下线"] E --> F["出口标志
旧路径零流量
≠ 新路径上线"]
每步都有明确的回滚动作、回滚时间、数据代价与审批人;出口标志是"旧路径零流量"而非"新路径上线"——这是防止双轨永久化的关键设计

阶段总览

核验后新增:S0.5 幂等前置工程(S1 之前,工期 +3~6 月进基线)与 S1-b 按服务拆 DB 账号(所有 REVOKE 动作的前置)。S0 内另设 Ribbon 去留决策门。
阶段月份一句话目标出口标志(= 旧路径零流量)最高回滚
S00–3止血 + 看得见核实项有结论;六个 lock 存在且 CI 强制;分片静默错置已修;99 job 单点已消除;Ribbon 去留已决策L0
S0.5+3~6幂等前置 新增三张核心请求表具备请求级幂等键;重复度普查清洗完成L1
S12–9门面就位 + 第一刀南北东西流量经门面(覆盖率分母按 45 目标名重定义);phoenix-openapi 连续 30 天零流量。第一刀改为薄壳保契约L1
S1-b并行按服务拆 DB 账号 新增一服务一账号;共用账号持有者清单归零L2
S27–15写权收口 + 租户耦合切断A 级 18 张表非授权写方 GRANT 清零;CCAG 专库与 SaaS 解耦L4
S312–20接口族搬迁:红冲 → 预制发票两域在新服务上跑,旧路径连续 30 天零流量L3
S418–26开票/单据解环 + 大表减负bill→invoice 同步 Feign 归零;1.49 TB 日志表剥离完成L3+L5
S524–30遗留下线 + 租户收敛遗留服务下线;租户按 A/B/C/D 定级完成L5
止损设计:路线图按可独立交付的刀组织,任一刀完成后停止,系统都比之前更简单、不留双轨。双写期硬上限 90 天;翻译表宿主在版本化 kernel 而非门面,避免翻译层永久化。若组织只能投入 6 个月,只做 S0 + 治理刀 + 租户横切止血,不要启动 S2 之后的任何一刀。

7风险登记册(节选)

#风险概率影响缓解措施
R1开票主链路无可靠幂等键,双写/切流期出现重复开票已确证极高升级为 S0.5 独立工程;幂等落地前禁止开票写路径双写与流量镜像;重复开票率设为一票否决指标
R4/ms 平面 638 个内部端点含 devOps 后门在公网无 WAF 暴露中极高核验确认 SAAS 有应用层鉴权(风险下调)、CRC/CCAG 为 false(私有化侧仍需紧急处置);deny 拆两步执行
R5phoenix-script-invoice 的 99 个批处理含未文档化的大客户业务逻辑,拆分时丢失行为高高拆分不重写,原样搬运 + 逐 job 对账;按客户拆使每客户可独立回滚;拆前 30 天输出基线快照;每个 job 停用前"空跑 + diff"2 周
R6租户侧(尤其华润)不配合跟随,主线成果被永久分叉稀释高高四条跟随契约写入商务协议;CI 硬规则堵反向污染;核验推翻了"中央 Apollo cluster 可作合流抓手",A 档降为「归因可做、归并待证」
R7CDC 静默断流或静默外泄导致 ES/数仓/AI 库停更、或新增列自动外流中高cdc.lock(扩至 16 canal + tower-invoices)+ DDL 门禁四问 + 位点快照 + 24h 下游同比校验;4 条零可见消费者 topic 补证前不得动
R1018 个生产服务无测试环境,合并/搬迁无法灰度验证已是事实中高S0 强制补齐,优先 athena 家族,且要求 prod 与 fat 同分支;未补齐的服务不得进入任何合并/搬迁动作
R13项目中途停止,系统永久停在"新旧双轨 + 双写 + 门面多一跳"——比重构前更复杂中高高每阶段出口标志是"旧路径零流量";按可独立交付的刀组织;双写期硬上限 90 天;翻译表宿主在版本化 kernel
R14税局通道在代码侧完全不可见,重构中意外打断开票执行链路低极高该通道只在网络层可见(2 个 ExternalName + 2 条 Ingress),代码侧检索 0 行。补证完成前不得触碰 taxware 相关配置
R17归档/删除动作触及税务法定留存义务中极高四条合规硬规则;不可逆动作门禁新增合规评审;在法务口径明确前维持"只冷存不删"

8落地前待验证清单

核验阶段已用现有湖仓数据当场解决了 4 项原定核实(幂等键、DB 账号、/ms 鉴权、listOfServers 唯一性)。下列 12 项仍然悬空,且会改变方案动作。标「阻塞」的,在验证完成前对应阶段不得启动。

#待验证验证方法(可立即执行)阻塞
V1是否还有更多 namespace 名册之外的核心表写入方放弃 ns 关键词过滤,从数据面反查:按 jdbc_url 中的实例 id 全库反查持有连接的 component,再 ⋈ code_mybatis_table_refs 取 writeS1④ · S2 · S4
V2三个共用账号的完整持有者名单与实际权限问 DBA 取 SELECT user,host FROM mysql.user + SHOW GRANTS;用连接来源 IP 反查实际使用方S1-b
V3两张请求表建唯一索引的在线可行性(存量可能已有重复行)先跑重复度普查(按候选幂等键 GROUP BY … HAVING count(*)>1),再定"先清洗后建索引"还是"幂等表旁路"S0.5
V4Ribbon 去留:9 个服务能否在不抬 SB 版本的前提下长期维持盘 SB/SC 版本矩阵;评估 Spring Cloud LoadBalancer + 显式地址映射作为替代截流平面的改造量S0 决策门
V5三个隐性下游(ods / ai-tm-ai-invoice / sellerinvoice_bak)的消费方与 SLA以 binlog dump 连接数反查订阅方(数据库侧可观测),而非依赖配置登记S4 · A 级 DDL
V6tower-invoices 的下游消费方清单查 MQ 侧消费组注册(本体只覆盖发送侧,消费方需从 MQ 控制台取)S4 · 合规
V7phoenix-seller-open-api 的 prod 数据源真值与 PolarDB 纳管状态code-probe 取证 + 问 DBA。湖仓显示它用 dvlp 账号连一台未纳管实例第一刀定稿
V894-local-crc-prod 的 Apollo 指向(本地 vs 中央)查该 ns 的 APOLLO_META / config-service env租户 A 档
V9tenant-security-server-starter 的装配语义(默认拦截 vs 默认放行)读 jar 的 spring.factories 与自动装配条件/ms 风险定级
V10三个无源码取证服务的真实形态ontoos-code-probe 对部署 commit 取证(命令已就绪,本次因额度中断未完成)服务去向表
V11华润 3 套独立销项库实例(含 MySQL 5.6)的版本、容量与同步关系dms_instances ⋈ dms_databases 按租户过滤;容量用 store_capacity(单位 MB)租户分档
V12税务合规:归档/删除/列裁剪在监管上是否可行非技术验证——需财税合规与法务给出留存年限与可删除范围的书面口径S4 大表减负

9本次调研自身暴露的方法论教训

unify-maintenance-app 被漏掉,恰恰印证了资产盘点阶段自己写下的警告,而调研在更高一层重犯了同样的错误。

资产盘点的结论 C1 说的是:在一个 namespace 内用服务名关键词(seller)圈定会系统性漏服务,必须按 namespace 圈定。但调研随后用 ILIKE '%phoenix%|%lmt%|%crc%|…' 给 namespace 本身做了关键词过滤——sa-unify-prod 一个模式都不匹配,于是一个对三张核心表有写权限的生产系统整体消失在视野外。

教训:资产圈定不能靠命名,只能靠关系。对下一轮调研与 S0 的资产普查,圈定入口应改为:

  • 先锚定物理数据面(RDS 实例 id / 库名),而非服务名或 namespace 名;
  • 从数据面反查所有持有连接的 component(code_datasources.jdbc_url 全库匹配);
  • 再从 component 反查 workload 与 GitLab 归属;
  • 命名关键词只用于交叉验证,不用于圈定。

同理适用于 MQ(从 topic 反查而非从服务反查)与前端(从门户菜单反查而非从仓库反查——证据已表明镜像抽取对 OSS 发布的前端天然失明)。

10证据与口径

数据源ontoos 研发本体湖仓(AnalyticDB for PostgreSQL),逻辑层 ods_current / dwd_current / dws;批次以 meta.batch_status 活跃批次为准(抽取激活 2026-09-06)
调研执行2026-09-11 ~ 2026-09-13
证据规模evidence/ 7 份共 3093 行 · sql/ 161 个可复跑 SQL · verify/ 2 份共 119 KB(含 44 次核验期实跑) · design/ 3 套候选方案共 3258 行
覆盖缺口① 源码取证仅完成 phoenix-seller-invoice 1/4,其余三服务结论均为元数据推断;② 私有化租户是抽取盲区(94-local-crc-prod 覆盖率 13.7%、p1099-wmt-prod 0%);③ MQ 消费侧、前端 OSS 发布物、XXL-Job 调度面本体均不覆盖
复跑方式cd ontoos-probe && python scripts/probe.py --format csv "<SQL>";SQL 直接写逻辑层名,probe 自动解析为实名
文档版本定稿 v2.0——由 v1.0 草案吸收两路对抗性核验修订而成。完整方案见 REFACTOR-PLAN.md(1208 行)
产出文件索引 · 展开
文件内容
REFACTOR-PLAN.md最终方案定稿(1208 行 / 13 节),含核验修订总表、执行摘要、架构债诊断、目标架构、路线图、数据迁移、租户策略、风险登记册、度量体系、待验证清单、证据索引
evidence/00-digest.md证据索引与六视角核心结论浓缩(347 行)
evidence/01-inventory.md资产总盘点:服务、仓库、部署位点、抽取覆盖率、溯源缺口(343 行)
evidence/02-api-topology.md接口与调用拓扑:端点规模、契约面、Feign 调用图与环、跨域边界、公网入口(651 行)
evidence/03-data-assets.md数据资产与血缘:共享库热力、跨服务共写、库表规模、CDC 外流(297 行)
evidence/04-async-config.md异步集成与配置治理:MQ 拓扑、孤儿通道、定时任务、Apollo 漂移(342 行)
evidence/05-frontend-portal.md前端与业务入口:功能地图、状态机、契约漂移、错误码(300 行)
evidence/06-deploy-tenancy.md部署形态与多租户:环境矩阵、租户分叉、资源足迹、交付链路(687 行)
evidence/code-1-*.mdphoenix-seller-invoice 部署 commit 源码取证(473 行,含 file:line 级证据)
design/option-1..3-*.md三套独立视角候选方案:DDD 边界重划 / 绞杀者渐进 / 地基工程(共 3258 行)
design/scorecard.md三视角评委评分与嫁接建议(263 行)
verify/facts.md对抗性核验 · 事实正确性与遗漏(57 KB,24 次实跑)
verify/executable.md对抗性核验 · 可执行性与风险(62 KB,20+ 次实跑)
sql/161 个可复跑 SQL,按视角前缀命名