在电信网络优化领域,业务逻辑极其复杂:涉及海量的性能指标(KPI)、复杂的邻区关系、动态的告警规则以及跨专业的工单流转。传统的"贫血模型"加"事务脚本"模式往往导致代码耦合度高、维护困难。
本文将分享如何基于 领域驱动设计(DDD) 思想,结合 Spring Cloud Alibaba 微服务架构与 Vue 3 前端,构建一个高内聚、低耦合的电信网络优化平台。我们将重点探讨如何通过限界上下文(Bounded Context)划分微服务,以及如何利用富领域模型处理复杂的优化算法。
一、 战略设计:限界上下文的划分
在 DDD 中,首要任务是识别核心域、支撑域和通用域,并划定限界上下文。基于电信业务特性,我们将系统划分为以下核心微服务:
1. 资源中心上下文 (NetMgr Context)
- 职责:管理基站、小区、天线、工参等基础资源数据。
- 核心实体:Cell (小区), Site (站点), Antenna (天线)。
- 微服务对应 :
netmgr-service - 关键业务:资源的增删改查、版本管理、空间位置索引构建。
2. 性能分析上下文 (Perf Context)
- 职责:处理 MR(测量报告)、PM(性能管理)数据,进行覆盖评估、干扰分析。
- 核心实体 :Grid (栅格),
MrSample(采样点),CoverageScore(覆盖得分)。 - 微服务对应 :
perf-service - 关键业务:海量数据聚合、栅格化计算、KPI 指标公式动态解析。
3. 智能优化上下文 (Optimize Context)
- 职责:基于资源和性能数据,执行 PCI 规划、天线调整推荐、负载均衡参数优化。
- 核心实体 :
OptimizationTask(优化任务),PciSolution(PCI 方案),AdjustmentRecommendation(调整建议)。 - 微服务对应 :
optimize-service - 关键业务:图算法计算(PCI 冲突检测)、规则引擎匹配、方案生成。
4. 工单协同上下文 (JOM Context)
- 职责:将优化建议转化为可执行的工单,跟踪处理流程。
- 核心实体 :WorkOrder (工单),
WorkflowInstance(流程实例)。 - 微服务对应 :
jom-service - 关键业务:状态机流转、任务派发、闭环验证。
二、 战术设计:富领域模型实现
在微服务内部,我们拒绝"Getter/Setter"式的贫血模型,转而采用包含业务行为的富领域模型。
1. 实体与值对象的设计
以 性能分析上下文 中的"栅格覆盖评估"为例:
java
// Grid.java - 栅格实体
public class Grid {
private GridId id;
private GeoLocation location; // 值对象:经纬度
private List<MrSample> samples; // 聚合根内的子实体
private CoverageLevel coverageLevel; // 枚举:覆盖等级
// 领域行为:添加采样点并重新计算覆盖等级
public void addSample(MrSample sample) {
this.samples.add(sample);
this.recalculateCoverage();
}
private void recalculateCoverage() {
double avgRsrp = this.samples.stream()
.mapToDouble(MrSample::getRsrp)
.average()
.orElse(-140);
if (avgRsrp > -95) {
this.coverageLevel = CoverageLevel.EXCELLENT;
} else if (avgRsrp > -105) {
this.coverageLevel = CoverageLevel.GOOD;
} else {
this.coverageLevel = CoverageLevel.POOR;
}
}
}
亮点:
- 封装性 :
coverageLevel的计算逻辑隐藏在实体内部,外部只需调用addSample,无需关心具体算法。 - 不变性约束:确保栅格的状态始终与采样点数据保持一致。
2. 领域服务处理复杂逻辑
对于涉及多个实体的复杂操作,如 PCI 冲突检测,我们使用领域服务:
java
// PciOptimizationService.java - 领域服务
@Service
public class PciOptimizationService {
@Autowired
private CellRepository cellRepository;
// 领域行为:为指定区域的小区推荐无冲突 PCI
public PciSolution recommendPci(Area area) {
List<Cell> cells = cellRepository.findByArea(area);
// 构建邻区关系图
Graph<Cell> graph = buildNeighborGraph(cells);
// 应用图着色算法求解
Map<Cell, Integer> solution = graphColoringAlgorithm.solve(graph);
return new PciSolution(area, solution, LocalDateTime.now());
}
}
三、 基础设施层:Spring Cloud Alibaba 集成
1. 仓储模式 (Repository) 与数据持久化
通过 Repository 接口隔离领域层与基础设施层。底层使用 MyBatis Plus 或 JPA 实现。
java
// CellRepository.java - 仓储接口
public interface CellRepository {
Cell findById(CellId id);
List<Cell> findByArea(Area area);
void save(Cell cell);
}
2. 事件驱动架构 (EDA)
微服务之间通过 RocketMQ 进行解耦。当 perf-service 完成覆盖评估后,发布领域事件,optimize-service 订阅该事件触发优化任务。
java
// CoverageEvaluatedEvent.java - 领域事件
public class CoverageEvaluatedEvent {
private String gridId;
private CoverageLevel level;
private LocalDateTime eventTime;
}
// 在 Perf Service 中发布
rocketMQTemplate.syncSend("TOPIC_COVERAGE_EVENT", new CoverageEvaluatedEvent(...));
// 在 Optimize Service 中消费
@RocketMQMessageListener(topic = "TOPIC_COVERAGE_EVENT", consumerGroup = "GROUP_OPTIMIZE")
public class CoverageEventListener implements RocketMQListener<CoverageEvaluatedEvent> {
@Override
public void onMessage(CoverageEvaluatedEvent event) {
if (event.getLevel() == CoverageLevel.POOR) {
optimizationService.createTask(event.getGridId());
}
}
}
3. 分布式事务保障
在创建优化工单时,需要同时更新优化方案状态和创建工单记录。使用 Seata 的 AT 模式保证跨服务的数据一致性。
java
@GlobalTransactional
public void createOrderAndUpdateSolution(String solutionId, WorkOrder order) {
optimizeService.updateSolutionStatus(solutionId, Status.ORDER_CREATED);
jomService.createWorkOrder(order);
}
四、 前端表现层:Vue 3 与领域模型的映射
前端不再仅仅是数据的展示者,而是领域状态的反映者。
1. 组合式 API 封装领域逻辑
在 Vue 3 中,我们将领域逻辑封装在 Composables 中,保持组件的简洁。
java
// useOptimizationTask.ts
import { ref, computed } from 'vue';
import { getTaskDetails, executePciOptimization } from '@/api/optimize';
export function useOptimizationTask(taskId: string) {
const task = ref<any>(null);
const loading = ref(false);
const isPciConflict = computed(() => {
return task.value?.metrics?.pciConflicts > 0;
});
async function loadTask() {
loading.value = true;
try {
task.value = await getTaskDetails(taskId);
} finally {
loading.value = false;
}
}
async function runOptimization() {
await executePciOptimization(taskId);
await loadTask(); // 刷新状态
}
return { task, loading, isPciConflict, loadTask, runOptimization };
}
2. GIS 可视化与领域交互
利用 Leaflet 或 Mapbox 展示栅格覆盖情况。点击地图上的栅格,触发领域查询,展示详细的 MrSample 分布。
- 图层管理 :将 Grid 实体映射为地图上的 Polygon Layer,颜色根据
CoverageLevel动态渲染。 - 交互反馈 :用户在地图上框选区域,前端构建
Area值对象,调用后端PciOptimizationService生成方案。
五、 总结
通过 DDD 驱动的微服务建模,我们实现了:
- 业务与技术解耦:领域层纯 Java 实现,不依赖 Spring 注解,便于单元测试和业务逻辑复用。
- 高内聚微服务:每个微服务围绕一个限界上下文构建,边界清晰,避免了分布式单体。
- 弹性架构:基于 RocketMQ 的事件驱动机制,使得系统能够应对海量的性能数据冲击。
- 前后端一致:前端的 Composables 与后端的领域服务形成呼应,提升了全栈开发效率。
这种架构不仅适用于网络优化场景,也为其他复杂的电信运维业务(如故障定界、资源调度)提供了可复用的设计范式。
互动环节
💬 你们公司的DDD是怎么实现解耦的?遇到过哪些难题?欢迎在评论区分享!
⭐ 如果觉得这篇文章有帮助,欢迎点赞、收藏、转发!
🔔 关注我,下一篇将分享《基于 Nacos 的微服务配置中心与服务发现实战》
版权声明:本文为原创文章,转载请注明出处。商业转载请联系作者获得授权。
作者简介:系统架构 师,专注于电信大数据平台架构设计与运维。目前负责日均处理2亿条消息的ucp平台,擅长分布式系统设计、消息中间件运维和高可用架构