diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/K8sDeploymentDTO.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/K8sDeploymentDTO.java index 65f8d6a3..5280affd 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/K8sDeploymentDTO.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/K8sDeploymentDTO.java @@ -49,6 +49,9 @@ public class K8sDeploymentDTO extends BaseDTO { @Schema(description = "K8S中的更新时间") private LocalDateTime k8sUpdateTime; + @Schema(description = "K8s资源版本号,用于增量同步") + private String resourceVersion; + @Schema(description = "YAML配置") private String yamlConfig; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/K8sDeployment.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/K8sDeployment.java index 3d232823..175e0b16 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/K8sDeployment.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/K8sDeployment.java @@ -60,4 +60,11 @@ public class K8sDeployment extends Entity { @Column(name = "yaml_config", columnDefinition = "TEXT") private String yamlConfig; + + /** + * K8s资源版本号,用于增量同步判断资源是否变化 + * 对应K8s的metadata.resourceVersion字段 + */ + @Column(name = "resource_version", length = 50) + private String resourceVersion; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IK8sServiceIntegration.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IK8sServiceIntegration.java index f18a0cb6..69243631 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IK8sServiceIntegration.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/IK8sServiceIntegration.java @@ -119,6 +119,21 @@ public interface IK8sServiceIntegration extends IExternalSystemIntegration { */ Integer calculateTotalRestartCount(ExternalSystem externalSystem, String namespace, String deploymentName); + /** + * 批量计算namespace下所有Deployment的重启次数 + * 性能优化:一次性查询所有Pod,在内存中按Deployment分组计算 + * + * @param externalSystem K8S系统配置 + * @param namespace 命名空间名称 + * @param deployments Deployment列表 + * @return Map + */ + java.util.Map batchCalculateRestartCounts( + ExternalSystem externalSystem, + String namespace, + List deployments + ); + /** * 获取系统类型 * diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/K8sServiceIntegrationImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/K8sServiceIntegrationImpl.java index d593d279..86f130e2 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/K8sServiceIntegrationImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/impl/K8sServiceIntegrationImpl.java @@ -229,6 +229,9 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp ); } + // 填充resourceVersion用于增量同步 + response.setResourceVersion(deployment.getMetadata().getResourceVersion()); + // 序列化为YAML配置 try { response.setYamlConfig(Yaml.dump(deployment)); @@ -303,6 +306,9 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp ); } + // 填充resourceVersion用于增量同步 + response.setResourceVersion(deployment.getMetadata().getResourceVersion()); + // 序列化为YAML配置 try { response.setYamlConfig(Yaml.dump(deployment)); @@ -763,6 +769,96 @@ public class K8sServiceIntegrationImpl extends BaseExternalSystemIntegration imp } } + /** + * 批量计算namespace下所有Deployment的重启次数 + * 性能优化:一次性查询所有Pod,在内存中按Deployment分组计算 + * + * @param externalSystem K8s集群 + * @param namespace 命名空间 + * @param deployments Deployment列表 + * @return Map + */ + @Override + public Map batchCalculateRestartCounts( + ExternalSystem externalSystem, + String namespace, + List deployments) { + + log.debug("批量计算Deployment重启次数,集群: {}, 命名空间: {}, Deployment数量: {}", + externalSystem.getName(), namespace, deployments.size()); + + Map restartCountMap = new java.util.HashMap<>(); + + try { + // 1. 一次性查询namespace下所有Pod + List allPods = listPods(externalSystem, namespace); + + if (allPods.isEmpty()) { + log.debug("命名空间 {} 下没有Pod", namespace); + return restartCountMap; + } + + // 2. 为每个Deployment计算重启次数 + for (K8sDeploymentResponse deployment : deployments) { + try { + Map selector = deployment.getSelector(); + if (selector == null || selector.isEmpty()) { + log.debug("Deployment {} 没有selector,跳过", deployment.getName()); + restartCountMap.put(deployment.getName(), 0); + continue; + } + + // 3. 在内存中过滤匹配该Deployment的Pod + int totalRestartCount = allPods.stream() + .filter(pod -> matchesSelector(pod.getLabels(), selector)) + .mapToInt(pod -> pod.getRestartCount() != null ? pod.getRestartCount() : 0) + .sum(); + + restartCountMap.put(deployment.getName(), totalRestartCount); + log.debug("Deployment {} 的重启次数: {}", deployment.getName(), totalRestartCount); + + } catch (Exception e) { + log.warn("计算Deployment {} 重启次数失败: {}", deployment.getName(), e.getMessage()); + restartCountMap.put(deployment.getName(), 0); + } + } + + log.debug("批量计算完成,成功计算 {} 个Deployment的重启次数", restartCountMap.size()); + return restartCountMap; + + } catch (Exception e) { + log.error("批量计算重启次数失败,集群: {}, 命名空间: {}, 错误: {}", + externalSystem.getName(), namespace, e.getMessage(), e); + // 失败时返回空Map,不影响同步流程 + return restartCountMap; + } + } + + /** + * 判断Pod的labels是否匹配Deployment的selector + * + * @param podLabels Pod的labels + * @param selector Deployment的selector + * @return 是否匹配 + */ + private boolean matchesSelector(Map podLabels, Map selector) { + if (podLabels == null || podLabels.isEmpty()) { + return false; + } + + // selector中的所有label都必须在Pod的labels中存在且值相等 + for (Map.Entry entry : selector.entrySet()) { + String selectorValue = entry.getValue(); + String podValue = podLabels.get(entry.getKey()); + + if (podValue == null || !podValue.equals(selectorValue)) { + return false; + } + } + + return true; + } + /** * 创建K8S ApiClient(内部实现,不使用缓存) * diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/K8sDeploymentResponse.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/K8sDeploymentResponse.java index 729be619..eefe1aa7 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/K8sDeploymentResponse.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/integration/response/K8sDeploymentResponse.java @@ -19,4 +19,10 @@ public class K8sDeploymentResponse { private LocalDateTime creationTimestamp; private LocalDateTime lastUpdateTime; private String yamlConfig; + + /** + * K8s资源版本号,用于增量同步判断资源是否变化 + * 每次资源被修改,resourceVersion都会改变 + */ + private String resourceVersion; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/K8sDeploymentServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/K8sDeploymentServiceImpl.java index 39f4df4c..fc0d0899 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/K8sDeploymentServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/K8sDeploymentServiceImpl.java @@ -83,19 +83,37 @@ public class K8sDeploymentServiceImpl extends BaseServiceImpl restartCountMap = k8sServiceIntegration.batchCalculateRestartCounts( + externalSystem, namespace.getNamespaceName(), deploymentResponses + ); + List deploymentsToSave = new ArrayList<>(); + int unchangedCount = 0; // 统计未变化的资源数量 // 1. 更新/新增K8S中存在的资源 for (K8sDeploymentResponse response : deploymentResponses) { K8sDeployment deployment = existingMap.get(response.getName()); + + // 增量同步优化:如果资源未变化(resourceVersion相同),跳过 + if (deployment != null && + response.getResourceVersion() != null && + response.getResourceVersion().equals(deployment.getResourceVersion())) { + unchangedCount++; + log.debug("Deployment {} 未变化,跳过更新", response.getName()); + continue; + } + if (deployment == null) { deployment = new K8sDeployment(); deployment.setExternalSystemId(externalSystem.getId()); deployment.setNamespaceId(namespace.getId()); deployment.setDeploymentName(response.getName()); + log.debug("新增Deployment: {}", response.getName()); } else { // 如果之前被软删除,恢复它 deployment.setDeleted(false); + log.debug("更新Deployment: {}", response.getName()); } deployment.setReplicas(response.getReplicas()); @@ -108,11 +126,12 @@ public class K8sDeploymentServiceImpl extends BaseServiceImpl