微服务系统的分阶段切换 📅 2026/8/22 20:46:43 切换顺序要尊重数据事实先拆边缘读服务能把路由、监控和回退机制跑通又不必一开始处理最复杂的数据一致性。涉及核心写入时先定义事实源和双写失败策略没有这两项所谓平滑切换只是把问题延后。网关的灰度规则应可读、可审查。按明确路由条件推进避免让某个用户因为随机命中而在新旧系统间来回跳。微服务系统的分阶段切换旧系统迁移的重点不在于快速拆出多少服务而在于保留业务规则、控制数据变更并且随时能停止或回退。全量重写的常见风险全量重写经常把风险集中到同一个上线窗口典型问题包括隐式业务逻辑丢失老系统里有一段看似冗余的if逻辑其实是为了兼容五年前某个大客户的特殊结算规则。重写时由于没人看得懂旧代码直接删掉了导致上线首日大量结算账单报错。数据双写引发死锁与脏数据为了保持新旧数据库同步团队在应用层写了双写逻辑由于没有考虑分布式事务锁的顺序造成旧 Oracle 数据库与新 MySQL 数据库频繁死锁。运维与测试压力集中爆发数十个全新的微服务同时上线链路追踪SkyWalking、日志收集ELK、配置中心Nacos同时承受压力任何一个节点配置错误都会引发连锁雪崩。从边界清晰的模块开始拆分要实现稳妥迁移模块的切割顺序至关重要。第一阶段先拆边缘服务优先拆分边缘、独立且不频繁读写主数据库的模块例如短信通知服务、图片文件上传服务、报表导出服务。这些服务即使在新环境中出了故障也不会影响主交易流程。同时团队可以借此机会把 Spring Cloud Gateway、Nacos 注册中心、Sentinel 限流组件的自动化 CI/CD 流程踩通。第二阶段逐步分离核心读写选择一个业务边界清晰的核心模块如“商品中心”。先剥离读流量新建product-service微服务直接读取旧单体数据库的只读副本。通过 Gateway 将/api/product/detail的读请求切给新微服务。后剥离写流量与数据迁移使用 Canal 或 Debezium 监听旧数据库 Binlog实时同步到新微服务的独立数据库中。双向同步稳定运行一周后将写请求切到新微服务。用网关控制切换节奏在迁移过程中网关Spring Cloud Gateway是控制流量走向的“指挥官”。我们可以通过配置基于 Predicate 的权重策略实现动态、无感的切流spring: cloud: gateway: routes: # 1. 新微服务路由 (按权重切流 20%) - id: order-service-new uri: lb://order-service predicates: - Path/api/orders/** - Weightorder_group, 20 filters: - StripPrefix1 # 2. 旧单体应用路由 (承接剩余 80% 流量) - id: legacy-monolith-old uri: http://legacy-monolith-host:8080 predicates: - Path/api/orders/** - Weightorder_group, 80当新服务在小流量下满足事先设定的错误率、延迟和业务校验条件后再按可回退的步骤扩大权重。每个阶段都应保留观察时间和停止条件。迁移过程中的边界避免新的跨库耦合新服务不宜把其他模块的表当作长期依赖。需要跨边界数据时可评估接口查询、事件订阅或本地只读视图并说明一致性和延迟取舍。保持 API 协议向前兼容新微服务的接口字段格式必须严格兼容旧单体的输出。如果旧系统返回的 JSON 结构中某个字段叫user_name新微服务不要随便改成username否则前端和三方系统会被迫跟着一起重构。保留回滚开关在网关或配置中心设置切回旧链路的开关并通过演练确认权限、传播时间和切换后的数据处理方式。架构演进不是一蹴而就的艺术而是小心翼翼的权衡。宁可多花三个月做分阶段过渡也不要冒着停摆风险去换取所谓的“纯粹架构”。