9.2 EvictionManager源码解读
本节重点总结 :
-
evictionManager初始化了两个相同的manager对象
- evictionManager做本机驱逐pod的判定和厨房
- evictionAdmitHandler用来kubelet创建Pod前进依据本机的资源压力进行准入检查
-
evictionManager判断内存驱逐阈值有两种方法
- 第一种使用内核的memcg的通知机制,更高效
- 当内存使用第一时间达到门槛,会立刻通知kubelet,并触发synchronize()进行资源回收的流程。这样提高了eviction的实时性。
- 第二种使用轮询检查的机制
- 第一种使用内核的memcg的通知机制,更高效
-
优先回收节点资源再驱逐pod
-
驱逐pod调用kubelet的syncPod()方法,把podPhase=Failed更新进去。
evictionManager 接口定义
- 位置 D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubelet\eviction\types.go
// Manager evaluates when an eviction threshold for node stability has been met on the node.
type Manager interface {// Start 用来监控驱逐的阈值的Start(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc, podCleanedUpFunc PodCleanedUpFunc, monitoringInterval time.Duration)// 返回内存是否有压力IsUnderMemoryPressure() bool// 返回磁盘是否有压力IsUnderDiskPressure() bool// 返回PID是否有压力IsUnderPIDPressure() bool
}
evictionManager 结构体字段解析
- 位置 D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubelet\eviction\eviction_manager.go
// managerImpl implements Manager
type managerImpl struct {// used to track timeclock clock.Clock// config is how the manager is configuredconfig Config// killpod的方法killPodFunc KillPodFunc// 获取静态pod的mirror pod 方法mirrorPodFunc MirrorPodFunc// 当node出现diskPressure condition时,imageGC进行unused images删除操作以回收disk space。imageGC ImageGC// the interface that knows how to do container gccontainerGC ContainerGC// protects access to internal statesync.RWMutex// 当前节点条件集合nodeConditions []v1.NodeConditionType// 记录nodecontions上一次观察的时间nodeConditionsLastObservedAt nodeConditionsObservedAt// nodeRef is a reference to the nodenodeRef *v1.ObjectReference// used to record events about the noderecorder record.EventRecorder// 提供node和node上所有pods的最新status数据汇总,既NodeStats and []PodStats。summaryProvider stats.SummaryProvider// records when a threshold was first observedthresholdsFirstObservedAt thresholdsObservedAt// 保存已经触发但还没解决的Thresholds,包括那些处于grace period等待阶段的Thresholds。thresholdsMet []evictionapi.Threshold// s定义各Resource进行evict挑选时的排名方法。signalToRankFunc map[evictionapi.Signal]rankFunc// 定义各Resource进行回收时调用的方法signalToNodeReclaimFuncs map[evictionapi.Signal]nodeReclaimFuncs// last observations from synchronizelastObservations signalObservations// dedicatedImageFs indicates if imagefs is on a separate device from the rootfsdedicatedImageFs *bool// 内存阈值通知器集合thresholdNotifiers []ThresholdNotifier// 上次thresholdNotifiers发通知的时间thresholdsLastUpdated time.Time
}
evictionManager的初始化
- 入口在kubelet 的new中
// setup eviction managerevictionManager, evictionAdmitHandler := eviction.NewManager(klet.resourceAnalyzer, evictionConfig, killPodNow(klet.podWorkers, kubeDeps.Recorder), klet.podManager.GetMirrorPodByPod, klet.imageManager, klet.containerGC, kubeDeps.Recorder, nodeRef, klet.clock)
- 返回的 evictionManager, evictionAdmitHandler 其实都是 evictionManager对象
func NewManager(summaryProvider stats.SummaryProvider,config Config,killPodFunc KillPodFunc,mirrorPodFunc MirrorPodFunc,imageGC ImageGC,containerGC ContainerGC,recorder record.EventRecorder,nodeRef *v1.ObjectReference,clock clock.Clock,
) (Manager, lifecycle.PodAdmitHandler) {manager := &managerImpl{clock: clock,killPodFunc: killPodFunc,mirrorPodFunc: mirrorPodFunc,imageGC: imageGC,containerGC: containerGC,config: config,recorder: recorder,summaryProvider: summaryProvider,nodeRef: nodeRef,nodeConditionsLastObservedAt: nodeConditionsObservedAt{},thresholdsFirstObservedAt: thresholdsObservedAt{},dedicatedImageFs: nil,thresholdNotifiers: []ThresholdNotifier{},}return manager, manager
}
evictionAdmitHandler的作用
- evictionAdmitHandler用来kubelet创建Pod前进行准入检查,满足条件后才会继续创建Pod,通过Admit方法来检查
- 可以看到evictionAdmitHandler被添加到kubelet的admitHandlers中了
klet.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler)
Admit方法解读
evictionAdmitHandler的Admit方法是 用node的压力状态 做pod是否准入的依据,相当于影响调度的结果
- 由下列可以看出如果 node现在没有压力状态那么准入
m.RLock()defer m.RUnlock()if len(m.nodeConditions) == 0 {return lifecycle.PodAdmitResult{Admit: true}}
- 如果是静态pod或者SystemCriticalPriority的高优则忽略节点压力状态准入
// Admit Critical pods even under resource pressure since they are required for system stability.// https://github.com/kubernetes/kubernetes/issues/40573 has more details.if kubelettypes.IsCriticalPod(attrs.Pod) {return lifecycle.PodAdmitResult{Admit: true}}
- 如果当前节点只有内存的压力,那么pod的qos类型为 非BestEffort则准入
if nodeOnlyHasMemoryPressureCondition {notBestEffort := v1.PodQOSBestEffort != v1qos.GetPodQOS(attrs.Pod)if notBestEffort {return lifecycle.PodAdmitResult{Admit: true}}
- 如果是BestEffort则要根据它的容忍类型判断
// When node has memory pressure, check BestEffort Pod's toleration:// admit it if tolerates memory pressure taint, fail for other tolerations, e.g. DiskPressure.if v1helper.TolerationsTolerateTaint(attrs.Pod.Spec.Tolerations, &v1.Taint{Key: v1.TaintNodeMemoryPressure,Effect: v1.TaintEffectNoSchedule,}) {return lifecycle.PodAdmitResult{Admit: true}}}
- 最后如果pod有disk压力就拒绝
// reject pods when under memory pressure (if pod is best effort), or if under disk pressure.klog.InfoS("Failed to admit pod to node", "pod", klog.KObj(attrs.Pod), "nodeCondition", m.nodeConditions)return lifecycle.PodAdmitResult{Admit: false,Reason: Reason,Message: fmt.Sprintf(nodeConditionMessageFmt, m.nodeConditions),}
总结
- eviction manager对kube-scheduler的调度结果影响
- Kubelet会定期的将Node Condition传给kube-apiserver并存于etcd
- kube-scheduler watch到Node Condition Pressure之后,会根据以下策略,阻止更多Pods Bind到该Node。
- 如果是内存压力,阻止BestEffort pod调度
- 如果是磁盘压力,阻止其他pod调度
evictionManager的启动
-
start方法,位置D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubelet\eviction\eviction_manager.go
-
如果启动了kubelet的参数 --experimental-kernel-memcg-notification
-
设置为 true 表示 kubelet 将会集成内核的 memcg 通知机制而不是使用轮询机制来 判断是否达到了内存驱逐阈值。
if m.config.KernelMemcgNotification {for _, threshold := range m.config.Thresholds {if threshold.Signal == evictionapi.SignalMemoryAvailable || threshold.Signal == evictionapi.SignalAllocatableMemoryAvailable {notifier, err := NewMemoryThresholdNotifier(threshold, m.config.PodCgroupRoot, &CgroupNotifierFactory{}, thresholdHandler)if err != nil {klog.InfoS("Eviction manager: failed to create memory threshold notifier", "err", err)} else {go notifier.Start()m.thresholdNotifiers = append(m.thresholdNotifiers, notifier)}}}}
- 如果没开启则使用轮询机制
// start the eviction manager monitoringgo func() {for {if evictedPods := m.synchronize(diskInfoProvider, podFunc); evictedPods != nil {klog.InfoS("Eviction manager: pods evicted, waiting for pod to be cleaned up", "pods", format.Pods(evictedPods))m.waitForPodsCleanup(podCleanedUpFunc, evictedPods)} else {time.Sleep(monitoringInterval)}}}()
synchronize解析
buildSignalToRankFunc
- 注册各个eviction signal所对应的资源排序方法
func buildSignalToRankFunc(withImageFs bool) map[evictionapi.Signal]rankFunc {signalToRankFunc := map[evictionapi.Signal]rankFunc{evictionapi.SignalMemoryAvailable: rankMemoryPressure,evictionapi.SignalAllocatableMemoryAvailable: rankMemoryPressure,evictionapi.SignalPIDAvailable: rankPIDPressure,}// usage of an imagefs is optionalif withImageFs {// with an imagefs, nodefs pod rank func for eviction only includes logs and local volumessignalToRankFunc[evictionapi.SignalNodeFsAvailable] = rankDiskPressureFunc([]fsStatsType{fsStatsLogs, fsStatsLocalVolumeSource}, v1.ResourceEphemeralStorage)signalToRankFunc[evictionapi.SignalNodeFsInodesFree] = rankDiskPressureFunc([]fsStatsType{fsStatsLogs, fsStatsLocalVolumeSource}, resourceInodes)// with an imagefs, imagefs pod rank func for eviction only includes rootfssignalToRankFunc[evictionapi.SignalImageFsAvailable] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot}, v1.ResourceEphemeralStorage)signalToRankFunc[evictionapi.SignalImageFsInodesFree] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot}, resourceInodes)} else {// without an imagefs, nodefs pod rank func for eviction looks at all fs stats.// since imagefs and nodefs share a common device, they share common ranking functions.signalToRankFunc[evictionapi.SignalNodeFsAvailable] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}, v1.ResourceEphemeralStorage)signalToRankFunc[evictionapi.SignalNodeFsInodesFree] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}, resourceInodes)signalToRankFunc[evictionapi.SignalImageFsAvailable] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}, v1.ResourceEphemeralStorage)signalToRankFunc[evictionapi.SignalImageFsInodesFree] = rankDiskPressureFunc([]fsStatsType{fsStatsRoot, fsStatsLogs, fsStatsLocalVolumeSource}, resourceInodes)}return signalToRankFunc
}
比如内存
- rankMemoryPressure底层调用exceedMemoryRequests来对pod内存进行排序
- pod内存来自于容器内存的叠加,容器内存使用采用workingSetBytes
- 排序的依据为
- 如果pod 的内存使用是否达到它的requests则较大
- 对于使用内存达到requests的则按照使用量再排序
func exceedMemoryRequests(stats statsFunc) cmpFunc {return func(p1, p2 *v1.Pod) int {p1Stats, p1Found := stats(p1)p2Stats, p2Found := stats(p2)if !p1Found || !p2Found {// prioritize evicting the pod for which no stats were foundreturn cmpBool(!p1Found, !p2Found)}p1Memory := memoryUsage(p1Stats.Memory)p2Memory := memoryUsage(p2Stats.Memory)p1ExceedsRequests := p1Memory.Cmp(v1resource.GetResourceRequestQuantity(p1, v1.ResourceMemory)) == 1p2ExceedsRequests := p2Memory.Cmp(v1resource.GetResourceRequestQuantity(p2, v1.ResourceMemory)) == 1// prioritize evicting the pod which exceeds its requestsreturn cmpBool(p1ExceedsRequests, p2ExceedsRequests)}
}
buildSignalToNodeReclaimFuncs
- 注册节点资源回收方法,例如imagefs.avaliable对用的是删除无用容器和无用镜像
// buildSignalToNodeReclaimFuncs returns reclaim functions associated with resources.
func buildSignalToNodeReclaimFuncs(imageGC ImageGC, containerGC ContainerGC, withImageFs bool) map[evictionapi.Signal]nodeReclaimFuncs {signalToReclaimFunc := map[evictionapi.Signal]nodeReclaimFuncs{}// usage of an imagefs is optionalif withImageFs {// with an imagefs, nodefs pressure should just delete logssignalToReclaimFunc[evictionapi.SignalNodeFsAvailable] = nodeReclaimFuncs{}signalToReclaimFunc[evictionapi.SignalNodeFsInodesFree] = nodeReclaimFuncs{}// with an imagefs, imagefs pressure should delete unused imagessignalToReclaimFunc[evictionapi.SignalImageFsAvailable] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}signalToReclaimFunc[evictionapi.SignalImageFsInodesFree] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}} else {// without an imagefs, nodefs pressure should delete logs, and unused images// since imagefs and nodefs share a common device, they share common reclaim functionssignalToReclaimFunc[evictionapi.SignalNodeFsAvailable] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}signalToReclaimFunc[evictionapi.SignalNodeFsInodesFree] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}signalToReclaimFunc[evictionapi.SignalImageFsAvailable] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}signalToReclaimFunc[evictionapi.SignalImageFsInodesFree] = nodeReclaimFuncs{containerGC.DeleteAllUnusedContainers, imageGC.DeleteUnusedImages}}return signalToReclaimFunc
}
synchronize 判定
- 通过podFunc 获取pod
- 获取node的状态summary
activePods := podFunc()updateStats := truesummary, err := m.summaryProvider.Get(updateStats)if err != nil {klog.ErrorS(err, "Eviction manager: failed to get summary stats")return nil}
makeSignalObservations
- 据传入的节点summary,获取各个驱逐信号对应的singleObservations和Pod的StatsFunc
observations, statsFunc := makeSignalObservations(summary)
- 返回值 signalObservations代表某一时间,资源的可用量和总量
- 返回值 statsFunc 后续对Pods进行Rank时需要用的方法
- 以内存为例
if memory := summary.Node.Memory; memory != nil && memory.AvailableBytes != nil && memory.WorkingSetBytes != nil {result[evictionapi.SignalMemoryAvailable] = signalObservation{available: resource.NewQuantity(int64(*memory.AvailableBytes), resource.BinarySI),capacity: resource.NewQuantity(int64(*memory.AvailableBytes+*memory.WorkingSetBytes), resource.BinarySI),time: memory.Time,}}
回到 synchronize 判定
- 计算得出当前触发阈值的threshold集合
thresholds = thresholdsMet(thresholds, observations, false)
- merge之前的已经触发的但还没恢复的thresholds
// determine the set of thresholds previously met that have not yet satisfied the associated min-reclaimif len(m.thresholdsMet) > 0 {thresholdsNotYetResolved := thresholdsMet(m.thresholdsMet, observations, true)thresholds = mergeThresholds(thresholds, thresholdsNotYetResolved)}debugLogThresholdsWithObservation("thresholds - reclaim not satisfied", thresholds, observations)
- 转换得到nodeConditions
// the set of node conditions that are triggered by currently observed thresholdsnodeConditions := nodeConditions(thresholds)if len(nodeConditions) > 0 {klog.V(3).InfoS("Eviction manager: node conditions - observed", "nodeCondition", nodeConditions)}
- 过滤出满足优雅删除的thresholds
// determine the set of thresholds we need to drive eviction behavior (i.e. all grace periods are met)thresholds = thresholdsMetGracePeriod(thresholdsFirstObservedAt, now)debugLogThresholdsWithObservation("thresholds - grace periods satisfied", thresholds, observations)
- 从这轮的观察结果中去掉上一轮的观察结果出现的thresholds
// determine the set of thresholds whose stats have been updated since the last syncthresholds = thresholdsUpdatedStats(thresholds, observations, m.lastObservations)debugLogThresholdsWithObservation("thresholds - updated stats", thresholds, observations)
- 按照驱逐的优先级给thresholds排序
// rank the thresholds by eviction prioritysort.Sort(byEvictionPriority(thresholds))thresholdToReclaim, resourceToReclaim, foundAny := getReclaimableThreshold(thresholds)if !foundAny {return nil}klog.InfoS("Eviction manager: attempting to reclaim", "resourceName", resourceToReclaim)
- 对应的将内存排在前面,优先驱逐
func (a byEvictionPriority) Less(i, j int) bool {_, jSignalHasResource := signalToResource[a[j].Signal]return a[i].Signal == evictionapi.SignalMemoryAvailable || a[i].Signal == evictionapi.SignalAllocatableMemoryAvailable || !jSignalHasResource
}
- 按照优先级最高的threshold回收节点资源,意思是先判断能否回收节点资源
// check if there are node-level resources we can reclaim to reduce pressure before evicting end-user pods.if m.reclaimNodeLevelResources(thresholdToReclaim.Signal, resourceToReclaim) {klog.InfoS("Eviction manager: able to reduce resource pressure without evicting pods.", "resourceName", resourceToReclaim)return nil}
- 使用rank方法排序
// rank the pods for evictionrank, ok := m.signalToRankFunc[thresholdToReclaim.Signal]if !ok {klog.ErrorS(nil, "Eviction manager: no ranking function for signal", "threshold", thresholdToReclaim.Signal)return nil}// the only candidates viable for eviction are those pods that had anything running.if len(activePods) == 0 {klog.ErrorS(nil, "Eviction manager: eviction thresholds have been met, but no pods are active to evict")return nil}// rank the running pods for eviction for the specified resourcerank(activePods, statsFunc)
- 执行驱逐动作
// we kill at most a single pod during each eviction intervalfor i := range activePods {pod := activePods[i]gracePeriodOverride := int64(0)if !isHardEvictionThreshold(thresholdToReclaim) {gracePeriodOverride = m.config.MaxPodGracePeriodSeconds}message, annotations := evictionMessage(resourceToReclaim, pod, statsFunc)if m.evictPod(pod, gracePeriodOverride, message, annotations) {metrics.Evictions.WithLabelValues(string(thresholdToReclaim.Signal)).Inc()return []*v1.Pod{pod}}}klog.InfoS("Eviction manager: unable to evict any pods from the node")return nil
- 底层调用killPodFunc 驱逐pod
func (m *managerImpl) evictPod(pod *v1.Pod, gracePeriodOverride int64, evictMsg string, annotations map[string]string) bool {// If the pod is marked as critical and static, and support for critical pod annotations is enabled,// do not evict such pods. Static pods are not re-admitted after evictions.// https://github.com/kubernetes/kubernetes/issues/40573 has more details.if kubelettypes.IsCriticalPod(pod) {klog.ErrorS(nil, "Eviction manager: cannot evict a critical pod", "pod", klog.KObj(pod))return false}// record that we are evicting the podm.recorder.AnnotatedEventf(pod, annotations, v1.EventTypeWarning, Reason, evictMsg)// this is a blocking call and should only return when the pod and its containers are killed.klog.V(3).InfoS("Evicting pod", "pod", klog.KObj(pod), "podUID", pod.UID, "message", evictMsg)err := m.killPodFunc(pod, true, &gracePeriodOverride, func(status *v1.PodStatus) {status.Phase = v1.PodFailedstatus.Reason = Reasonstatus.Message = evictMsg})if err != nil {klog.ErrorS(err, "Eviction manager: pod failed to evict", "pod", klog.KObj(pod))} else {klog.InfoS("Eviction manager: pod is evicted successfully", "pod", klog.KObj(pod))}return true
}
killPodFunc对应的就是killPodNow
- 位置 D:\go_path\src\github.com\kubernetes\kubernetes\pkg\kubelet\pod_workers.go
- 调用podworker 执行 UpdatePod
podWorkers.UpdatePod(UpdatePodOptions{Pod: pod,UpdateType: kubetypes.SyncPodKill,KillPodOptions: &KillPodOptions{CompletedCh: ch,Evict: isEvicted,PodStatusFunc: statusFn,PodTerminationGracePeriodSecondsOverride: gracePeriodOverride,},})
- 最终就是调用kubelet的syncPod()方法,把podPhase=Failed更新进去
本节重点总结 :
-
evictionManager初始化了两个相同的manager对象
- evictionManager做本机驱逐pod的判定和厨房
- evictionAdmitHandler用来kubelet创建Pod前进依据本机的资源压力进行准入检查
-
evictionManager判断内存驱逐阈值有两种方法
- 第一种使用内核的memcg的通知机制,更高效
- 当内存使用第一时间达到门槛,会立刻通知kubelet,并触发synchronize()进行资源回收的流程。这样提高了eviction的实时性。
- 第二种使用轮询检查的机制
- 第一种使用内核的memcg的通知机制,更高效
-
优先回收节点资源再驱逐pod
-
驱逐pod调用kubelet的syncPod()方法,把podPhase=Failed更新进去。
相关文章:
9.2 EvictionManager源码解读
本节重点总结 : evictionManager初始化了两个相同的manager对象 evictionManager做本机驱逐pod的判定和厨房evictionAdmitHandler用来kubelet创建Pod前进依据本机的资源压力进行准入检查 evictionManager判断内存驱逐阈值有两种方法 第一种使用内核的memcg的通知机制ÿ…...
考研数一非数竞赛复习之Stolz定理求解数列极限
在非数类大学生数学竞赛中,Stolz定理作为一种强大的工具,经常被用来解决和式数列极限的问题,也被誉为离散版的’洛必达’方法,它提供了一种简洁而有效的方法,使得原本复杂繁琐的极限计算过程变得直观明了。本文&#x…...
整理一下高级设施农业栽培学这门课程的所有知识点
整理一下高级设施农业栽培学这门课程的所有知识点 以下是高级设施农业栽培学这门课程从入门到精通需要学习的知识点: 一、设施农业概述 设施农业的概念与发展历程 了解设施农业的定义、特点及作用,掌握其发展历程、现状与未来趋势。熟悉国内外设施农业…...
2025最新软件测试面试八股文(含答案+文档)
1、请试着比较一下黑盒测试、白盒测试、单元测试、集成测试、系统测试、验收测试的区别与联系。 参考答案: 黑盒测试:已知产品的功能设计规格,可以进行测试证明每个实现了的功能是否符合要求。 白盒测试:已知产品的内部工作过程…...
系统架构设计师—系统架构设计篇—基于体系结构的软件开发方法
文章目录 概述基于体系结构的开发模型-ABSDM体系结构需求体系结构设计体系结构文档化体系结构复审体系结构实现体系结构演化 概述 基于体系结构(架构)的软件设计(Architecture-Based Software Design,ABSD)方法。 AB…...
求最大公约数【C/C++】
大家好啊,欢迎来到本博客( •̀ ω •́ )✧,我将带领大家详细的了解最大公约数的思想与解法。 一、什么是公约数 公约数,也称为公因数,是指两个或多个整数共有的因数。具体来说,如果一个整数能被两个或多个整数整除&…...
Transformer 代码剖析16 - BLEU分数(pytorch实现)
一、BLEU算法全景图 #mermaid-svg-uwjb5mQ2KAC6Rqbp {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-uwjb5mQ2KAC6Rqbp .error-icon{fill:#552222;}#mermaid-svg-uwjb5mQ2KAC6Rqbp .error-text{fill:#552222;stroke:…...
手机屏幕摔不显示了,如何用其他屏幕临时显示,用来导出资料或者清理手机
首先准备一个拓展坞 然后 插入一个外接的U盘 插入鼠标 插入有数字小键盘区的键盘 然后准备一根高清线,一端链接电脑显示器,一端插入拓展坞 把拓展坞的连接线,插入手机充电口(可能会需要转接头) 然后确保手机开机 按下键盘…...
labelimg标注的xml标签转换为yolo格式标签
本文不生产技术,只做技术的搬运工!!! 前言 在yolo训练时,我们需要对图像进行标注,而使用labelimg标注时如果直接选择输出yolo格式的数据集,则原始数据的很多信息无法被保存,因此一版…...
Linux云计算SRE-第十七周
1. 做三个节点的redis集群。 1、编辑redis节点node0(10.0.0.100)、node1(10.0.0.110)、node2(10.0.0.120)的安装脚本 [rootnode0 ~]# vim install_redis.sh#!/bin/bash # 指定脚本解释器为bashREDIS_VERSIONredis-7.2.7 # 定义Redis的版本号PASSWORD123456 # 设置Redis的访问…...
K8S学习之基础十八:k8s的灰度发布和金丝雀部署
灰度发布 逐步扩大新版本的发布范围,从少量用户逐步扩展到全体用户。 特点是分阶段发布、持续监控、逐步扩展 适合需要逐步验证和降低风险的更新 金丝雀部署 将新版本先部署到一小部分用户或服务器,观察其表现,再决定是否全面推广。 特点&…...
WSL with NVIDIA Container Toolkit
一、wsl 下安装 docker 会提示安装 docekr 桌面版,所以直接安装 docker 桌面版本即可 二、安装 NVIDIA Container Toolkit NVIDIA Container Toolkit仓库 https://github.com/NVIDIA/nvidia-container-toolkitgithub.com/NVIDIA/nvidia-container-toolkit 安装…...
PAT线上考试 真题/注意细节(甲/乙级)
闲谈 从此以后!参加竞赛! 都要为自己留够足够的时间练习! 都要为自己留够足够的时间练习! 都要为自己留够足够的时间练习! 重要的事情说三遍,毕竟这只是我参加各种竞赛的开始! \(ÿ…...
springcloud sentinel教程
QPS(Queries Per Second)即每秒查询率 TPS,每秒处理的事务数目 PV(page view)即页面浏览量 UV 访问数(Unique Visitor)指独立访客访问数 一、初识Sentinel 什么是雪崩问题? 微服务之间相…...
摄相机标定的基本原理
【相机标定的基本原理与经验分享】https://www.bilibili.com/video/BV1eE411c7kr?vd_source7c2b5de7032bf3907543a7675013ce3a 相机模型: 定义: 内参:就像相机的“眼睛”。它描述了相机内部的特性,比如焦距(镜头的放…...
HJ C++11 Day2
Initializer Lists 对于一个类P class P{P(int a, int b){cout << "P(int, int), a" << a << ", b " << b << endl;}P(initializer_list<int> initlist){cout << "P(initializer_list<int>), val…...
在 ASP.NET Core 中启用 Brotli 和 Gzip 响应压缩
在本文中,我们将探讨如何在 ASP.NET Core 应用程序中启用响应压缩,重点介绍 Brotli 和 Gzip 算法以及如何验证压缩是否有效。 什么是响应压缩? 响应压缩通过使用Brotli 或 Gzip等算法来最小化 HTTP 响应的大小。这些算法在传输文本资产&#…...
leetcode69.x 的平方根
题目: 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。…...
第11章 web应用程序安全(网络安全防御实战--蓝军武器库)
网络安全防御实战--蓝军武器库是2020年出版的,已经过去3年时间了,最近利用闲暇时间,抓紧吸收,总的来说,第11章开始学习利用web应用程序安全,主要讲信息收集、dns以及burpsuite,现在的资产测绘也…...
flac、kgg、kgma格式音频转换MP3
1. 选择需要转换的音频文件 2. 下载闪电音频格式转换器 闪电音频格式转换器-全面覆盖常见音乐格式_音频合并分割_音频压缩 3. 买会员有点贵,也没必要,偶尔转换一次的,就去闲鱼买,两天会员9块钱。 4. 闲鱼卖家给兑换码,…...
macos 程序 运行
sudo xattr -r -d com.apple.quarantine [/Applications/Name]使用stow 管理配置文件...
基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...
HTML5 表单属性
HTML5 表单属性 引言 HTML5作为新一代的网页标准,带来了许多新的特性和改进。在表单处理方面,HTML5引入了一系列新的表单属性,这些属性使得表单的创建和使用更加灵活和强大。本文将详细介绍HTML5表单属性,包括其功能、使用方法和注意事项。 一、HTML5表单属性概述 HTML…...
从0开始,手搓Tomcat
一、什么是Tomcat Tomcat 是一款开源的、轻量级的 Web 服务器,它不仅能够提供 HTTP 服务,还能够运行 Java Servlet 和 JavaServer Pages(JSP)。对于许多开发者来说,理解 Tomcat 的目录结构以及如何在该结构中组织应用…...
数列分块入门2
题目描述 给出一个长为 n n n 的数列,以及 n n n 个操作,操作涉及区间加法,询问区间内小于某个值 x x x 的元素个数。 输入格式 第一行输入一个数字 n n n。 第二行输入 n n n 个数字,第 i i i 个数字为 a i a_i ai&a…...
【ThreeJS Basics 06】Camera
文章目录 Camera 相机PerspectiveCamera 透视相机正交相机用鼠标控制相机大幅度转动(可以看到后面) 控制组件FlyControls 飞行组件控制FirstPersonControls 第一人称控制PointerLockControls 指针锁定控制OrbitControls 轨道控制TrackballControls 轨迹球…...
postman接口请求中的 Raw是什么
前言 在现代的网络开发中,API 的使用已经成为数据交换的核心方式之一。然而,在与 API 打交道时,关于如何发送请求体(body)内容类型的问题常常困扰着开发者们,尤其是“raw”和“json”这两个术语之间的区别…...
docker1
前言 技术架构 单机架构 应用数据分离架构 应用服务集群架构 读写分离/主从分离架构 写入主的时候,要同步Mysql从的数据才可以 冷热分离架构 写的时候要写入主和缓存数据库 读的时候先去缓存看有没有,没有的话就去从数据库读数据 主要就是看这个数据是…...
RocketMQ延迟消息深度解析:原理、实践与性能调优
RocketMQ延迟消息深度解析:原理、实践与性能调优 编程相关书籍分享:https://blog.csdn.net/weixin_47763579/article/details/145855793 DeepSeek使用技巧pdf资料分享:https://blog.csdn.net/weixin_47763579/article/details/145884039 一、…...
RabbitMQ 高级特性解析:RabbitMQ 消息可靠性保障 (上)
RabbitMQ 核心功能 RabbitMQ 高级特性解析:RabbitMQ 消息可靠性保障 (上)-CSDN博客 RabbitMQ 高级特性:从 TTL 到消息分发的全面解析 (下)-CSDN博客 前言 最近再看 RabbitMQ,看了看自己之前写…...
大白话JavaScript实现一个函数,将数组中的元素进行去重
大白话JavaScript实现一个函数,将数组中的元素进行去重 答题思路 要实现数组元素去重的函数,核心思路是遍历数组,然后判断每个元素是否已经在新数组里存在,如果不存在就添加进去,存在则跳过。下面会介绍几种不同的实…...
PQL查询和监控各类中间件
1 prometheus的PQL查询 1.1 Metrics数据介绍 prometheus监控中采集过来的数据统一称为Metrics数据,其并不是代表具体的数据格式,而是一种统计度量计算单位当需要为某个系统或者某个服务做监控时,就需要使用到 metrics prometheus支持的met…...
uni_app实现下拉刷新
1. 在页面配置中启用下拉刷新 首先,你需要在页面的 pages.json 文件中启用下拉刷新功能。 {"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页","enablePull…...
C#类型转换基本概念
一、基本定义 C# 类型转换是将数据从一种类型转换为另一种类型的过程,分为 隐式转换 和 显式转换 两类。 强类型语言特性:C# 要求变量类型在编译时确定,类型转换需满足兼容性或显式规则。目的:处理不同数据类…...
【学习笔记】【DeepSeek AI 医生】2-2 AI家庭医生课程内容介绍
【DeepSeek AI 医生】2-4 项目详细分析及DeepSeek适用场景 一、Ollama部署二、可视化UI三、构建项目环境四、搭建项目架构五、Spring Al六、SSE服务端推送事件七、数据持久化八、线上部署 一、Ollama部署 Mac部署windows 部署ollama脚本、常用命令DeepSeek 提示词、角色、适用…...
DeepSeek使用教程--让DeepSeek生成精准题库
想让DeepSeek出好题,关键在于提示词的设计。总结了一个基本模板: 请帮我生成一套关于[学科/知识点]的题目,包括[题型],难度为[简单/中等/困难],适合[年级/学习阶段]的学生,总共[数量]道题。每道题请提供详细…...
数学之约数个数定理-阶乘约数
题目: 定义阶乘 n!123⋅⋅⋅n。 请问 100!(100的阶乘)有多少个正约数。 们需要计算 100! 的正约数的个数。阶乘 100! 的定义是: 100!123⋯100 直接计算 100!的值是不现实的,因为它是一个非常大的数。因此…...
C语言学习笔记-进阶(7)字符串函数3
1. strstr的使用和模拟实现 char * strstr ( const char * str1, const char * str2); Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1. (函数返回字符串str2在字符串str1中第⼀次出现的位置&#x…...
快乐数 力扣202
一、题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&…...
Cpu100%问题(包括-线上docker服务以及Arthas方式进行处理)
🍓 简介:java系列技术分享(👉持续更新中…🔥) 🍓 初衷:一起学习、一起进步、坚持不懈 🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏 🍓 希望这篇文章对你有所帮助,欢…...
近三年图像超分辨率研究进展综述(轻量化方向)
一、图像超分辨率技术的近三年核心进展 1. 轻量化网络设计突破 轻量化模型是端侧部署的关键,近三年研究主要围绕参数压缩与计算效率提升展开: 11卷积与通道优化:SCNet提出全11卷积架构,通过逐点卷积替代传统33卷积,在保持重建质量的同时将模型参数减少60%以上。该设计通…...
成都亚恒云知教育咨询公司:绘画的风格如何学习与确定?
宝子们,好久不见! 最近收到好多同学发给我们成都亚恒云知教育咨询有限公司创作的作品,同时也收到了有很多乖乖的询问:关于绘画,老师我没有属于自己的风格,怎么才能画出属于自己的风格的作品啊,…...
数据结构篇——串(String)
一、引入 在计算机中的处理的数据内容大致可分为以整形、浮点型等的数值处理和字符、字符串等的非数值处理。 今天我们主要学习的就是字符串数据。本章主要围绕“串的定义、串的类型、串的结构及其运算”来进行串介绍与学习。 二、串的定义 2.1、串的基本定义 串(s…...
Qwen架构与Llama架构的核心区别
我们在讨论Deepseek不同版本之间的区别时了解到,DeepSeek-R1的蒸馏模型分为Qwen和Llama两个系列,包括Qwen系列的0.5B、1.5B、3B、7B、14B、32B、72B和Llama系列的8B、70B。Qwen系列以阿里通义千问(Qwen)为基础模型架构(具体是Qwen-2.5),Llama系列以Meta的Llama为基础模型…...
uniapp或者vue 使用serialport
参考https://blog.csdn.net/ykee126/article/details/90440499 版本是第一位:否则容易编译失败 node 版本 18.14.0 npm 版本 9.3.1 electron 版本 30.0.8 electron-rebuild 版本 3.2.9 serialport 版本 10.0.0 需要python环境 main.js // Modules to control app…...
Linux和gcc/g++常用命令总结
目录 Linux命令总结 文件操作相关命令 ls cd pwd cp mv rm cat mkdir rmdir touch 文本处理操作命令 grep awk sed 进程管理操作相关命令 ps top htop kill pkill killall chmod chown 网络操作相关命令 ping ifconfig netstat ss lsof curl …...
Vue3路由组件和一般组件 切换路由时组件挂载和卸载 路由的工作模式
路由组件和一般组件 路由组件 一般放到pages或view目录 一般组件 一般放到component目录 切换路由 切换路由时,组件和执行挂载和卸载 路由的工作模式 Hash模式 缺点 1.不美观,路径带#号 优点 1.兼容性好 一般适用于管理系统 History模式 缺点…...
MySQL如何给其他账号分配权限?
目录 基础权限分配流程 权限级别对照表 安全事项 MySQL数据库使用root账号为test账号分配权限的标准操作流程及注意事项: 基础权限分配 1、root用户登录, 输入root密码后进入MySQL命令行环境 mysql -u root -p2、用户存在性校验 SELECT user,host FROM …...
记录一些面试遇到的问题
重载和重写的区别 重载是overload,覆盖是override 重载属于编译时多态,覆盖属于运行时多态 运行时多态和编译时多态 运行时多态指的是在运行的时候才知道要调用哪一个函数,编译时多态是指在编译的时候就知道调用哪一个函数。 运行时多态…...
Windows 系统 Docker Desktop 入门教程:从零开始掌握容器化技术
文章目录 前言一、Docker 简介二、Docker Desktop 安装2.1 系统要求2.2 安装步骤 三、Docker 基本概念四、Docker 常用命令五、实战:运行你的第一个容器5.1 拉取并运行 Nginx 容器5.2 查看容器日志5.3 停止并删除容器 六、总结 前言 随着云计算和微服务架构的普及&…...