← 返回题目列表

微服务的数据所有权应该如何划分?

困难 第 23 / 25 题 更新于 2026/10/02
微服务数据所有权数据库一致性
学习 AI 实战项目

简化版

数据应由负责对应业务不变量的服务独占写入,其他服务通过 API、事件或只读投影获取,而不是跨库直接改表。所有权包含 Schema、写规则、质量、迁移和故障恢复责任,不等于“这张表部署在哪台机器”。

详细版

先按限界上下文识别谁有权决定状态变化,例如订单服务拥有订单生命周期,库存服务拥有可售量。跨服务流程用命令与事件协调;报表和搜索建立派生副本,并标注新鲜度与可重建性。

共享数据库阶段可先做到账号和 Schema 隔离、禁止跨域写,再逐步迁移物理存储。跨域查询用组合 API、CQRS 投影或离线数仓,避免把 join 便利性换成发布耦合和不可审计写入。

完整版教学

一、所有权由不变量决定

谁能判断一条状态迁移是否合法,谁就应拥有该数据。库存不能由订单服务直接 UPDATE stock,因为库存服务才知道预占、释放、超卖和仓库维度规则;物理表名不是划分依据。

心法:一个事实只能有一个权威写入者,可以有很多受控的读取副本。

二、读与写要分开看

写:Caller -> Owner API/Command -> owner database
读:Caller -> Owner API | local projection | analytics store

禁止跨域写不代表所有读取都必须实时 RPC。高频展示可订阅事件维护本地投影,但必须接受延迟、处理重复并提供重建和对账。

三、为什么共享表危险

做法短期收益长期问题
跨服务直接写开发快绕过不变量与审计
跨库 Join查询方便Schema 发布互锁
复制数据本地读取快最终一致与修复成本
Owner API语义明确延迟与可用性依赖

当两个服务都修改同一列时,无法判断谁负责数据错误,回滚一个服务也可能破坏另一个服务的新格式。

四、跨服务事务怎么处理

订单创建与库存预占属于两个所有者,通常用 Saga:订单先进入 PENDING,库存成功后确认,失败则取消。它不提供瞬时原子性,而是用状态机、幂等命令和补偿把流程收敛。

若业务必须在一个事务里维护强不变量,可能说明边界切错,应考虑把相关状态放回同一服务,而非默认引入复杂分布式事务。

五、派生数据如何治理

搜索索引、缓存和报表是派生副本,不应反向成为权威来源。事件带 entityId、version 和 eventId;消费者只推进更高版本,并通过快照或重放恢复缺口。

例如投影延迟 30 秒,页面应明确允许旧读还是回源;不能一边宣称实时库存,一边只依赖分钟级同步。

六、共享数据库如何渐进迁移

先盘点表级读写者,为每个表指定 owner;再给非 owner 撤销写权限,以 API 替代写入。随后用 CDC/双读校验迁移数据,冻结旧写入口,切换读取,最后才删除旧表。

迁移需要按记录数、校验差异和最大同步 lag 验收。例如 1000 万行回填后不能只比总数,还要抽样字段并核对按主键分桶的校验和。

删除旧写权限前应先以审计模式记录越权调用,找出定时任务、脚本和报表等不在服务拓扑里的隐藏写入者。

数据 owner 还负责保留、删除和合规请求,不能把这些责任留给共享数据库管理员兜底。

七、常见误区与追问

  • 误区:一个服务一套数据库就是数据所有权。 仍可能通过共享账号跨库改写。
  • 误区:复制数据后可以任意修改。 派生副本应由权威事件或重建流程更新。
  • 误区:禁止 Join 就只能多次同步调用。 可用组合 API、投影和数仓。
  • 误区:Saga 能恢复强原子性。 中间状态可见,补偿也可能失败。
  • 追问:谁拥有客户地址? 取决于哪个上下文定义语义;订单快照与客户当前地址不是同一事实。
  • 追问:如何发现越权写? 独立账号、数据库审计、血缘扫描和权限测试。
  • 追问:Owner 故障时能否写副本? 不能随意双主,应按明确容灾与 fencing 切换。

八、加强记忆

数据所有权按“不变量—权威写入者—受控读取—派生副本—迁移责任”回答。核心不是数据库拆开,而是写权限和语义责任唯一;跨域流程接受明确的一致性模型,副本可重建可对账,共享库则按先禁写、再迁移、后清理演进。