4. 服务边界原则:高内聚低耦合、单一职责、服务自治与数据所有权

在 DAG 任务调度系统中,服务边界的划定直接决定了系统的可维护性、可扩展性与运行稳定性。错误的边界会导致“牵一发而动全身”的连锁故障,而合理的边界则让每个服务成为独立演化的“微宇宙”。本节围绕四项核心原则展开,它们共同构成了服务拆分的黄金法则。

4.1 四项原则概览

原则 核心含义 在 DAG 调度中的体现
高内聚低耦合 模块内部紧密关联,模块间依赖最小化 调度引擎与任务执行器分离,通过事件而非 RPC 通信
单一职责 一个服务只负责一个明确的业务维度 DAG 解析服务只做图结构校验,不参与任务调度
服务自治 服务能独立部署、独立运行、独立演进 每个调度域拥有独立的队列与状态存储
数据所有权 数据归属明确,修改必须通过所属服务 任务实例状态只能由调度服务写入,其他服务只读
实践要点:四项原则并非孤立存在。数据所有权是服务自治的基石,单一职责是高内聚的必然结果。在 DAG 调度场景中,违背任意一条原则都会在后续迭代中产生“技术债利息”。

4.2 高内聚低耦合:从“网状调用”到“星型事件”

高内聚要求一个服务内部的类、函数、数据模型围绕同一个业务目标组织;低耦合要求服务之间仅通过稳定的接口或事件进行交互。在 DAG 调度中,最常见的反模式是“调度服务直接调用执行器 API 获取状态”。

高内聚低耦合:事件驱动 vs 直接调用 ❌ 高耦合:直接 RPC 调用 调度服务 执行器服务 getStatus() 调度服务 执行器服务 submitTask() 服务间网状依赖 一方变更,多方修改 ✅ 低耦合:事件驱动 调度服务 执行器服务 发布 TaskSubmitted 调度服务 执行器服务 发布 TaskCompleted 通过事件总线解耦 服务只关心事件类型,不关心发布者
内聚度评估指标:一个服务内,如果修改一个业务规则需要同时修改超过 3 个模块,说明内聚不足。在 DAG 调度中,建议将“图解析”“状态管理”“任务分发”拆为独立服务,每个服务内部变更影响范围控制在自身边界内。

4.3 单一职责:一个服务,一个业务维度

单一职责原则(SRP)在微服务架构中常被误解为“一个服务只做一件事”。更精确的表述是:一个服务只应对一个业务角色(Actor)或一个业务维度负责。在 DAG 调度中,典型的职责划分如下:

  • DAG 定义服务:负责图结构的 CRUD、版本管理、语法校验。不关心任务如何执行。
  • 调度编排服务:负责拓扑排序、依赖解析、触发策略。不关心任务具体逻辑。
  • 任务执行服务:负责实际的任务运行、资源分配、日志收集。不关心 DAG 结构。
  • 监控告警服务:负责指标采集、阈值判断、通知分发。不关心调度逻辑。
反模式 问题表现 正确做法
调度服务同时做图校验 图结构变更导致调度逻辑被迫修改 图校验下沉到 DAG 定义服务
执行器服务直接写数据库 数据所有权混乱,状态不一致 执行器只上报事件,由调度服务更新状态
监控服务内嵌调度策略 告警逻辑与调度逻辑耦合,难以单独测试 监控只消费事件,不参与决策

4.4 服务自治:独立部署与独立演进

服务自治要求每个服务拥有独立的数据库(或 Schema)、独立的部署单元、独立的版本号。在 DAG 调度中,自治性直接决定了团队能否并行开发。

服务自治:独立数据存储与部署边界 调度编排服务 v2.1.0 独立部署单元 调度状态库 (PostgreSQL) schema: scheduler 任务执行服务 v3.0.1 独立部署单元 执行日志库 (Elasticsearch) index: task-execution-* DAG 定义服务 v1.5.2 独立部署单元 图定义库 (PostgreSQL) schema: dag_definition 事件 事件 每个服务拥有独立数据库 Schema / 索引,版本独立演进 服务间仅通过事件或 API 契约通信,不共享数据存储
自治陷阱:不要为了“自治”而过度拆分。如果两个服务必须同步部署才能工作,说明它们实际上是一个逻辑服务。在 DAG 调度中,“调度编排”与“任务分发”如果共享同一个状态机,就应该合并为一个服务,直到有明确的独立演化需求。

4.5 数据所有权:谁生产,谁拥有,谁修改

数据所有权原则规定:每一份数据只能有一个“拥有者服务”(Owner Service),该服务负责数据的创建、更新和删除;其他服务只能通过 API 或事件间接读取数据。在 DAG 调度中,数据所有权划分如下:

数据实体 拥有者服务 其他服务访问方式
DAG 定义(节点、边、配置) DAG 定义服务 调度服务通过 API 读取
任务实例状态(pending/running/success/fail) 调度编排服务 执行器通过事件上报,监控服务通过事件消费
执行日志(stdout/stderr) 任务执行服务 监控服务通过 API 查询
调度历史与统计 调度编排服务 监控服务通过事件或 API 读取
数据所有权检查清单:
✅ 每个数据表/索引有且仅有一个服务写入。
✅ 其他服务读取数据时,必须通过拥有者服务的 API 或事件,不能直连数据库。
✅ 如果两个服务需要同时修改同一张表,说明数据所有权划分错误,需要重新拆分或引入事件溯源。
✅ 在 DAG 调度中,最常见的违规是“执行器服务直接修改任务状态表”,这会导致调度服务无法准确感知状态变更。

4.6 四项原则的协同作用

四项原则并非独立生效,而是形成一个相互增强的闭环:

  1. 单一职责 决定了服务的业务边界,确保每个服务只关注一个维度。
  2. 高内聚低耦合 决定了服务的内部组织与外部通信方式,确保边界内的元素紧密协作,边界外的依赖松散可控。
  3. 数据所有权 为服务自治提供了物质基础——拥有数据才能独立演进。
  4. 服务自治 是前三项原则的最终体现,一个自治的服务可以独立发布、独立扩缩容、独立故障恢复。

在 DAG 任务调度系统中,遵循这四项原则意味着:当业务需要增加一种新的任务类型时,只需要修改“任务执行服务”的内部逻辑,而“调度编排服务”和“DAG 定义服务”完全不受影响。反之,如果调度策略需要从“拓扑排序”改为“基于优先级的调度”,也只需要修改“调度编排服务”,其他服务保持稳定。

架构决策记录(ADR)建议:在项目初期,将四项原则写入 ADR 文档,并在每次服务拆分或合并时对照检查。例如:“本次拆分是否导致数据所有权模糊?”“新服务的职责是否跨越了多个业务维度?”这些问题的答案将直接决定架构的健康度。