7. 高级编程特性

7.1 容错机制

模块运行错误通常分为两类:

  • 逻辑错误:代码逻辑导致的结果错误;

  • 非逻辑错误:外部软硬件环境异常导致的结果错误;通常在外部环境恢复后,重复多次运行,可解决;

非逻辑错发生有一定的概率,大规模数据处理中,非逻辑错的自动处理,将大大提升数据处理的效率及可靠性。

常见的外部运行环境异常

  • 不稳定的硬件和基础软件

    • 网络设备链路的不稳定

    • 环境温度升高,导致计算节点暂时停止服务

    • 磁盘盘阵中介质不稳定,导致RAID暂时失效

    • 集群存储软件的临时性、可修复的bug

  • 运行中的随机异常

    • 高负载导致核心存储响应延时增加

      • 可变延时(数秒~几分钟)

      • 暂时性不可写入

    • 高负载导致低概率的内存超分,应用内存不足

    • 系统高负载,不合适的调度策略,导致算法运行超时

  • 数据异常

    • 异常输入数据

    • 前导处理软件的随机错误

    • 各类运行异常导致的数据不完整

非逻辑错的容错处理

  • 系统异常的判断与定位

    • 读取/执行/回写的时间

    • 任务返回码

    • 系统监控的异常信息

  • 异常任务的容错处理

    • 自动/人工

7.1.1 模块级容错

  • 设置module的参数retry_rules。 按照算法代码对于非逻辑错的错误,设置主脚本不同的错误码。按返回错误码,在模块定义中设置自动重试,从而实现自动重试。

在Module定义中,设置retry_rules实现以上功能。

    retry_rules: "['91','92:3']"

在以上设置中,若返回码为91,则重试1次;若返回码为92,则重试3次。

返回码是模块运行的结果代码,模块运行出错的返回码就是错误码。

7.1.2 平台级故障及恢复

  • slot启动运行出错,但运行task时很快出错,导致task运行时间短,单位时间内可完成多个task;

  • module的max_tasks_per_minutes参数(取值>=3),在超出该参数时,将对应slot设置为’ERROR’,以免干扰其他task的正常等待;

  • 再结合retry_rules,即可在有大量slot运行错的情况下,停止有问题的slot运行;

  • 最后,可以再通过手工恢复。

7.1.3 跨模块容错

  • 基于vtask

  • 在任务中增加用于管理的任务头,实现基于vtask的管理(删除?)

  • 清理vtask中设计的task、semaphore、variable等

容错分级

  • task级:基于退出码的重试机制。vtask内的task重试,需要调整vtask状态。尽可能在task级恢复。

  • slot级:

  • vtask级:节点本地计算模式下,保证最终的幂等性。vtask层保持强一致性。

    • vtask内的task,重试,需要调整vtask状态

    • 部分出错(节点退出),只能在vtask级恢复。

7.2 准入控制机制

准入控制(Admission Control)

本地计算本地资源受限,需引入准入控制,避免本地节点的关键资源(内存容量、磁盘空间大小)超载。 对于复杂应用程序的本地计算,高级准入控制可大大简化业务逻辑,避免运行异常。

算法模块的准入控制,就是控制流式数据处理的进度,以免数据处理所需不可共享的核心计算资源(内存缓存、GPU显存、本地磁盘空间)超过本地资源的物理限额,导致计算异常中断,包括运行异常退出、程序死锁等。

流量控制的实现机制是在消息处理前,通过模块的标准流控规则、自定义流控规则检查是否符合外部条件,若不符合,则在代码中显式调用sleep(),等待一段时间后再做检查。经过多次检查未果,则退出模块运行。

流控规则通过引入等待机制,降低了局部计算资源的利用率,但从整体上保证应用程序的顺利执行。 避免内存空间的峰值需求,以增加等待时间为代价,在低内存配置的机器上运行本地计算的应用。

流控分为slot级流控、node间并行同步流控。 流控支持模块运行的同步,以免系统资源受限而导致运行异常。

精准控制数据输出,若数据空间不满足,等待其他并行任务完成后释放资源,清理出空间,待空间容量满足要求后再继续运行。

7.2.1 准入控制分类

7.2.1.1 task addmission

  • 规则型准入控制:Rule-based Admission Control

    • 存储容量准入控制(Storage Capacity Admission Control)

    • 计数型准入控制(Counter-based Admission Control)

  • 自定义准入控制:Custom Admission Control

7.2.1.2 slot addmission

可以启动多少个slot?

7.2.2 存储容量准入控制

(Storage Capacity Admission Control)

7.2.2.1 目录最大占用空间流控

  • 标准属性名:dir_quota_gb,通过限制目录的最大占用存储空间来实现流控。

7.2.2.2 目录分区最少空余空间

  • 标准流控属性:space_free_gb,通过限制目录所在存储分区的最小空余空间实现流控

7.2.3 vtask计数准入控制

  • 标准流控属性vtask_size

    • 理解为可运行task的最大数量

    • 若基于vtask框架,在vtask-head模块中,计数器减一,在vtask-tail模块中,计数器加一

    • 若在独立模块中,计数器减一。需在主路由中,手工完成计数器加一操作。

启用vtask的模块,在task启动时将计数器自动减一,若计数器值<=0,则计数流控生效,新task不能运行。从实现上看,vtask机制设置了等待队列长度。

后续模块的任务处理完成后,在主路由中自动恢复vtask计数器。也可对计数器手工操作,实现启停。

  • 处理过程

    • 在模块入口处,检查信号量计数器值,若<=0,表示无运行槽位,准入控制不通过;

    • 主路由对该计数值自动减一,占用一个运行槽位。该操作自动完成,不需要编程控制;

    • vtask处理完成,则在对应消息路由中,通过信号量操作,对计数值加一,释放一个空槽位。

SLOT-BOUND模块

  • 生成对应信号量:slot_vtask_size:${mod_name}:${slot_id},其初值为参数值。

    • mod_name为首模块名

    • slot_id为SLOT的ID

  • 计算槽上最多可运行的vtask数量,通常表示计算节点组上运行队列的长度。

HOST-BOUND模块

  • 生成对应信号量:host_vtask_size:${mod_name}:${hostname},其初值为参数值。

    • mod_name为首模块名

    • hostname为t_host表中的hostname

  • 计算节点上最多可运行的vtask数量,表示节点上运行队列的长度。

缺省类型模块

  • 生成对应信号量:vtask_size:${mod_name},其初值为参数值。

    • mod_name为首模块名

  • 全局范围内最多可运行的vtask数量,表示节点上运行队列的长度。

7.2.4 节点组并行同步准入控制

  • 标准流控属性node_progress_gap

    • 按节点的进度计数器,基于同步信号量实现

    • node_progress_diff:当前节点进度与最慢进度的差值作为控制变量

  • 主路由中,按task处理进度,修改对应信号量;

  • 业务模块基于信号量计数值,实现同步流控;

7.2.5 task级自定义准入控制

  • 代码定制流控(可基于信号量)

    • ACTION_CHECK/check.sh:自定义流控逻辑

7.3 关键模块的任务运行排序

task运行排序是scalebox应用运行的重要基础。

对于多节点协同处理的模块来说,排序可将同一时段上所有数据在不同计算资源上并行运行,以在后续模块中做协同(分组等)。

通过设置以下参数,实现排序。

7.3.1 排序标签

消息头中sort_tag,是用于消息排序的专用标签,具有最高高优先级,通常由main-router设置

7.3.2 任务分组号

  • group_regex:正则表达式,从任务体中提取相关分组字符串。

  • group_index:正则表达式对应的分组编号。

7.3.3 任务处理顺序

若未设置前述排序方式,则缺省按任务生成的顺序进行处理

  • 幂等性:节点本地计算存在节点失败的可能性,导致本地存储失效,无法保证task级的幂等性,在跨模块的vtask层级上实现幂等性。

7.4 超时设置(timeout)

由于代码的bug、数据错误等原因,可能导致算法模块进入死循环,一直占用slot运行,无法正常退出。

超时设置可以解决以上问题。通过设置module的task_max_seconds参数,在超出该时限后,该任务(task)会退出运行,返回错误码 124.

在封装脚本调用算法代码时,建议也在封装脚本中加入timeout的相关设置。若无此设置,外层脚本timeout,内层脚本还会运行结束,导致不确定的结果。 若算法代码名为run.py,则封装代码中对应部分可写成:

timeout ${TASK_TIMEOUT_SECONDS}s run.py $*

7.4 task-perspective

  • scalebox标准时间格式 2023-10-24T18:00:00.123456+0800

  • bash生成当前时间

date +"%Y-%m-%dT%H:%M:%S.%6N%z"
  • golang生成当前时间

formattedTime := time.Now().Format("2006-01-02T15:04:05.999999")
fmt.Println(formattedTime)
  • python生成当前时间


7.5 git应用代码库

7.6 跨集群应用

7.7 slot启动命令表达式

支持 (( )) 定界符的表达式,在slot启动时,再按外部环境,动态求解表达式,得到最终的启动命令。适用于以下场景:

  • 单节点多GPU卡,需通过不同命令启动不同GPU卡对应的slot

  • 在准入控制规则中,需以slot序号为变量,精准定义存储容量上限,保证资源充分利用。

7.7.1 变量类型

表达式中,变量名用@开头,分为数值型变量、字符串变量。

数值型变量(slot序号)

每个模块,针对每个节点,有一个从0计数的序号,可用于slot启动命令表达式,实现对不同slot序号用不同的启动命令。

@seq标识计数序号

字符串变量(global变量)

按全局变量值,解析最终slot命令,可指定镜像名版本号

@v:var_name标识字符串变量

7.7.2 slot序号变量示例

单个计算节点可配置多个GPU加速卡。通常为每个GPU配置独立的slot,模块算法不需针对多GPU卡做并行优化,这样配置通常也更具高运行效率。 在这种场景下,不同GPU需要用不同的slot启动命令。 slot启动命令支持参数化配置。

应用定义

  beam-make:
    command: ${ROCM_COMMAND}
    arguments:
      free_space_gb: '{"${LOCAL_SHMDIR}":${BEAM_MAKE_FREE_GB}}'

准入控制参数定义

LOCAL_SHMDIR=/dev/shm/scalebox/mydata
BEAM_MAKE_FREE_GB='((@seq*5+11))'

singularity多GPU配置命令

ROCM_COMMAND='singularity exec --rocm --env ROCR_VISIBLE_DEVICES=((@seq)) {{ENVS}} {{VOLUMES}} {{IMAGE}} goagent'

docker多GPU配置命令1

ROCM_COMMAND='docker run -d --rm --network host --tmpfs=/work --device=/dev/kfd --device=/dev/dri --security-opt seccomp=unconfined --group-add video -e ROCR_VISIBLE_DEVICES=((@seq)) {{ENVS}} {{VOLUMES}} {{IMAGE}}'

docker多GPU配置命令2

docker run -d --rm --network=host --tmpfs=/work --device=/dev/kfd --device=/dev/dri/card((@seq%2)) --device=/dev/dri/renderD((n%2+128)) --security-opt seccomp=unconfined --group-add video --cap-add=SYS_PTRACE {{ENVS}} {{VOLUMES}} {{IMAGE}}

7.7.3 global变量示例

  my-module:
    base_image: my-image:(($v:pipeline_version))

在global中定义全局变量 pipeline_version20260411,则在启动时,实际镜像名为my-image:20260411

scalebox global set pipeline_version 20260411

7.9 slot自动扩缩容

7.9.1 概述

Slot 自动扩缩容根据资源使用情况自动调整任务执行槽数量,通过监控主机资源使用率智能决策扩容或缩容,优化资源利用率和任务执行效率。

7.9.2 功能特性

  • 自动监控:定期检查主机资源使用情况

  • 智能决策:基于使用率阈值自动决定扩容/缩容

  • 双重策略:支持资源紧张扩容和容量不足扩容

  • 安全保护:防止过度扩缩容,内置冷却机制确保系统稳定

7.9.3 配置参数

在模块参数中设置以下关键配置项:

{
  "autoscaling.enabled": "true",
  "autoscaling.min_slots": "1",
  "autoscaling.max_slots": "10",
  "autoscaling.scale_up_threshold": "0.8",
  "autoscaling.scale_down_threshold": "0.3",
  "autoscaling.scale_up_step": "2",
  "autoscaling.scale_down_step": "1"
}

7.9.4 扩缩容策略

扩容触发条件

  1. 资源紧张扩容:当资源使用率超过扩容阈值(默认80%)时

  2. 容量不足扩容:当当前slot数量低于最大可用容量的阈值比例时

缩容触发条件

  1. 资源闲置缩容:当资源使用率低于缩容阈值(默认30%)时

  2. 超量运行缩容:当slot数量超过物理容量时强制缩容

7.9.5 资源指标要求

系统需要三类资源指标配合工作:

  • 主机总资源(total.*):主机配置中的总资源定义

  • 主机已使用资源(used.*):外部监控系统定时更新的使用数据

  • Slot资源需求(slot_req.*):模块配置中每个slot的资源需求

三类指标需要保持相同的key名称和单位一致性。

7.9.6 使用示例

# 正常扩容场景
初始状态:slot=3,最大可用=10,使用率=90%
结果:触发扩容2个slot(使用率>80%且当前<最大容量×80%)

# 正常缩容场景  
初始状态:slot=8,最大可用=10,使用率=20%
结果:触发缩容1个slot(使用率<30%)

# 超量运行缩容
初始状态:slot=5,最大可用=1
结果:强制缩容到物理容量内