🎉在调度的花园里面挖呀挖

上文使用koordinator演示gang-scheduling和binpack调度, 已经生效。

4个2卡Pod龟缩在一个节点,另外一个2卡Pod被挤到另外一个节点(每节点上虚拟gpu:8卡)。

此时我们再尝试申请8卡作业,pod会/* by yours.tools - online tools website : yours.tools/zh/json2get.html */ Pending状态。但一旦节点有资源,pod就会自动进入/* by yours.tools - online tools website : yours.tools/zh/json2get.html */ Running状态

这就是resource.requests/limits 软调度的效果。

1. resource.requests/limits 软调度

上面的调度主要由requests配置来约束。

requests: 是“承诺资源”, kube-scheduler将requests cpu:1 的pod调度到某个node, 就相当于从该node资源池上划走了有一部分资源,这1核会被预定,不再承诺给其他pod,即使你这个pod只用了500m核。

limits: 是资源使用的上限,是由kubelet来强制执行。

2. k8s原生配额ResourceQuota: 硬隔离

当多个团队共享k8s集群节点资源时, 会有某一租户霸占大量资源的可能性。

资源配额就是用来解决这个问题:

资源配额作用在命名空间上(命名空间天生就是多租户概念的载体), 限制了该租户(命名空间)能创建的资源对象(+基础设施资源)的上限, 这个限制是通过api server在资源对象层面做到的。

ResourceQuota 相当于框定某一类资源的可用上限, 有“资源类型”、”配额作用域“ 等过滤资源的选项, 具体请参见ResouceQouta官方。

下面给出一个包含[基础设施资源、扩展资源、资源对象]的ResourceQuota:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-demo
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi   # 需求总量
    limits.cpu: "2"
    limits.memory: 2Gi      # 限额总量
    requests.example.com/dongle: 2
    
    pods: "4"
    replicationcontrollers: "20"
    secrets: "10"
    services: "10"

因为扩展资源不可超量分配,故没有必要为扩展资源同时指定requests和limits配置,只需指定requests.xxxx 即可。

因为配额的准入是在apiserver 资源对象层面, 所以当配额不足,不会产生pod处于pending的现象,kubectl命令会给出报错:pods "quota-mem-cpu-demo-2" is forbidden: exceeded quota, 这点与resource.requests/limits 软调度不同。

提示:
ResourceQuota 与集群资源总量是完全独立的。它们通过绝对的单位来配置。
所以,为集群添加节点时,k8s资源配额不会自动赋予每个命名空间消耗更多资源的能力。

3. kueue 任务队列

上文k8s原生resourceQuota 是命名空间级别的硬资源限制,“它只负责限制, 不负责调度”。

在企业级多租户云环境中,为了①高效②灵活 利用集群资源, 需要“协调和调度”的能力。

kueue 这种任务队列就是这个作用,它不谋求替代k8s原生组件作用,工作在k8s原生调度器之上。

kueue是k8s上管理资源池配额和管控job消费资源池配额的任务队列系统,
kueue决定了job什么时候应该等待,什么时候被准入,什么时候job可以被抢占。

什么时候使用kueue?

① 需要弹性计算资源(可随时扩缩容)

② 计算资源是异构资源(架构、可用性、价格等因素)

这里我用自己的想法协助大家理解这①②点:

kueue中构建的clusterQueue引用的资源池配额是逻辑配额, 资源可以跨队列流动 (借用、抢占), 虽然和k8s原生配额一样都不与硬件资源直接挂钩,但很明显相比k8s原生配额更具弹性。

同构资源指的是所有计算节点/设备规格相同, 异构资源是指计算节点/设备规格/特性不同。

为什么会存在异构资源?
由业务需求驱动产生的不同设备形态(AI/ML工作负载、边缘计算、科学计算等要求的设备种类、设备规格、设备侧重都不同), 衍生出设备价格也不同。


下图是kueue的作用原理。

3.1 资源高度抽象

上面的resource.requests/limits 和k8s原生resourceQuota 都没能跳脱worker 节点资源的概念。

kueue将worker节点上的资源抽象成由特定资源风味(ResourceFlavor)表征的资源池, 框定了某一类含有特定资源类型/规格的节点。

apiVersion: kueue.x-k8s.io/v1beta2
kind: ResourceFlavor
metadata:
  name: "vgpu"
spec:
  nodeLabels:
    instance-type: vgpu

上面名为vgpu的资源风味 框定了带有instance-type=vgpu标签的节点

如果是同构资源,你也可以定义empty resource flavor。


然后基于框定的资源池给某个任务队列分发资源配额。

3.2 资源池的配额 nominalQuota

ClusterQueue 默认是集群级别的对象,定义了集群中某类资源风味的配额。

下面为cluster-queue的全局队列(依托于“default-flavor”资源池)定义了使用配额, 其中为稀缺资源example.com/dongle约束10卡。

命名空间team-a的localQueue引用了该clusterQueue。

apiVersion: kueue.x-k8s.io/v1beta2
kind: ResourceFlavor
metadata:
  name: default-flavor ##  对同构资源,定义empty资源风味
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: ClusterQueue
metadata:
  name: "cluster-queue"
spec:
  namespaceSelector: {} # match all.
  resourceGroups:
  - coveredResources: ["cpu", "memory", "pods"]
    flavors:
    - name: "default-flavor"
      resources:
      - name: "cpu"
        nominalQuota: 10
      - name: "memory"
        nominalQuota: 10Gi
      - name: "example.com/dongle"
        nominalQuota: 10
---
apiVersion: kueue.x-k8s.io/v1beta2
kind: LocalQueue
metadata:
  namespace: team-a 
  name: team-a-queue
spec:
  clusterQueue: cluster-queue 

clusterQueue与localQueue的引用关系实现了共享全局资源池的理念。

形成的对象映射关系如下:


浅绿色是kueue产生的对象,浅蓝色是用户实际提交的批处理任务。


下面用一个k8s原生job来演示 kueue的工作表现。

apiVersion: batch/v1
kind: Job
metadata:
  name: pi3
  labels:
    kueue.x-k8s.io/queue-name: team-a-queue
spec:
  parallelism: 3 # 并行执行次数,默认为1
  completions: 3 # 完成次数,默认为parallelism的值
  suspend: true # 应该在挂起状态下创建job,由kueue来决定何时启动job
  template:
    spec:
      containers:
      - name: pi
        image: perl
        imagePullPolicy: IfNotPresent
        command: [ "perl", "-Mbignum=bpi", "-wle", "print bpi(5000)" ]
        resources:
          requests:
            cpu: "1"
            memory: "200Mi"
            example.com/dongle: "2"
          limits:
            cpu: "1"
            memory: "200Mi"
            example.com/dongle: "2"
      restartPolicy: Never

# Job 代表一次性任务,运行完成到停止,它将π计算到5000个位置并将其打印出来。完成大约需要60秒。 之后pod状态是 Completed
  • 这里最重要的是配置是job中的"suspend:true", job应该以挂起状态被创建,由kueue来决定何时启动。
  • 在原生job标签关联localqueue

提交第一个任务,3个Pod占用了6卡;
再立刻启动同样配置的第二个任务,受localqueue中nominalQuota: 10的约束,任务2会pending,等待任务1执行完,释放了example.com/dongle资源,最后进入runing状态跑完任务。

分别查看任务1和任务2的准入事件:


kueue 还有很多特性,读者自行审阅,修行在个人。

① 核心的clusterqueue默认的排队策略是: BestEffortFIFO: 先按优先级排序,再按照创建时间;未被准入的旧任务不会影响后续能被准入的新来任务。

② 支持队列组Cohort, 可实现资源弹性借用

③ 注意队列组、clusterqueue与资源风味的1对多的关系。

在企业级多租户、强资源生产隔离、计费要求的背景下,一般是独立clusterQueue 与 共享ClusterQueue结合的做法。

4. 总结

今天主要在调度这个花园里面挖呀挖, 更准确的是聚焦在“准入”这个动作上展开思路。

k8s原生资源配额的目的:不是为了优化调度,而是在多租户背景下,约束资源的硬使用边界。
ResourceQuota 框定了命名空间中某些资源的产生上限;

kueue资源池的配额约束了某些细粒度要求的资源池的逻辑边界,通过resourceFalvor抽象出资源池的概念, kueue通过”排队“这个概念细化了准入这个动作,在kube-scheduler工作前管控了批处理任务的调度。

  • https://juejin.cn/post/7327353547313053723#heading-9
  • https://www.infracloud.io/blogs/batch-scheduling-on-kubernetes/

本文来自博客园,作者:{有态度的马甲},转载请注明原文链接:https://www.cnblogs.com/JulianHuang/p/19351159

欢迎关注我的原创技术、职场公众号, 加好友谈天说地,一起进化
本项目构建于RASA开源架构之上,旨在实现一个具备多模态交互能力的智能对话系统。该系统的核心模块涵盖自然语言理解、语音转文本处理以及动态对话流程控制三个主要方。 在自然语言理解层,研究重点集中于增强连续对话中的用户目标判定效能,并运用深度神经网络技术提升关键信息提取的精确度。目标判定旨在解析用户话语背后的真实需求,从而生成恰当的反馈;信息提取则专注于从语音输入中析出具有特定意义的要素,例如个体名称、空间位置或时间节点等具体参数。深度神经网络的应用显著优化了这些功能的实现效果,相比经典算法,其能够解析更为复杂的语言结构,展现出更优的识别精度与更强的适应性。通过分层特征学习机制,这类模型可深入捕捉语言数据中隐含的语义关联。 语音转文本处理模块承担将音频信号转化为结构化文本的关键任务。该技术的持续演进大幅提高了人机语音交互的自然度与流畅性,使语音界日益成为高效便捷的沟通渠道。 动态对话流程控制系统负责维持交互过程的连贯性与逻辑性,包括话轮转换、上下文关联维护以及基于情境的决策生成。该系统需具备处理各类非常规输入的能力,例如用户使用非规范表达或对系统指引产生歧义的情况。 本系统适用于多种实际应用场景,如客户服务支持、个性化事务协助及智能教学辅导等。通过准确识别用户需求并提供对应信息或操作响应,系统能够创造连贯顺畅的交互体验。借助深度学习的自适应特性,系统还可持续优化语言模式理解能力,逐步完善对新兴表达方式与用户偏好的适应机制。 在技术实施方,RASA框架为系统开发提供了基础支撑。该框架专为构建对话式人工智能应用而设计,支持多语言环境并拥有活跃的技术社区。利用其内置工具集,开发者可高效实现复杂的对话逻辑设计与部署流程。 配套资料可能包含补充学习文档、实例分析报告或实践指导手册,有助于使用者深入掌握系统原理与应用方法。技术文档则详细说明了系统的安装步骤、参数配置及操作流程,确保用户能够顺利完成系统集成工作。项目主体代码及说明文件均存放于指定目录中,构成完整的解决方案体系。 总体而言,本项目整合了自然语言理解、语音信号处理与深度学习技术,致力于打造能够进行复杂对话管理、精准需求解析与高效信息提取的智能语音交互平台。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
### 解码 Unicode 字符实体以获取原始文本 在处理包含 HTML 或 XML 等格式的文本时,经常会遇到使用数字字符引用(Numeric Character References, NCR)表示的 Unicode 字符。例如,`flag{...}` 这样的序列实际上代表的是 ASCII 字符 `flag{...}` 的形式。 #### 解码过程 这些字符是以十进制形式表示的 Unicode 码点。每个 `&amp;#x;` 形式的实体代表一个特定的 Unicode 字符。可以通过 Python 中的 `html.unescape()` 函数来解码这些实体[^4]: ```python import html # 示例:解码 Unicode 字符实体 encoded_string = "flag{b7d2431d32c4e0b3a0962b9dd0049b9b}" decoded_string = html.unescape(encoded_string) print(decoded_string) ``` 运行上述代码后,输出结果将是: ``` flag{b7d2431d32c4e0b3a0962b9dd0049b9b} ``` #### 编码与解码机制 - **HTML 实体编码**:在 HTML 中,某些字符(如 `<`, `>`, `&amp;`)具有特殊含义,因此需要通过字符实体(如 `<`, `>`, `&amp;`)进行转义。同样地,任何 Unicode 字符都可以用 `&amp;#xHHHH;`(十六进制)或 `&amp;#DDDD;`(十进制)的形式表示。 - **Python 处理方式**:Python 提供了标准库 `html` 来处理 HTML 实体编码和解码操作。`html.unescape()` 可以将所有 HTML 实体转换回原始字符[^4]。 --- ### 相关问题 1. 如何在 Python 中手动将 Unicode 码点转换为字符? 2. 什么是 HTML 实体编码?它在 Web 开发中有什么作用? 3. 如果输入的字符串包含混合编码(如 UTF-8 和 HTML 实体),应该如何处理? 4. 在 Python 中如何检测字符串是否已经被 HTML 转义? 5. 使用 `html.unescape()` 是否会自动处理其他类型的编码错误?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值