页面 JSON Schema 版本管理

解读

国内高并发业务(电商、SaaS、小程序)普遍采用“前后端分离 + 多端复用”架构,页面渲染字段由后端下发的 JSON Schema 驱动。Schema 一旦变更,H5、小程序、APP 三端必须同步兼容;若上线节奏不一致,就会出现“白屏”“字段错位”等 P0 事故。因此面试官想确认候选人是否具备“Schema 向前兼容 + 灰度发布 + 回滚”的落地经验,而不仅仅是“写个版本号字段”这么简单。

知识点

  1. JSON Schema 规范(draft-07/2019-09)与自定义 meta:version
  2. SemVer 语义化版本在接口层的裁剪规则(主版本.breaking、次版本.additive、修订版.fix)
  3. PHP 侧版本决策策略:请求头 X-SCHEMA-VERSION、UA 指纹、用户白名单、城市灰度
  4. 多版本共存代码组织:命名空间隔离、策略模式、Composer 自动加载 PSR-4
  5. 存储方案:Git 单仓多分支、对象存储(OSS)按版本分目录、MySQL blob + 唯一索引(version, page_id)
  6. 性能与回滚:OPcache 预热、Schema 缓存 Redis Hash、回滚时 CDN 302 重定向到旧版本目录
  7. 安全:Schema 写入权限走 Code Review + 运维 LOCK 文件,防止前端私自改结构
  8. 监控:Elasticsearch 建立 version.keyword 字段, Grafana 看板实时对比“新版本 5xx 率”与“旧版本”差异,超过 1% 自动回滚

答案

“我上一份在电商大促团队负责会场投放,日均 6 亿次 Schema 下发。我们的版本管理分四层:

① 版本号规则:采用 主.次.修订 三段式,但只有主版本号升级才允许删字段或改类型;次版本号只增字段并给默认值;修订号仅改描述。规则写进 CONTRIBUTING.md,合并请求 CI 会跑 json-schema-diff 工具,若出现 breaking change 而主版本号未升级,直接拒绝合并。

② PHP 加载链路:Laravel 路由层收到带 X-SCHEMA-VERSION: 2.3.1 的请求后,先查 Redis Hash key=schema:2.3.1:homepage, miss 回源到 OSS 目录 /schema/v2/3/1/homepage.json,文件内容用 gzip 压缩,回写 Redis 并设置 5 分钟 TTL。若客户端未带版本头,则按用户白名单 10% 灰度到最新版,其余 fallback 到上一主版本。

③ 代码隔离: breaking 版本升级时,后端同时保留两个 Transformer 类,如 AppJsonV2Transformer 与 AppJsonV3Transformer,用策略模式根据版本号实例化,保证同一套业务数据可以吐出不同形状,避免 if/else 爆炸。

④ 灰度与回滚:灰度信息写入 Apollo 配置,PHP 进程每分钟拉一次;一旦 Sentry 报警量或 Grafana 曲线异常,运维在 30 秒内把灰度比例改 0%,CDN 302 到旧版本目录,实现用户无感回滚。

⑤ 上线流程:Schema 文件合并到 master 后,GitLab CI 自动打 tag,OSS 同步脚本把 json 文件按语义化目录推送,并生成 md5 文件供 PHP 校验完整性;同时把新版本号写入 DB 白名单表,灰度系统才能识别。

通过这套机制,我们在 618 期间做到 0 次因 Schema 变更导致的会场白屏,回滚平均耗时 28 秒,版本回退率低于 0.02%。”

拓展思考

  1. 如果公司把页面配置权完全交给运营,Schema 由低代码平台拖拽生成,PHP 如何实时校验“运营生成的 Schema 是否向前兼容”?是否需要在保存前跑一遍 json-schema-diff 并阻塞发布?
  2. 当小程序审核周期长达 3 天,而后端需要每天迭代,怎样利用“特性开关 + 多版本 Schema”让已发版的小程序在审核期间不被新字段炸掉,同时保证新小程序能用到新功能?
  3. 在微服务场景下,商品、营销、用户三个域各自维护子 Schema,PHP 聚合层如何做“版本矩阵”兼容性检查,避免 A 域 v2 与 B 域 v1 组合后出现字段冲突?
  4. 若未来接入 TypeScript 自动生成的 Type,从 JSON Schema → Type → PHP DTO,如何保证三端类型定义同源,防止“PHP 改字段而前端没感知”?