diff --git a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/autoscaling/HiveClusterAutoscaler.java b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/autoscaling/HiveClusterAutoscaler.java index f6016043fc63..5be325e40853 100644 --- a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/autoscaling/HiveClusterAutoscaler.java +++ b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/autoscaling/HiveClusterAutoscaler.java @@ -81,6 +81,25 @@ public static void setManagedReplicas(String namespace, String clusterName, MANAGED_REPLICAS.put(cacheKey(namespace, clusterName, component), replicas); } + /** + * Removes the autoscaler-managed replica count for a component. Used when autoscaling is disabled so + * a pre-existing in-memory scale decision if any is cleared up. + */ + public static void cleanupManagedReplicas(String namespace, String clusterName, String component) { + MANAGED_REPLICAS.remove(cacheKey(namespace, clusterName, component)); + } + + /** + * Clears all in-memory autoscaling state for a component when autoscaling is disabled. + */ + public void resetComponentAutoscalingState(String namespace, String clusterName, String component) { + String key = cacheKey(namespace, clusterName, component); + MANAGED_REPLICAS.remove(key); + pendingScaleDowns.remove(key); + autoscalers.remove(key); + lastScaleTimes.remove(key); + } + private record PendingScaleDown(int targetReplicas, Instant annotatedAt, List podsToDeregister) {} private final BackgroundMetricsScraper bgScraper; diff --git a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java index 557ebe99d545..ccb1390c90bd 100644 --- a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java +++ b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java @@ -162,6 +162,15 @@ public UpdateControl reconcile(HiveCluster resource, Context reconcile(HiveCluster resource, Context entry : eval.patches().entrySet()) { patchReplicas(client, resource, entry.getKey(), entry.getValue()); @@ -553,6 +561,42 @@ private HiveClusterAutoscaler getOrCreateAutoscaler(KubernetesClient client) { return autoscaler; } + /** + * Clears autoscaling state for components with autoscaling disabled in spec. + */ + private static void resetAutoscalingStateForDisabledComponents(HiveCluster resource, HiveClusterAutoscaler scaler) { + HiveClusterSpec spec = resource.getSpec(); + String ns = resource.getMetadata().getNamespace(); + String clusterName = resource.getMetadata().getName(); + + if (!spec.hiveServer2().autoscaling().isEnabled()) { + clearAutoscalingState(scaler, ns, clusterName, ConfigUtils.COMPONENT_HIVESERVER2); + } + if (spec.metastore().isEnabled() && !spec.metastore().autoscaling().isEnabled()) { + clearAutoscalingState(scaler, ns, clusterName, ConfigUtils.COMPONENT_METASTORE); + } + for (var llap : spec.llapClusters()) { + if (!llap.isEnabled()) { + continue; + } + if (!llap.autoscaling().isEnabled()) { + clearAutoscalingState(scaler, ns, clusterName, ConfigUtils.llapComponentKey(llap.name())); + } + if (spec.tezAm().isEnabled() && !llap.tezAm().autoscaling().isEnabled()) { + clearAutoscalingState(scaler, ns, clusterName, ConfigUtils.tezAmComponentKey(llap.name())); + } + } + } + + private static void clearAutoscalingState(HiveClusterAutoscaler scaler, + String namespace, String clusterName, String component) { + if (scaler != null) { + scaler.resetComponentAutoscalingState(namespace, clusterName, component); + } else { + HiveClusterAutoscaler.cleanupManagedReplicas(namespace, clusterName, component); + } + } + private static boolean anyAutoscalingEnabled(HiveClusterSpec spec) { if (spec.hiveServer2().autoscaling().isEnabled()) { return true; @@ -713,12 +757,12 @@ private int resolveLlapReplicaCount(HiveCluster resource, return 0; } String componentKey = ConfigUtils.llapComponentKey(llapSpec.name()); - Integer managed = HiveClusterAutoscaler.getManagedReplicas(ns, clusterName, componentKey); - if (managed != null) { - return managed; - } - // First reconcile before autoscaler runs: start at minReplicas if autoscaling enabled if (llapSpec.autoscaling().isEnabled()) { + Integer managed = HiveClusterAutoscaler.getManagedReplicas(ns, clusterName, componentKey); + if (managed != null) { + return managed; + } + // First reconcile before autoscaler runs: start at minReplicas if autoscaling enabled return llapSpec.autoscaling().minReplicas(); } return llapSpec.replicas(); @@ -734,21 +778,17 @@ private int resolveTezAmReplicaCount(HiveCluster resource, return 0; } LlapSpec.LlapTezAmSpec tezAmSpec = llapSpec.tezAm(); - // Check if autoscaler has a managed value for this specific TezAM String tezAmComponentKey = ConfigUtils.tezAmComponentKey(llapSpec.name()); - Integer tezAmManaged = HiveClusterAutoscaler.getManagedReplicas(ns, clusterName, tezAmComponentKey); - if (tezAmManaged != null) { - return tezAmManaged; - } - // TezAM follows LLAP's autoscaling gate: only run if LLAP is running. - String llapComponentKey = ConfigUtils.llapComponentKey(llapSpec.name()); - Integer llapManaged = HiveClusterAutoscaler.getManagedReplicas(ns, clusterName, llapComponentKey); - if (llapManaged != null && llapManaged == 0) { - return 0; + // Check if autoscaler has a managed value for this specific TezAM + if (tezAmSpec.autoscaling().isEnabled()) { + Integer tezAmManaged = HiveClusterAutoscaler.getManagedReplicas(ns, clusterName, tezAmComponentKey); + if (tezAmManaged != null) { + return tezAmManaged; + } } - if (llapSpec.autoscaling().isEnabled() && llapManaged == null - && llapSpec.autoscaling().minReplicas() == 0) { - // First reconcile before autoscaler runs: LLAP starts at 0, so TezAM stays down too. + + int llapDesired = resolveLlapReplicaCount(resource, llapSpec, ns, clusterName); + if (llapDesired == 0) { return 0; } if (tezAmSpec.autoscaling().isEnabled()) { @@ -1012,35 +1052,29 @@ private void wakeCluster(HiveCluster resource) { // the dependent resources (Deployments/StatefulSets) on the next reconcile // and use these values for spec.replicas. We don't call patchReplicas() // because the workloads may have been garbage-collected while suspended. - // With autoscaling disabled the wake value is the spec's static replica - // count — using minReplicas (0 by default) would pin the component to 0. - int hs2Wake = spec.hiveServer2().autoscaling().isEnabled() - ? Math.max(1, spec.hiveServer2().autoscaling().minReplicas()) - : spec.hiveServer2().replicas(); - HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.COMPONENT_HIVESERVER2, hs2Wake); + if (spec.hiveServer2().autoscaling().isEnabled()) { + HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.COMPONENT_HIVESERVER2, + Math.max(1, spec.hiveServer2().autoscaling().minReplicas())); + } - if (spec.metastore().isEnabled() && spec.autoSuspend().includeMetastore()) { - int hmsWake = spec.metastore().autoscaling().isEnabled() - ? Math.max(1, spec.metastore().autoscaling().minReplicas()) - : spec.metastore().replicas(); - HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.COMPONENT_METASTORE, hmsWake); + if (spec.metastore().isEnabled() && spec.autoSuspend().includeMetastore() + && spec.metastore().autoscaling().isEnabled()) { + HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.COMPONENT_METASTORE, + Math.max(1, spec.metastore().autoscaling().minReplicas())); } for (var llap : spec.llapClusters()) { - if (llap.isEnabled()) { - int llapWake = llap.autoscaling().isEnabled() - ? llap.autoscaling().minReplicas() : llap.replicas(); - HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.llapComponentKey(llap.name()), llapWake); + if (llap.isEnabled() && llap.autoscaling().isEnabled()) { + HiveClusterAutoscaler.setManagedReplicas(ns, name, ConfigUtils.llapComponentKey(llap.name()), + llap.autoscaling().minReplicas()); } } if (spec.tezAm().isEnabled()) { for (var llap : spec.llapClusters()) { - if (llap.isEnabled()) { - int tezWake = llap.tezAm().autoscaling().isEnabled() - ? llap.tezAm().autoscaling().minReplicas() : llap.tezAm().replicas(); + if (llap.isEnabled() && llap.tezAm().autoscaling().isEnabled()) { HiveClusterAutoscaler.setManagedReplicas(ns, name, - ConfigUtils.tezAmComponentKey(llap.name()), tezWake); + ConfigUtils.tezAmComponentKey(llap.name()), llap.tezAm().autoscaling().minReplicas()); } } }