微服务架构下的数据库治理——从“一个库所有人用“到“独立自治“

📅 2026/7/31 9:44:15
微服务架构下的数据库治理——从“一个库所有人用“到“独立自治“
喜欢把枯燥的技术文档变成手把手教程不讲空话只讲怎么连、怎么写、怎么优化。微服务拆分最难的往往不是服务本身是数据库。代码拆成十个服务很简单把 controller 移过去、改个包名、跑通就行。但数据库怎么拆每个服务一个独立库还是共享跨库 JOIN 怎么做一个服务改了表结构其他五个服务跟着报错这怎么解今天把微服务架构下的数据库治理问题讲透。从拆分策略到跨库一致性到版本管理跟着我走一遍你也能搭一套合理的微服务数据库架构。一、共享库的代价——为什么不能一个库所有人用先说说最常见的起步方式微服务拆了数据库不动。五个服务连同一个库大家共用同一套表。刚起步的时候没问题。三个服务、几十个表、两个开发共享一个库效率最高。但规模上来之后问题就来了问题一schema 变更互相影响。服务 A 给 orders 表加了一个字段服务 B 的 ORM 映射没更新直接报错。更麻烦的是服务 C 依赖那个字段做查询但服务 A 还没发布导致服务 C 上线后查不到数据。问题二连接数爆炸。每个服务都有自己的连接池假设每个服务 20 个连接10 个服务就是 200 个连接。数据库的 max_connections 是有限的每个连接还占用内存。服务越多连接压力越大。问题三性能干扰。服务 A 跑了一个大报表查询把数据库 CPU 打满了。服务 B 的在线交易跟着变慢——明明两个服务完全无关却因为共享数据库互相拖累。问题四权限无法隔离。服务 A 只需要读用户表但因为连的是同一个库它理论上可以访问所有表。权限粒度做不到服务级别。关键判断点如果你的服务数量超过 5 个、开发团队超过两个、schema 变更开始出现跨服务影响共享库的模式就该结束了。二、数据库拆分策略——按什么规则拆共享库不行那就拆。但怎么拆有三种主流策略。策略 A一个服务一个数据库每个微服务拥有自己独立的数据库实例。服务之间不共享任何数据只能通过 API 交互。优点隔离性最好。schema 变更互不影响、连接数可控、权限天然隔离。缺点跨服务查询困难。原来一个 JOIN 能搞定的事现在得调 API。数据库实例多运维成本上升。适合服务边界清晰、跨服务查询少的场景。策略 B按业务域拆分不是每个服务一个库而是按业务域分组。比如订单域包含订单服务、支付服务、物流服务它们共享一个订单域数据库。用户域包含用户服务、权限服务、消息服务共享一个用户域数据库。域与域之间不共享数据。优点平衡了隔离性和复杂度。域内服务可以共享数据库跨域服务通过 API 或数据同步交互。缺点域边界需要仔细设计。分错了域内服务还是会有 schema 冲突。适合服务数量多、但业务域清晰的场景。策略 C核心/边缘分离核心业务交易、支付、用户用独立数据库边缘业务日志、统计、通知共享一个数据库。核心严格隔离边缘适度共享。优点资源集中在核心系统边缘系统降低运维成本。缺点边缘服务之间仍有共享库的问题只是范围缩小了。适合团队规模有限、但核心系统对稳定性和性能要求高的场景。三、跨库数据一致性——不能 JOIN 了怎么保证数据对得上拆了库之后最大的挑战来了原来在一个库里用事务 JOIN 就能保证一致性的操作现在跨库了怎么做方案一Saga 模式——用业务补偿代替技术回滚Saga 的思路是把一个跨服务的长事务拆成多个本地短事务每个服务执行自己的事务如果中间某一步失败了就依次执行前面各步的补偿操作来撤销。举例电商下单流程涉及三个服务订单服务创建订单、库存服务扣减库存、支付服务扣款。第一步订单服务创建订单状态为待支付。第二步库存服务扣减库存。如果库存不足调用订单服务的补偿接口把订单状态改为已取消。第三步支付服务扣款。如果扣款失败调用库存服务的补偿接口恢复库存再调用订单服务的补偿接口取消订单。关键每个服务必须实现正向操作和补偿操作。补偿操作不是删除数据是把状态恢复到操作前。方案二TCC 模式——Try-Confirm-CancelTCC 比 Saga 更精细分三个阶段Try各服务预留资源比如库存服务冻结库存支付服务冻结额度但不真正提交。Confirm所有服务 Try 都成功后统一 Confirm真正提交。Cancel任一服务 Try 失败统一 Cancel释放预留资源。TCC vs Saga 的区别TCC 在 Try 阶段就锁定了资源保证了更强的隔离性Saga 的正向操作直接提交靠补偿回滚隔离性弱但实现简单。方案三本地消息表——最朴素但最可靠本地消息表的思路是每个服务在执行本地事务的同时往自己的消息表里插入一条记录。这条记录记录了我做了什么需要通知谁。然后有一个独立的消费者扫描消息表把消息推给目标服务。举例订单服务创建订单后在本地事务中同时插入一条消息记录{target: inventory, action: deduct, orderId: xxx}。消费者扫描到这条消息调用库存服务扣减库存。库存服务处理完后回传确认。如果库存服务处理失败消息状态保持待处理消费者会重试。为什么可靠消息的插入和业务操作在同一个本地事务中要么都成功要么都失败不会出现业务做了但消息没发的情况。为什么不推荐用分布式事务框架直接上 2PC两阶段提交在高并发场景下性能很差。持有锁的时间长、容易死锁、一个节点慢全体等。生产环境里2PC 用得很少。四、跨库查询怎么解决——不 JOIN 了数据怎么拼拆了库之后原来一条 SQL 就能搞定的跨表查询现在数据分散在不同库里了。怎么办方法一API 聚合查询时应用层分别调用各服务的 API拿到数据后在内存中拼接。优点实现简单不需要额外的数据同步。缺点多次网络调用延迟高。不适合需要频繁跨库查询的场景。适合低频查询、数据量小的场景。方法二CDC 数据同步 宽表用 CDCChange Data Capture工具实时捕获各服务的数据库变更同步到一个集中的查询库或宽表中。查询时只读这个集中库不需要跨库。优点查询性能好一次查询搞定。缺点需要维护 CDC 管道数据有延迟通常秒级。适合高频查询、报表类场景。方法三CQRS 读写分离写操作走各服务的独立数据库读操作走一个专门构建的查询库读模型。读模型通过事件驱动从各服务同步数据。优点读写彻底解耦读模型可以按查询需求自由设计。缺点架构复杂度最高需要完整的事件体系。适合读写比例悬殊、查询模式复杂的场景。五、数据库版本管理——每个服务独立演进怎么管拆了库之后每个服务有自己的数据库 schema。版本管理怎么做不能靠手动跑 SQL 脚本。工具选择Flyway基于 SQL 脚本的版本管理工具。每个变更是一个独立的 SQL 文件按版本号顺序执行。简单、可靠、学习成本低。Liquibase基于 XML/YAML/JSON 的变更日志管理。支持回滚脚本、差异生成。功能更强但学习成本高。微服务环境下的实践原则一每个服务自带数据库版本管理。服务启动时自动检查并执行未应用的变更脚本。不要把版本管理放到 CI/CD 流水线里做它应该是服务的一部分。原则二变更脚本只改自己服务的库。跨库变更通过数据同步或 API 协调不要在一个服务的变更脚本里改其他服务的表。原则三向后兼容。改 schema 时保证旧版本服务也能正常运行。比如加字段而不是改字段旧代码不会用到新字段所以不会报错。# Flyway 脚本命名规范 V1__create_orders.sql -- 创建订单表 V2__add_order_status.sql -- 增加订单状态字段 V3__create_order_items.sql -- 创建订单项表注意不要跳过版本号。Flyway 严格按版本号顺序执行跳过会导致版本不一致。六、公共数据的处理——用户、权限、字典表放哪有些数据是多个服务都需要用的用户信息、权限数据、字典/配置表。放哪个库方案一归口服务管理。用户数据归用户服务管权限数据归权限服务管。其他服务需要这些数据时通过 API 查询或 CDC 同步。方案二独立基础库。建一个基础数据库存放用户、权限、字典等公共服务数据。所有服务只读不写这个库写操作只能通过对应的管理服务。方案三各服务各自冗余。每个服务缓存自己需要的公共数据比如订单服务缓存用户昵称。通过消息机制保持缓存更新。适合读多写少的场景。我的建议用户和权限用方案一归口服务管理字典和配置用方案三各服务缓存。基础库方案增加了架构复杂度除非你的公共数据量很大。对比五种微服务数据库模式模式隔离性复杂度跨库查询适用阶段共享库低低一个 JOIN 搞定起步期 5 服务一服务一库高中API 聚合或 CDC成长期5-20 服务按域拆分中中域内 JOIN域间 CDC成熟期20 服务核心/边缘分离核心高、边缘低低-中核心库独立边缘可 JOIN团队规模有限CQRS 读写分离高高读模型一次查询读写比例悬殊决策框架按三个维度选择拆分策略维度一服务数量 5 个共享库即可先跑起来再说5-20 个一服务一库或按域拆分20 个按域拆分 域内共享维度二团队规模1-2 个开发团队核心/边缘分离降低运维负担3-5 个开发团队按域拆分每个团队负责一个域5 个团队一服务一库 CQRS维度三数据耦合度低服务间数据交互少一服务一库中有跨服务查询但不频繁按域拆分 域内共享高频繁跨服务查询CDC 宽表 CQRS 读模型微服务数据库治理检查清单拆分前评估梳理现有共享库的表标记哪些表被哪些服务使用识别跨服务的数据依赖关系A 服务写、B 服务读的表评估拆分后的跨库查询需求提前规划解决方案拆分后验证确认每个服务的数据库连接独立连接数在合理范围确认 schema 变更不会影响到其他服务确认跨库一致性方案Saga/TCC/本地消息表的补偿逻辑正确确认公共数据的归口管理方案已落实日常运维每个服务的数据库版本管理脚本已纳入代码仓库跨库数据同步的延迟在监控范围内CDC 延迟 5 秒定期演练补偿逻辑确保异常场景下能正确回滚新增服务时按拆分策略分配数据库资源不要走共享库的老路总结微服务数据库治理的核心就三条拆要拆到位——按服务或按业务域隔离不要共享库走到黑。一致性选对方案——不要一上来就搞 2PCSaga 或本地消息表在大部分场景下够用。版本管理自动化——每个服务自带数据库版本管理变更脚本向后兼容。实际项目里我见过最惨的情况是 15 个服务共享一个库改一个字段要拉五个团队开会。拆了之后每个团队管自己的库效率高了很多跨库数据用 CDC 同步延迟在秒级可接受。这条路每个做微服务的团队都要走早点规划比后期重构好。后续我会继续分享分布式事务落地实战、CDC 数据同步方案对比这些话题跟着我一篇篇学数据库这块就没问题了。有问题评论区见。喜欢把枯燥的技术文档变成手把手教程。关注我数据库这块我们一起搞定。