引言
制造执行系统(Manufacturing Execution System,MES)是连接企业计划层与车间执行层的核心系统,负责生产计划的执行、生产过程的监控、质量管理、设备管理等关键功能。本文以 PointLion Cloud MES 模块为例,深入探讨如何基于 Spring Cloud 微服务架构构建企业级 MES 系统。
相关链接:
- 🌐 官网:http://www.dianshixinxi.com/
- 📱 演示站:http://cloud.dianshixinxi.com:90/
- 🎨 Gitee:https://gitee.com/glorylion/JFinalOA
- 💻 GitCode:https://gitcode.com/Glory_Lion/pointlion-cloud
技术架构概览
核心技术栈
- Spring Boot 2.7.18: 微服务基础框架
- Spring Cloud 2021.0.9: 微服务治理
- Spring Cloud Alibaba 2021.0.6.2: 阿里云生态集成
- MyBatis Plus 3.5.10.1: ORM 框架
- Flowable 6.8.0: 工作流引擎
- Redisson 3.41.0: 分布式缓存
- XXL-Job 2.4.0: 分布式任务调度
- RocketMQ 2.3.1: 消息队列
- TDengine 3.3.3: 时序数据库
MES 系统功能架构
┌─────────────────────────────────────────────────────────┐
│ 前端展示层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ PC 端 │ │ 移动端 │ │ 大屏 │ │ 报表 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────┤
│ 应用服务层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 计划管理 │ │ 生产执行 │ │ 质量管理 │ │ 设备管理 │ │
│ │ 工艺管理 │ │ 仓储管理 │ │ 能源管理 │ │ 系统管理 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────┤
│ 业务中台层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 工作流 │ │ 规则引擎 │ │ 数据采集 │ │ 告警中心 │ │
│ │ 权限管理 │ │ 多租户 │ │ 数据权限 │ │ 审计日志 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────┤
│ 数据存储层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ MySQL │ │ Redis │ │TDengine │ │ RocketMQ│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────┤
│ 设备集成层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ PLC │ │ 传感器 │ │ 数控设备 │ │ AGV │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────┘
生产计划管理模块设计
生产工单管理核心实现
java
@Service
public class ProductionOrderService {
private final ProductionOrderMapper orderMapper;
private final WorkOrderRouter workOrderRouter;
private final RedissonClient redissonClient;
private final RocketMQTemplate rocketMQTemplate;
/**
* 创建生产工单
*/
@Transactional(rollbackFor = Exception.class)
public Long createProductionOrder(ProductionOrderCreateReq req) {
// 1. 参数校验
validateOrderCreateReq(req);
// 2. 构建工单实体
ProductionOrder order = buildProductionOrder(req);
// 3. 工单排程计算
scheduleWorkOrder(order);
// 4. 物料需求计算
calculateMaterialRequirement(order);
// 5. 保存工单
orderMapper.insert(order);
// 6. 发送工单创建消息
sendOrderCreateMessage(order);
return order.getId();
}
/**
* 工单排程计算
*/
private void scheduleWorkOrder(ProductionOrder order) {
// 1. 获取生产线信息
ProductionLine line = productionLineMapper.selectById(order.getLineId());
// 2. 获取工艺路线
ProcessRoute route = processRouteMapper.selectById(order.getRouteId());
// 3. 计算标准工时
List<ProcessStep> steps = route.getSteps();
long totalStandardTime = 0;
for (ProcessStep step : steps) {
totalStandardTime += step.getStandardTime() * order.getQuantity();
}
// 4. 计算排产时间
LocalDateTime startTime = calculateStartTime(order, line);
LocalDateTime endTime = startTime.plusSeconds(totalStandardTime);
// 5. 产能冲突检查
if (hasCapacityConflict(line.getId(), startTime, endTime)) {
throw new BusinessException("产线产能冲突,无法排产");
}
order.setPlanStartTime(startTime);
order.setPlanEndTime(endTime);
order.setStandardTime(totalStandardTime);
}
/**
* 物料需求计算(MRP)
*/
private void calculateMaterialRequirement(ProductionOrder order) {
// 1. 获取 BOM 清单
List<BomNode> bomList = bomMapper.selectByProductId(order.getProductId());
// 2. 计算物料需求
List<MaterialRequirement> requirements = new ArrayList<>();
for (BomNode bom : bomList) {
MaterialRequirement req = new MaterialRequirement();
req.setOrderId(order.getId());
req.setMaterialId(bom.getMaterialId());
req.setRequiredQuantity(bom.getQuantity() * order.getQuantity());
req.setUnit(bom.getUnit());
// 3. 检查库存
MaterialStock stock = materialStockMapper.selectByMaterialId(bom.getMaterialId());
if (stock != null && stock.getAvailableQuantity() >= req.getRequiredQuantity()) {
req.setSupplyStatus("SUFFICIENT");
} else {
req.setSupplyStatus("SHORTAGE");
req.setShortageQuantity(req.getRequiredQuantity() -
(stock != null ? stock.getAvailableQuantity() : 0));
}
requirements.add(req);
}
// 4. 保存物料需求
materialRequirementMapper.batchInsert(requirements);
}
/**
* 工单开工
*/
public void startWorkOrder(Long orderId) {
ProductionOrder order = orderMapper.selectById(orderId);
// 1. 状态检查
if (!"PENDING".equals(order.getStatus())) {
throw new BusinessException("工单状态不允许开工");
}
// 2. 前置条件检查
checkStartConditions(order);
// 3. 更新工单状态
order.setStatus("IN_PROGRESS");
order.setActualStartTime(LocalDateTime.now());
orderMapper.updateById(order);
// 4. 记录操作日志
operationLogService.record("WORK_ORDER_START", orderId,
"工单开工,操作人:" + SecurityUtils.getUsername());
// 5. 发送开工消息
rocketMQTemplate.syncSend("MES:WORK_ORDER_START", order);
// 6. 更新设备状态
updateEquipmentStatus(order);
}
/**
* 工单完工
*/
public void completeWorkOrder(Long orderId, WorkOrderCompleteReq req) {
ProductionOrder order = orderMapper.selectById(orderId);
// 1. 使用分布式锁保证并发安全
RLock lock = redissonClient.getLock("work_order:complete:" + orderId);
try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
try {
// 2. 状态检查
if (!"IN_PROGRESS".equals(order.getStatus())) {
throw new BusinessException("工单状态不允许完工");
}
// 3. 数量核对
if (req.getCompletedQuantity().compareTo(order.getQuantity()) > 0) {
throw new BusinessException("完工数量不能大于计划数量");
}
// 4. 质量检查
if (!qualityCheckService.checkOrderQuality(orderId, req.getQualityData())) {
throw new BusinessException("质量检查不合格,无法完工");
}
// 5. 更新工单状态
order.setStatus("COMPLETED");
order.setActualEndTime(LocalDateTime.now());
order.setCompletedQuantity(req.getCompletedQuantity());
order.setQualifiedQuantity(req.getQualifiedQuantity());
order.setDefectiveQuantity(req.getDefectiveQuantity());
order.setCompleteReason(req.getReason());
orderMapper.updateById(order);
// 6. 库存更新
inventoryService.finishWorkOrder(order);
// 7. 物料扣减
materialService.deductMaterial(order);
// 8. 记录操作日志
operationLogService.record("WORK_ORDER_COMPLETE", orderId,
"工单完工,操作人:" + SecurityUtils.getUsername());
// 9. 发送完工消息
rocketMQTemplate.syncSend("MES:WORK_ORDER_COMPLETE", order);
} finally {
lock.unlock();
}
} else {
throw new BusinessException("系统繁忙,请稍后重试");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new BusinessException("系统异常");
}
}
}
生产执行管理模块设计
工序作业管理
java
@Service
public class ProcessOperationService {
private final ProcessOperationMapper operationMapper;
private final WorkStationService workStationService;
private final EquipmentService equipmentService;
private final RedissonClient redissonClient;
/**
* 工序开工
*/
@Transactional(rollbackFor = Exception.class)
public void startProcessOperation(ProcessOperationStartReq req) {
// 1. 获取工序信息
ProcessOperation operation = operationMapper.selectById(req.getOperationId());
if (operation == null) {
throw new BusinessException("工序不存在");
}
// 2. 状态检查
if (!"PENDING".equals(operation.getStatus())) {
throw new BusinessException("工序状态不允许开工");
}
// 3. 工位检查
WorkStation station = workStationService.getById(req.getStationId());
if (station == null || !"ACTIVE".equals(station.getStatus())) {
throw new BusinessException("工位不可用");
}
// 4. 设备检查
if (req.getEquipmentId() != null) {
Equipment equipment = equipmentService.getById(req.getEquipmentId());
if (equipment == null || !"RUNNING".equals(equipment.getStatus())) {
throw new BusinessException("设备不可用");
}
}
// 5. 人员资质检查
if (!checkOperatorQualification(req.getOperatorId(), operation.getProcessId())) {
throw new BusinessException("操作人员无此工序资质");
}
// 6. 更新工序状态
operation.setStatus("IN_PROGRESS");
operation.setStationId(req.getStationId());
operation.setEquipmentId(req.getEquipmentId());
operation.setOperatorId(req.getOperatorId());
operation.setActualStartTime(LocalDateTime.now());
operationMapper.updateById(operation);
// 7. 记录工序开工事件
recordOperationEvent(operation, "START");
// 8. 更新工位状态
workStationService.updateStatus(req.getStationId(), "BUSY");
}
/**
* 工序报工
*/
@Transactional(rollbackFor = Exception.class)
public void reportProcessOperation(ProcessOperationReportReq req) {
// 1. 获取工序信息
ProcessOperation operation = operationMapper.selectById(req.getOperationId());
if (operation == null) {
throw new BusinessException("工序不存在");
}
// 2. 状态检查
if (!"IN_PROGRESS".equals(operation.getStatus())) {
throw new BusinessException("工序状态不允许报工");
}
// 3. 数量校验
if (req.getReportedQuantity().compareTo(BigDecimal.ZERO) <= 0) {
throw new BusinessException("报工数量必须大于零");
}
// 4. 使用分布式锁防止重复报工
RLock lock = redissonClient.getLock("process:report:" + req.getOperationId());
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
try {
// 5. 创建报工记录
ProcessReport report = new ProcessReport();
report.setOperationId(req.getOperationId());
report.setOrderId(operation.getOrderId());
report.setProcessId(operation.getProcessId());
report.setReportedQuantity(req.getReportedQuantity());
report.setQualifiedQuantity(req.getQualifiedQuantity());
report.setDefectiveQuantity(req.getDefectiveQuantity());
report.setOperatorId(req.getOperatorId());
report.setReportTime(LocalDateTime.now());
report.setRemark(req.getRemark());
processReportMapper.insert(report);
// 6. 更新工序累计数量
operation.setReportedQuantity(operation.getReportedQuantity()
.add(req.getReportedQuantity()));
operation.setQualifiedQuantity(operation.getQualifiedQuantity()
.add(req.getQualifiedQuantity()));
operation.setDefectiveQuantity(operation.getDefectiveQuantity()
.add(req.getDefectiveQuantity()));
// 7. 检查工序是否完成
if (operation.getReportedQuantity().compareTo(operation.getPlanQuantity()) >= 0) {
operation.setStatus("COMPLETED");
operation.setActualEndTime(LocalDateTime.now());
// 释放工位
workStationService.updateStatus(operation.getStationId(), "IDLE");
}
operationMapper.updateById(operation);
// 8. 记录报工事件
recordOperationEvent(operation, "REPORT");
// 9. 触发下游工序检查
checkNextOperation(operation);
} finally {
lock.unlock();
}
} else {
throw new BusinessException("系统繁忙,请稍后重试");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new BusinessException("系统异常");
}
}
/**
* 工序暂停/恢复
*/
public void pauseProcessOperation(Long operationId, boolean pause) {
ProcessOperation operation = operationMapper.selectById(operationId);
if (operation == null) {
throw new BusinessException("工序不存在");
}
if ("IN_PROGRESS".equals(operation.getStatus())) {
operation.setStatus(pause ? "PAUSED" : "IN_PROGRESS");
operationMapper.updateById(operation);
// 记录暂停/恢复事件
recordOperationEvent(operation, pause ? "PAUSE" : "RESUME");
} else {
throw new BusinessException("工序状态不允许此操作");
}
}
}
质量管理模块设计
质量检验管理
java
@Service
public class QualityInspectionService {
private final QualityInspectionMapper inspectionMapper;
private final InspectionStandardService standardService;
private final InspectionTaskService taskService;
/**
* 创建检验任务
*/
@Transactional(rollbackFor = Exception.class)
public Long createInspectionTask(InspectionTaskCreateReq req) {
// 1. 获取检验标准
InspectionStandard standard = standardService.getById(req.getStandardId());
if (standard == null) {
throw new BusinessException("检验标准不存在");
}
// 2. 生成检验任务
InspectionTask task = new InspectionTask();
task.setTaskNo(generateTaskNo());
task.setStandardId(req.getStandardId());
task.setOrderId(req.getOrderId());
task.setBatchNo(req.getBatchNo());
task.setSampleType(req.getSampleType());
task.setSampleQuantity(req.getSampleQuantity());
task.setStatus("PENDING");
task.setPlanTime(LocalDateTime.now().plusHours(standard.getResponseTime()));
task.setCreateTime(LocalDateTime.now());
inspectionMapper.insert(task);
// 3. 生成检验项目
generateInspectionItems(task, standard);
// 4. 分配检验员
assignInspector(task);
return task.getId();
}
/**
* 执行质量检验
*/
@Transactional(rollbackFor = Exception.class)
public void executeInspection(InspectionExecuteReq req) {
// 1. 获取检验任务
InspectionTask task = inspectionMapper.selectById(req.getTaskId());
if (task == null) {
throw new BusinessException("检验任务不存在");
}
// 2. 状态检查
if (!"ASSIGNED".equals(task.getStatus())) {
throw new BusinessException("检验任务状态不允许执行");
}
// 3. 获取检验项目
List<InspectionItem> items = inspectionItemMapper.selectByTaskId(req.getTaskId());
// 4. 处理检验结果
boolean allPassed = true;
for (InspectionItemResult result : req.getResults()) {
InspectionItem item = findItem(items, result.getItemId());
if (item == null) {
continue;
}
// 判断是否合格
boolean passed = judgeItemResult(item, result);
// 保存检验结果
InspectionItemRecord record = new InspectionItemRecord();
record.setTaskId(req.getTaskId());
record.setItemId(result.getItemId());
record.setInspectionValue(result.getValue());
record.setPassed(passed);
record.setInspectorId(req.getInspectorId());
record.setInspectionTime(LocalDateTime.now());
record.setRemark(result.getRemark());
inspectionItemRecordMapper.insert(record);
if (!passed) {
allPassed = false;
}
}
// 5. 更新任务状态
task.setStatus("COMPLETED");
task.setInspectorId(req.getInspectorId());
task.setInspectionTime(LocalDateTime.now());
task.setResult(allPassed ? "PASSED" : "FAILED");
task.setRemark(req.getRemark());
inspectionMapper.updateById(task);
// 6. 处理不合格品
if (!allPassed) {
handleDefectiveProduct(task);
}
}
/**
* 判断检验项结果
*/
private boolean judgeItemResult(InspectionItem item, InspectionItemResult result) {
switch (item.getJudgeType()) {
case "VALUE":
// 数值判断
return judgeValueResult(item, result.getValue());
case "VISUAL":
// 目视判断
return "PASS".equalsIgnoreCase(result.getValue());
case "FUNCTIONAL":
// 功能测试判断
return judgeFunctionalResult(item, result);
default:
return true;
}
}
/**
* 数值判断
*/
private boolean judgeValueResult(InspectionItem item, String valueStr) {
try {
double value = Double.parseDouble(valueStr);
// 获取检验规格
InspectionSpec spec = item.getSpec();
if (spec == null) {
return true;
}
// 判断是否在规格范围内
switch (spec.getSpecType()) {
case "RANGE":
return value >= spec.getMinValue() && value <= spec.getMaxValue();
case "MAX":
return value <= spec.getMaxValue();
case "MIN":
return value >= spec.getMinValue();
case "TARGET":
double tolerance = spec.getTolerance();
double target = spec.getTargetValue();
return Math.abs(value - target) <= tolerance;
default:
return true;
}
} catch (NumberFormatException e) {
return false;
}
}
/**
* 处理不合格品
*/
private void handleDefectiveProduct(InspectionTask task) {
// 1. 创建不合格品记录
DefectiveProduct defective = new DefectiveProduct();
defective.setTaskId(task.getId());
defective.setOrderId(task.getOrderId());
defective.setBatchNo(task.getBatchNo());
defective.setDefectType("QUALITY");
defective.setStatus("PENDING");
defective.setCreateTime(LocalDateTime.now());
defectiveProductMapper.insert(defective);
// 2. 发起不合格品处理流程
startDefectiveHandlingProcess(defective);
// 3. 发送告警通知
sendDefectiveAlarm(defective);
}
}
设备管理模块设计
设备监控与状态管理
java
@Service
public class EquipmentMonitorService {
private final EquipmentMapper equipmentMapper;
private final EquipmentStatusCache statusCache;
private final RedissonClient redissonClient;
private final TDengineTemplate tdengineTemplate;
/**
* 更新设备状态
*/
public void updateEquipmentStatus(String equipmentCode, EquipmentStatus status) {
// 1. 更新 Redis 缓存
String cacheKey = "equipment:status:" + equipmentCode;
RBucket<String> bucket = redissonClient.getBucket(cacheKey);
bucket.set(status.name(), 30, TimeUnit.MINUTES);
// 2. 更新数据库
equipmentMapper.updateStatus(equipmentCode, status.name());
// 3. 记录状态变更日志
recordStatusChange(equipmentCode, status);
// 4. 发布状态变更事件
publishStatusChangeEvent(equipmentCode, status);
}
/**
* 采集设备实时数据
*/
@Async
public void collectEquipmentData(EquipmentData data) {
// 1. 数据校验
if (!validateEquipmentData(data)) {
return;
}
// 2. 写入时序数据库
String sql = String.format(
"INSERT INTO %s USING equipment_data TAGS (?,?) VALUES (?,?,?)",
"eq_" + data.getEquipmentCode()
);
tdengineTemplate.update(sql,
data.getEquipmentCode(),
data.getEquipmentType(),
data.getTimestamp(),
data.getDataKey(),
data.getDataValue()
);
// 3. 更新实时数据缓存
updateRealtimeDataCache(data);
// 4. 检查告警阈值
checkAlarmThreshold(data);
}
/**
* 检查告警阈值
*/
private void checkAlarmThreshold(EquipmentData data) {
// 1. 获取告警规则
List<AlarmRule> rules = alarmRuleMapper.selectByEquipmentCode(
data.getEquipmentCode(), data.getDataKey()
);
// 2. 检查是否触发告警
for (AlarmRule rule : rules) {
if (checkRuleTriggered(rule, data)) {
// 创建告警
createAlarm(rule, data);
}
}
}
/**
* 检查规则是否触发
*/
private boolean checkRuleTriggered(AlarmRule rule, EquipmentData data) {
try {
double value = Double.parseDouble(data.getDataValue());
switch (rule.getCompareType()) {
case "GT":
return value > rule.getThreshold();
case "LT":
return value < rule.getThreshold();
case "GTE":
return value >= rule.getThreshold();
case "LTE":
return value <= rule.getThreshold();
case "EQ":
return value == rule.getThreshold();
case "NE":
return value != rule.getThreshold();
default:
return false;
}
} catch (NumberFormatException e) {
return false;
}
}
/**
* 设备 OEE 计算
*/
public OEEResult calculateOEE(String equipmentCode, LocalDateTime start, LocalDateTime end) {
// 1. 获取计划生产时间
long plannedTime = getPlannedProductionTime(equipmentCode, start, end);
// 2. 获取实际运行时间
long actualTime = getActualRunningTime(equipmentCode, start, end);
// 3. 计算可用率
double availabilityRate = plannedTime > 0 ? (double) actualTime / plannedTime : 0;
// 4. 获取标准产量和实际产量
long standardOutput = getStandardOutput(equipmentCode, start, end);
long actualOutput = getActualOutput(equipmentCode, start, end);
// 5. 计算性能率
double performanceRate = plannedTime > 0 ?
(double) actualOutput / standardOutput : 0;
// 6. 获取合格品数量和总数量
long qualifiedCount = getQualifiedCount(equipmentCode, start, end);
long totalCount = getTotalCount(equipmentCode, start, end);
// 7. 计算质量率
double qualityRate = totalCount > 0 ? (double) qualifiedCount / totalCount : 0;
// 8. 计算 OEE
double oee = availabilityRate * performanceRate * qualityRate;
// 9. 构建结果
OEEResult result = new OEEResult();
result.setEquipmentCode(equipmentCode);
result.setStartTime(start);
result.setEndTime(end);
result.setAvailabilityRate(availabilityRate);
result.setPerformanceRate(performanceRate);
result.setQualityRate(qualityRate);
result.setOee(oee);
return result;
}
}
数据采集与实时监控
基于 XXL-Job 的定时数据采集
java
@Component
@JobHandler(name = "mesDataCollectionJob")
public class MESDataCollectionJob extends IJobHandler {
@Autowired
private DataCollectionService dataCollectionService;
@Override
public void execute() throws Exception {
// 1. 获取所有激活的数据采集任务
List<DataCollectionTask> tasks = dataCollectionService.getActiveTasks();
// 2. 并行执行采集任务
tasks.parallelStream().forEach(task -> {
try {
dataCollectionService.executeTask(task);
} catch (Exception e) {
log.error("数据采集任务执行失败: {}", task, e);
}
});
}
}
实时数据监控大屏
java
@RestController
@RequestMapping("/mes/monitor")
public class MESMonitorController {
@Autowired
private ProductionMonitorService productionMonitorService;
/**
* 获取生产实时数据
*/
@GetMapping("/production/realtime")
public CommonResult<ProductionRealtimeData> getProductionRealtime(
@RequestParam Long lineId) {
ProductionRealtimeData data = productionMonitorService
.getRealtimeData(lineId);
return CommonResult.success(data);
}
/**
* 获取设备运行状态
*/
@GetMapping("/equipment/status")
public CommonResult<List<EquipmentStatusData>> getEquipmentStatus(
@RequestParam(required = false) String lineId) {
List<EquipmentStatusData> data = productionMonitorService
.getEquipmentStatus(lineId);
return CommonResult.success(data);
}
/**
* 获取生产计划完成情况
*/
@GetMapping("/plan/progress")
public CommonResult<List<PlanProgressData>> getPlanProgress(
@RequestParam String date) {
List<PlanProgressData> data = productionMonitorService
.getPlanProgress(date);
return CommonResult.success(data);
}
/**
* 获取质量统计信息
*/
@GetMapping("/quality/statistics")
public CommonResult<QualityStatisticsData> getQualityStatistics(
@RequestParam String date,
@RequestParam(required = false) String lineId) {
QualityStatisticsData data = productionMonitorService
.getQualityStatistics(date, lineId);
return CommonResult.success(data);
}
}
总结
本文介绍了基于 Spring Cloud 微服务架构构建企业级 MES 系统的设计与实现。通过生产计划管理、生产执行管理、质量管理、设备管理等核心模块的设计,展示了如何构建一个完整的制造执行系统。
关键技术要点:
- 微服务架构: 基于 Spring Cloud 实现服务拆分与治理
- 工作流引擎: 使用 Flowable 实现复杂的业务流程管理
- 分布式调度: 使用 XXL-Job 实现定时任务调度
- 消息驱动: 使用 RocketMQ 实现服务间异步通信
- 时序数据存储: 使用 TDengine 处理海量设备数据
- 分布式协调: 使用 Redisson 实现分布式锁和缓存
- 数据权限: 基于多租户和数据权限实现数据隔离