kubernetes hpa源码分析

hpa原理详解 从源码角度分析hpa的计算逻辑 阅读详情

 

初始化

文件位置:cmd/kube-controller-manager/app/controllermanager.go

func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc {
	...
	controllers["horizontalpodautoscaling"] = startHPAController
	...
}

HPA Controller和其他的Controller一样,都在NewControllerInitializers方法中进行注册,然后通过startHPAController来启动。

startHPAController

|-> startHPAControllerWithRESTClient

    |-> startHPAControllerWithMetricsClient

        |-> NewHorizontalController

文件位置:/pkg/controller/podautoscaler/horizontal.go

// NewHorizontalController creates a new HorizontalController.
func NewHorizontalController(
	evtNamespacer v1core.EventsGetter,
	scaleNamespacer scaleclient.ScalesGetter,
	hpaNamespacer autoscalingclient.HorizontalPodAutoscalersGetter,
	mapper apimeta.RESTMapper,
	metricsClient metricsclient.MetricsClient,
	hpaInformer autoscalinginformers.HorizontalPodAutoscalerInformer,
	podInformer coreinformers.PodInformer,
	resyncPeriod time.Duration,
	downscaleStabilisationWindow time.Duration,
	tolerance float64,
	cpuInitializationPeriod,
	delayOfInitialReadinessStatus time.Duration,

) *HorizontalController {
	broadcaster := record.NewBroadcaster()
	broadcaster.StartStructuredLogging(0)
	broadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: evtNamespacer.Events("")})
	recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "horizontal-pod-autoscaler"})

  ...

	hpaInformer.Informer().AddEventHandlerWithResyncPeriod(
		cache.ResourceEventHandlerFuncs{
			AddFunc:    hpaController.enqueueHPA,
			UpdateFunc: hpaController.updateHPA,
			DeleteFunc: hpaController.deleteHPA,
		},
		resyncPeriod,
	)
  ...

	return hpaController
}

核心逻辑是监听hpa对象的事件,分别对应hpaController.unqueueHPA,hpaController.updateHPA和hpaController.deleteHPA。enqueueHPA本质上就是把hpa对象注册到HorizontalController的队列里,updateHPA是更新hpa对象,deleteHPA是删除对象。hpa对象存在hpaController的workqueue中。

代码见下文

文件位置:/pkg/controller/podautoscaler/horizontal.go

// obj could be an *v1.HorizontalPodAutoscaler, or a DeletionFinalStateUnknown marker item.
func (a *HorizontalController) updateHPA(old, cur interface{}) {
	a.enqueueHPA(cur)
}

// obj could be an *v1.HorizontalPodAutoscaler, or a DeletionFinalStateUnknown marker item.
func (a *HorizontalController) enqueueHPA(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
		return
	}

	// Requests are always added to queue with resyncPeriod delay.  If there's already
	// request for the HPA in the queue then a new request is always dropped. Requests spend resync
	// interval in queue so HPAs are processed every resync interval.
	a.queue.AddRateLimited(key)
}

func (a *HorizontalController) deleteHPA(obj interface{}) {
	key, err := controller.KeyFunc(obj)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("couldn't get key for object %+v: %v", obj, err))
		return
	}

	// TODO: could we leak if we fail to get the key?
	a.queue.Forget(key)
}

startHPAController

文件位置:cmd/kube-controller-manager/app/autoscaling.go

最后会调用到startHPAControllerWithMetricsClient方法,启动一个线程来调用NewHorizontalController方法初始化一个HPA Controller,然后执行Run方法。
func startHPAController(ctx ControllerContext) (http.Handler, bool, error) {
	...
	return startHPAControllerWithLegacyClient(ctx)
}

func startHPAControllerWithLegacyClient(ctx ControllerContext) (http.Handler, bool, error) {
	hpaClient := ctx.ClientBuilder.ClientOrDie("horizontal-pod-autoscaler")
	metricsClient := metrics.NewHeapsterMetricsClient(
		hpaClient,
		metrics.DefaultHeapsterNamespace,
		metrics.DefaultHeapsterScheme,
		metrics.DefaultHeapsterService,
		metrics.DefaultHeapsterPort,
	)
	return startHPAControllerWithMetricsClient(ctx, metricsClient)
}


func startHPAControllerWithMetricsClient(ctx ControllerContext, metricsClient metrics.MetricsClient) (http.Handler, bool, error) {
	hpaClient := ctx.ClientBuilder.ClientOrDie("horizontal-pod-autoscaler")
	hpaClientConfig := ctx.ClientBuilder.ConfigOrDie("horizontal-pod-autoscaler")
 
	scaleKindResolver := scale.NewDiscoveryScaleKindResolver(hpaClient.Discovery())
	scaleClient, err := scale.NewForConfig(hpaClientConfig, ctx.RESTMapper, dynamic.LegacyAPIPathResolverFunc, scaleKindResolver)
	if err != nil {
		return nil, false, err
	}
	// 初始化
	go podautoscaler.NewHorizontalController(
		hpaClient.CoreV1(),
		scaleClient,
		hpaClient.AutoscalingV1(),
		ctx.RESTMapper,
		metricsClient,
		ctx.InformerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
		ctx.InformerFactory.Core().V1().Pods(),
		ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerSyncPeriod.Duration,
		ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerDownscaleStabilizationWindow.Duration,
		ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerTolerance,
		ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerCPUInitializationPeriod.Duration,
		ctx.ComponentConfig.HPAController.HorizontalPodAutoscalerInitialReadinessDelay.Duration,
	).Run(ctx.Stop)
	return nil, true, nil
}

Run

文件位置:pkg/controller/podautoscaler/horizontal.go

func (a *HorizontalController) Run(stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()
	defer a.queue.ShutDown()

	klog.Infof("Starting HPA controller")
	defer klog.Infof("Shutting down HPA controller")

	if !cache.WaitForNamedCacheSync("HPA", stopCh, a.hpaListerSynced, a.podListerSynced) {
		return
	}
  // 启动异步线程,每秒执行一次
	go wait.Until(a.worker, time.Second, stopCh)

	<-stopCh
}

这里会调用worker执行具体的扩缩容的逻辑。

hpa逻辑路口:定时执行worker

go wait.Until(a.worker, time.Second, stopCh)

核心代码分析

processNextWorkItem: 遍历所有hpa对象

func (a *HorizontalController) worker() {
	for a.processNextWorkItem() {
	}
	klog.Infof("horizontal pod autoscaler controller worker shutting down")
}
func (a *HorizontalController) processNextWorkItem() bool {
	key, quit := a.queue.Get()
	if quit {
		return false
	}
	defer a.queue.Done(key)

	deleted, err := a.reconcileKey(key.(string))
	if err != nil {
		utilruntime.HandleError(err)
	}

	if !deleted {
		a.queue.AddRateLimited(key)
	}

	return true
}
hpa对象存储在HorizontalController的队列中,遍历每个hpa对象进行处理。
processNextWorkItem->

    |-> reconcileKey

        |-> reconcileAutoscaler

worker里面一路执行下来会走到reconcileAutoscaler方法里面,这里是HPA的核心。下面我们专注看看这部分。

reconcileAutoscaler:计算副本数

func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.HorizontalPodAutoscaler, key string) error {
	...
    //副本数为0,不启动自动扩缩容
	if scale.Spec.Replicas == 0 && minReplicas != 0 {
		// Autoscaling is disabled for this resource
		desiredReplicas = 0
		rescale = false
		setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "ScalingDisabled", "scaling is disabled since the replica count of the target is zero")
	//	如果当前副本数大于最大期望副本数,那么设置期望副本数为最大副本数
	} else if currentReplicas > hpa.Spec.MaxReplicas {
		rescaleReason = "Current number of replicas above Spec.MaxReplicas"
		desiredReplicas = hpa.Spec.MaxReplicas
	//	同上
	} else if currentReplicas < minReplicas {
		rescaleReason = "Current number of replicas below Spec.MinReplicas"
		desiredReplicas = minReplicas
	} else {
		var metricTimestamp time.Time
		//计算需要扩缩容的数量
		metricDesiredReplicas, metricName, metricStatuses, metricTimestamp, err = a.computeReplicasForMetrics(hpa, scale, hpa.Spec.Metrics)
		if err != nil {
			...
		}

		klog.V(4).Infof("proposing %v desired replicas (based on %s from %s) for %s", metricDesiredReplicas, metricName, metricTimestamp, reference)

		rescaleMetric := ""
		if metricDesiredReplicas > desiredReplicas {
			desiredReplicas = metricDesiredReplicas
			rescaleMetric = metricName
		}
		if desiredReplicas > currentReplicas {
			rescaleReason = fmt.Sprintf("%s above target", rescaleMetric)
		}
		if desiredReplicas < currentReplicas {
			rescaleReason = "All metrics below target"
		}

		//可以在扩缩容的时候指定一个稳定窗口,以防止缩放目标中的副本数量出现波动
		//doc:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-configurable-scaling-behavior
		if hpa.Spec.Behavior == nil {
			desiredReplicas = a.normalizeDesiredReplicas(hpa, key, currentReplicas, desiredReplicas, minReplicas)
		} else {
			desiredReplicas = a.normalizeDesiredReplicasWithBehaviors(hpa, key, currentReplicas, desiredReplicas, minReplicas)
		}
		rescale = desiredReplicas != currentReplicas
	}
    ...
}
这一段代码是reconcileAutoscaler里面的核心代码,在这里会确定一个区间,首先根据当前的scale对象和当前hpa里面配置的对应的参数的值,决策当前的副本数量,其中针对于超过设定的maxReplicas和小于minReplicas两种情况,只需要简单的修正为对应的值,直接更新对应的scale对象即可,而scale副本为0的对象,则hpa不会在进行任何操作。

对于当前副本数在maxReplicas和minReplicas之间的时候,则需要计算是否需要扩缩容,计算则是调用computeReplicasForMetrics方法来实现。

computeReplicasForMetrics 遍历度量目标

func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *autoscalingv1.Scale,
	metricSpecs []autoscalingv2.MetricSpec) (replicas int32, metric string, statuses []autoscalingv2.MetricStatus, timestamp time.Time, err error) {
	...
  
	//这里的度量目标可以是一个列表,所以遍历之后取最大的需要扩缩容的数量
	for i, metricSpec := range metricSpecs {
		//根据type类型计算需要扩缩容的数量
		replicaCountProposal, metricNameProposal, timestampProposal, condition, err := a.computeReplicasForMetric(hpa, metricSpec, specReplicas, statusReplicas, selector, &statuses[i])

		if err != nil {
			if invalidMetricsCount <= 0 {
				invalidMetricCondition = condition
				invalidMetricError = err
			}
			invalidMetricsCount++
		}
		//记录最大的需要扩缩容的数量
		if err == nil && (replicas == 0 || replicaCountProposal > replicas) {
			timestamp = timestampProposal
			replicas = replicaCountProposal
			metric = metricNameProposal
		}
	}
    ...
    return replicas, metric, statuses, timestamp, nil
}

在上面的代码中遍历所有的metrics,然后选取返回副本数最大的那个。主要计算逻辑都在computeReplicasForMetric中,下面我们看看这个方法。

computeReplicasForMetric:根据type计算副本数

func (a *HorizontalController) computeReplicasForMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, spec autoscalingv2.MetricSpec,
	specReplicas, statusReplicas int32, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, metricNameProposal string,
	timestampProposal time.Time, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) {
	//根据不同的类型来进行计量
	switch spec.Type {
	//表示如果是一个k8s对象,如Ingress对象
	case autoscalingv2.ObjectMetricSourceType:
		...
	//	表示pod度量类型
	case autoscalingv2.PodsMetricSourceType:
		metricSelector, err := metav1.LabelSelectorAsSelector(spec.Pods.Metric.Selector)
		if err != nil {
			condition := a.getUnableComputeReplicaCountCondition(hpa, "FailedGetPodsMetric", err)
			return 0, "", time.Time{}, condition, fmt.Errorf("failed to get pods metric value: %v", err)
		}
		//仅支持AverageValue度量目标,计算需要扩缩容的数量
		replicaCountProposal, timestampProposal, metricNameProposal, condition, err = a.computeStatusForPodsMetric(specReplicas, spec, hpa, selector, status, metricSelector)
		if err != nil {
			return 0, "", time.Time{}, condition, fmt.Errorf("failed to get pods metric value: %v", err)
		}
	//	表示Resource度量类型
	case autoscalingv2.ResourceMetricSourceType:
		...
	case autoscalingv2.ExternalMetricSourceType:
		...
	default:
		errMsg := fmt.Sprintf("unknown metric source type %q", string(spec.Type))
		err = fmt.Errorf(errMsg)
		condition := a.getUnableComputeReplicaCountCondition(hpa, "InvalidMetricSourceType", err)
		return 0, "", time.Time{}, condition, err
	}
	return replicaCountProposal, metricNameProposal, timestampProposal, autoscalingv2.HorizontalPodAutoscalerCondition{}, nil
}

这里会根据不同的度量类型来进行统计,目前度量类型有四种,分别是Pods、Object、Resource、External。

computeStatusForPodsMetric&GetMetricReplicas:计算需要扩缩容的数量

文件位置:pkg/controller/podautoscaler/replica_calculator.go

func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) {
	//计算需要扩缩容的数量
	replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetMetricReplicas(currentReplicas, metricSpec.Pods.Target.AverageValue.MilliValue(), metricSpec.Pods.Metric.Name, hpa.Namespace, selector, metricSelector)
	if err != nil {
		condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetPodsMetric", err)
		return 0, timestampProposal, "", condition, err
	}
	...
	return replicaCountProposal, timestampProposal, fmt.Sprintf("pods metric %s", metricSpec.Pods.Metric.Name), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil
}

func (c *ReplicaCalculator) GetMetricReplicas(currentReplicas int32, targetUtilization int64, metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) {
	//获取pod中度量数据
	metrics, timestamp, err := c.metricsClient.GetRawMetric(metricName, namespace, selector, metricSelector)
	if err != nil {
		return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v", metricName, err)
	}
	//通过结合度量数据来计算希望扩缩容的数量是多少
	replicaCount, utilization, err = c.calcPlainMetricReplicas(metrics, currentReplicas, targetUtilization, namespace, selector, v1.ResourceName(""))
	return replicaCount, utilization, timestamp, err
}

这里会调用GetRawMetric方法来获取pod对应的度量数据,然后再调用calcPlainMetricReplicas方法结合度量数据与目标期望来计算希望扩缩容的数量是多少。

calcPlainMetricReplicas:计算副本数具体实现

func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMetricsInfo, currentReplicas int32, targetUtilization int64, namespace string, selector labels.Selector, resource v1.ResourceName) (replicaCount int32, utilization int64, err error) {

	podList, err := c.podLister.Pods(namespace).List(selector)
	...
	//将pod分成三类进行统计,得到ready的pod数量、ignored Pod集合、missing Pod集合
	readyPodCount, ignoredPods, missingPods := groupPods(podList, metrics, resource, c.cpuInitializationPeriod, c.delayOfInitialReadinessStatus)
	//在度量的数据里移除ignored Pods集合的数据
	removeMetricsForPods(metrics, ignoredPods)
	//计算pod中container request 设置的资源之和
	requests, err := calculatePodRequests(podList, resource)
	...
	//获取资源使用率
	usageRatio, utilization := metricsclient.GetMetricUtilizationRatio(metrics, targetUtilization)
	...
}

这里会调用groupPods将pod列表的进行一个分类统计。ignoredPods集合里面包含了pod状态为PodPending的数据;missingPods列表里面包含了在度量数据里面根据pod名找不到的数据。

因为missingPods的度量数据已经在metrics里是找不到的,然后只需要剔除掉ignored Pods集合中度量的资源就好了。接下来调用calculatePodRequests方法统计pod中container request 设置的资源之和。

总结

hpa整个逻辑流程图:


 

Kubernetes——HPA自动伸缩机制 弹性伸缩是根据用户的业务需求和策略,自动“调整”其“弹性资源”的管理服务。通过弹性伸缩功能,用户可设置对定时、周期或监控策略,恰到好处地增加或减少“弹性资源”,并完成实例配置,保证业务平稳健康运行在实际工作中,我们常常需要做一些扩容缩容操作,如:电商平台在618和双十一搞秒杀活动;由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作。Node层面:对K8s物理节点扩容和缩容,根据业务规模实现物理节点自动扩缩容Pod层面。 阅读详情

相关推荐

Kubernetes 的 HPA 原理详解

总的来说,从k8s v1.18开始HPA的机制已经算比较灵活了,在扩缩容识别指标上可以使用Pod的系统cpu、内存指标,也可以Pods自身暴露的自定义metrics指标,还可以支持外部的业务指标;在具体自定义实现上也提供了标准的扩展框架,还有社区其他人贡献的promesheus adapter。在扩缩容速度上也通过相对百分比和绝对 Pods数变化,可以独立控制单位时间内最大的扩容和缩容,此外还通过自定义窗口时间机制保证副本变化的稳定性。...

weixin_67470255的博客 3377

HPA详解

当我们从API 获取的指标来进行自动扩缩容时,只能以CPU、内存作为资源度量指标。只能使用绝对值或者百分比。因为cpu或者内存并不能全面的代表机器的压力,所以我们引入通过外部的指标,来进行扩缩容。(自定义度量指标)包括两种度量指标pod度量指标:比如根据pod的网络io来进行伸缩object度量指标:比如根据ingress的并发数来进行伸缩。

weixin_43539320的博客 999

Kubernetes中水平自动伸缩(Horizontal Pod Autoscaling,HPA)的工作原理

在Kubernetes中,水平自动伸缩(HPA)是一种自动化机制,可根据CPU使用率或其他指标自动调整Pod的数量。HPA控制器:HPA控制器是一个Kubernetes控制器,负责监测目标CPU使用率并根据设定的规则进行自动扩展或收缩Pod。Kubernetes中的水平自动伸缩(HPA)是一种自动化机制,用于根据CPU使用率或其他指标自动调整Pod的数量,以满足应用程序的需求并保持最佳性能。在HPA的工作流程中,Pod副本控制器会根据HPA控制器的指令创建或销毁Pod副本。

CqppDeveloper的博客 270

【kubernetes/k8s源码分析】kubectl-controller-manager之HPA源码分析

本文基于kubernetes版本:v1.12.1 HPA介绍 https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ The Horizontal Pod Autoscaler automatically scales the number of pods in a replica...

zhonglinzhang 3878

cron-hpa:Cron水平Pod自动缩放器(CronHPA)

CronHPA Cron Horizo​​ntal Pod Autoscaler(CronHPA)使我们能够使用方案定期自动扩展工作负载(那些支持scale子资源,例如部署,statefulset)。 CronHPA示例: apiVersion: extensions.tkestack.io/v1 kind: CronHPA metadata: name: example-cron-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: demo-deployment crons: - schedule: "0 23 * * 5" // Set replicas to 60 every Friday 23:00 targetReplicas:

薛定谔虚拟筛选实战:如何用PDB文件快速构建受体格点(避坑指南)

本文提供了薛定谔虚拟筛选实战指南,聚焦于如何从PDB文件快速、精准地构建受体格点。文章详细解析了可变残基的理性处理策略、基于配体尺寸的盒子量化设置方法,并分享了高级约束与排除体积的实战技巧,旨在帮助用户避开常见陷阱,提升虚拟筛选的成功率与效率。

weixin_28419039的博客 254

k8s HPA 自动伸缩机制 (配置,资源限制,)

当需要使用自定义指标(如来自Prometheus的指标)时,自定义指标适配器允许HPA使用这些外部指标。它通过Custom Metrics API将外部指标转换为Kubernetes可以理解的格式。

qq_51545656的博客 2446

【Clickhouse从入门到精通】第60篇:ClickHouse生态总结与未来展望

ClickHouse系列收官总结 本文作为《ClickHouse从入门到精通》系列的第60篇收官之作,系统回顾了整个系列的知识体系。文章从基础概念到高级应用,全面梳理了ClickHouse的核心技术: 知识体系:完整回顾了60篇文章的知识图谱,包括列式存储原理、MergeTree引擎家族、分布式架构等核心内容 生态工具:详细盘点了ClickHouse的企业版工具、运维监控、数据集成和可视化方案 版本演进:分析了从21.x到24.x的主要版本特性升级 未来趋势:展望了向量化引擎、湖仓一体、AI集成等发展方向

xyghehehehe的专栏 441

Kubernetes HPA Controller源码分析

本博文对Kubernetes的HorizontalPodAutoscaler的代码实现进行了分析,包括源码目录结构分析,关键代码走读分析,内部实现原理图,希望能帮助大家深入的理解k8s实现auto scale的原理。

WaltonWang's Blog 2万+

AI落地困局与破局者FDE:从技术神话到价值实干的战略转型

AI落地困局与破局者FDE:从技术神话到价值实干的战略转型 当前AI企业级应用面临三大核心挑战:业务场景深度非标化、技术落地"最后一公里"困局、以及市场竞争焦点转向实用价值。前线部署工程师(FDE)作为破局关键,通过技术-业务-产品三维交汇的复合能力,将AI从实验室推向生产环境。FDE不仅是技术架构师,更是业务价值挖掘机和产品进化传感器,通过"碎石路-高速公路"双循环模式,将定制化需求沉淀为可复用的平台能力。这种模式颠覆了传统SaaS的销售逻辑,形成基于价值的J型增长

随笔记录-分享&记忆 4003

用于多种无人机协作的群体智能算法:综合综述

随着无人机技术的快速高水平发展,将多架无人机作为自主控制的编队应用于复杂情况是一个新兴领域的代表之一。在实现自主控制的挑战中,碰撞避免、任务分配、路径规划和编队重构是关键功能。本文对各种经典的无人机群智能算法进行了系统的总结和分析。

erjia_的博客 1万+

k8s controller-manager之hpa源码分析

基于kubernetes release-1.9 源码目录结构 cmd/kube-controller-manager/app/autoscaling.go // HPA Controller的启动代码 /pkg/controller/podautoscaler . ├── metrics │ ├── BUILD │ ├── interfaces.go │ ├── ...

polarwu的博客 2661

Python控制Keysight DAQ973A/DAQ970A实现数据采集

本文介绍了如何通过编程实现Keysight DAQ973A数据采集系统的自动化温度测量。首先,通过GPIB线将PC与仪器连接,并使用热电耦测量线连接被测装置。接着,通过查阅Keysight官网提供的编程手册,获取了实现温度测量所需的SCPI指令。然后,使用pyvisa库编写代码,与仪器进行交互,发送SCPI指令并读取测量结果。代码中整合了配置和查询指令,并将测量结果转换为浮点数格式。最后,将整个流程封装为命令行工具,用户可以通过配置文件设置参数,并执行自动化测试,测试结果将保存为CSV文件。整个过程实现了温

xgh1951的博客 1887

kubernetes实战与源码剖析

介绍docker的前世今生,了 解docker的实现原理,以Django项目为例,教大家如何编写好的Dockerfile实现构业务镜像的制作。通过课程的学习,大家会知道docker的概念及基本操作,并学习构建自己的业务镜像,并通过抓包的方式学习Docker最常用的bridge网络模式的通信。 kubernetes实战与源码剖析|MCA小课| 完结 课程目录: ├──章节1-第1章 准...

ygunoil的博客 136

数据挖掘实战-基于情感分析+网络语义分析+LDA主题分析对大唐不夜城用户评论进行文本分析

本研究基于去哪儿网和携程网的1888条大唐不夜城游客评论数据,运用Python进行文本分析。通过情感分析发现游客评价以积极为主(占比约70%),中性占20%,消极占10%。采用ROSTCM6软件进行社会网络语义分析,识别不同情绪下的高频词汇。使用LDA主题模型将评论划分为3个主题(夜景、表演、美食),并分析主题强度随时间变化趋势。实验包含数据采集、预处理、情感分析、语义网络分析和LDA建模等完整流程,为景区管理优化提供数据支持。源代码涵盖爬虫、数据处理和可视化分析的全套实现。

m0_64336780的博客 1万+

使用openclaw出现blocked URL fetch (url-fetch) reason=Blocked: resolves to private/internal/special 解决方案

本文主要介绍了使用openclaw出现blocked URL fetch (url-fetch) target=https://news.google.com/search reason=Blocked: resolves to private/internal/special-use IP address 解决方案,希望能对使用xx的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 11万+

[kubernetes系列]HPA模块深度讲解

一,前言 对于kubernetes基础性的知识,目前有很多资料,于是不会重复展开,想做一个对每个模块都深入讲解的系列,包括基础使用,源码解读,和实践中遇到的问题等,所以篇幅很比较长。 二,HPA模块 1,相关说明 (1) kubernetes版本:v1.9.2 (2) 适合对kubernetes基础有一定了解的人群 2,基本概念和使用 (1) 概念 HPA是kubernetes中自动水平扩展模块,...

weixin_34227447的博客 1105

华为OD机试 - 停车场费用统计 - HashSet(Python/JS/C/C++ 双机位C卷 100分)

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。停车场统计当日总收费,包月的车不统计,不包月的车半个小时收一块钱,不满半小时不收费,如果超过半小时,零头不满半小时按半小时算,每天11:30-13:30时间段不收费,如果一辆车停车时间超过8小时后不收费。现提供停车场进出车辆的统计信息,需要你来计

学Java,找哪吒 238

K8s中明明配置了HPA,但是没扩容

HPA不扩容?伤脑筋。

wanger5354的博客 935

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【Kubernetes】k8s 自动伸缩机制—— HPA 部署

●HPA 是 控制器管理pod资源的副本数量 实现自动伸缩●原理:追踪可控制器管理的pod负载情况,来根据设置的阈值来动态调整pod副本的数量●metrics-server 收集k8s中的node、pod 等资源的使用情况,kubectl top node/pod●kubectl autoscale 控制器 --cpuprecent=60 --min=最小值 --max=最大值。

Mo_nor的博客 2454

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

K8S的HPA机制

K8S的HPA机制一、HPA简介二、HPA设置 一、HPA简介 HPA(Horizontal Pod Autoscaler)Pod自动弹性伸缩,通过对Pod中运行的容器各项指标(CPU占用、内存占用、网络请求量)的检测,实现对Pod实例个数的动态新增和减少。 早期的kubernetes版本,只支持CPU指标的检测,因为它是通过kubernetes自带的监控系统heapster实现的。 到了kube...

rootlh的博客 1万+

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

k8s-HPA

一、认识HPA 参考: https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale/ HPA全称是Horizontal Pod Autoscaler,中文意思是POD水平自动伸缩. 可以基于 CPU 利用率自动扩缩 ReplicationController、Deployment、ReplicaSet 和 StatefulSet 中的 Pod 数量。 除了 CPU 利用率,内存占用外,也可以基于其他应程

Kubernetes enthusiasts 1万+

【k8s应用管理】kubernetes HPA+rancher

Kubernetes HPA(Horizontal Pod Autoscaling)可以根据Pod的CPU利用率自动调整Deployment、Replication Controller或ReplicaSet中的Pod数量。本文将指导您如何部署HPA,包括前置条件(metrics-server的部署)和HPA的实际部署。

Karoku的博客 1032

K8S中HPA详解

一、 HPA解决的问题 HPA全称是 Horizontal Pod Autoscaler,也就是对k8s的workload的副本数进行自动水平扩缩容(scale)机制,也是k8s里使用需求最广泛的一种Autoscaler机制,在开始详细介绍HPA之前,先简单梳理下k8s autoscale的整个大背景。 k8s被誉为新一代数据中心操作系统(DCOS),说到操作系统我们自然想到其定义:管理计算机的...

mcl914的博客 7687
上一篇: 【SpringBoot】 理解Spirng中的IOC原理
下一篇: 一文读懂 Kubernetes APIServer 原理
cbmljs
博客等级 码龄10年 329粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值