UDF Actor放置策略
scheduling_strategy用于控制UDF Actor的放置策略,支持两种策略类型。
策略1:InstanceSchedulingStrategy实例共置/分散
控制同一查询的多个Actor实例的放置关系:
from aura_frame.ibis.expr.operations.scheduling_strategy import (
InstanceSchedulingStrategy, InstanceAffinityMode
)
# 多实例必须同节点(共享缓存/通信)
InstanceSchedulingStrategy(mode=InstanceAffinityMode.SAME_REQUIRED)
# 多实例必须不同节点(容错/负载均衡)
InstanceSchedulingStrategy(mode=InstanceAffinityMode.DIFF_REQUIRED)
# 优先同节点,允许回退
InstanceSchedulingStrategy(mode=InstanceAffinityMode.SAME_PREFERRED)
# 优先不同节点,允许回退
InstanceSchedulingStrategy(mode=InstanceAffinityMode.DIFF_PREFERRED) from aura_frame.ibis.expr.operations.scheduling_strategy import (
InstanceSchedulingStrategy,
InstanceAffinityMode,
)
# 场景:数据预处理(分散优先)+ 模型推理(必须共置)
# Actor-A 先分发落位,Actor-B 通过相同 label 追踪
# Actor-A:DIFF_PREFERRED 先分发,分散到不同节点
ds = ds.map(
fn="my_schema.preprocess",
on=["raw_col"],
as_col="preprocessed",
scheduling_strategy=InstanceSchedulingStrategy(
mode=InstanceAffinityMode.DIFF_PREFERRED,
label="inference-pipeline",
),
)
# Actor-B:SAME_REQUIRED 追到 Actor-A 所在节点,共享预处理缓存
ds = ds.map(
fn="my_schema.inference",
on=["preprocessed"],
as_col="score",
scheduling_strategy=InstanceSchedulingStrategy(
mode=InstanceAffinityMode.SAME_REQUIRED,
label="inference-pipeline",
),
) 关键点:
- 相同的label:两个Actor必须使用完全相同的label字符串。
- 非REQUIRED先分发:用DIFF_PREFERRED或SAME_PREFERRED的Actor先落位。
- REQUIRED后分发:用SAME_REQUIRED的Actor通过label追过去。
# 优先共置,允许回退——不需要 SAME_REQUIRED 的简单场景 scheduling_strategy=InstanceSchedulingStrategy(mode=InstanceAffinityMode.SAME_PREFERRED),
Label命名规范:
- 最大63个字符
- 必须以字母或数字开头和结尾
- 中间只能使用字母、数字、-、_、.
- 禁止使用保留前缀 actor_
策略2:NodeLabelSchedulingStrategy 节点选择
from aura_frame.ibis.expr.operations.scheduling_strategy import (
NodeLabelSchedulingStrategy, In, NotIn, Exists, DoesNotExist
)
# 硬约束:必须在 pool=gpu 的节点
NodeLabelSchedulingStrategy(hard={"pool": In("gpu")})
# 软约束:优先高带宽节点,不满足时回退
NodeLabelSchedulingStrategy(soft={"high_speed_net": Exists()})
# 组合使用
NodeLabelSchedulingStrategy(
hard={"pool": In("gpu")}, # 必须满足
soft={"high_mem": In("true")}, # 优先满足
) 四个操作符:
| 操作符 | 写法 | 含义 |
|---|---|---|
| In | {"pool": In("gpu", "npu")} | 标签值匹配其中之一 |
| NotIn | {"env": NotIn("test")} | 标签值不在指定范围 |
| Exists | {"npu_type": Exists()} | 标签key存在 |
| DoesNotExist | {"maintenance": DoesNotExist()} | 标签key不存在 |
多Workgroup场景下的调度
集群中同一类型设备(如 GPU)可能被划分为多个workgroup(资源池),每个workgroup在节点上以endpointId作为标签 key 标识,标签value为workgroup名称。当存在多个workgroup时,device="GPU" 等参数只能将Actor调度到GPU类型的节点,但无法区分具体哪个workgroup。
endpointId是Aura endpoint的标识。不同集群的endpointId可能不同,用户可在租户面查看自己的endpointId。
from aura_frame.ibis.expr.operations.scheduling_strategy import (
NodeLabelSchedulingStrategy, InstanceSchedulingStrategy,
InstanceAffinityMode, In,
)
# 指定调度到名为 "gpu-pool-a" 的 GPU workgroup,同时实例分散
# 标签 key 为 endpointId(从租户面获取),value 为 workgroup 名称
ds = ds.map(
fn="my_schema.inference",
on=["feature_col"],
as_col="result",
device="GPU",
model="A100",
num_models=1,
scheduling_strategy=[
NodeLabelSchedulingStrategy(hard={"<endpointId>": In("gpu-pool-a")}),
InstanceSchedulingStrategy(mode=InstanceAffinityMode.DIFF_PREFERRED),
],
) | 来源 | 级别 | 优先级 | 说明 |
|---|---|---|---|
| work_group_name | DDL注册级 | 最高 | CREATE FUNCTION 中指定,内核以LabelInOperator(endpointId, {workgroup_name}) 追加为 AND约束。 |
| NodeLabelSchedulingStrategy | 运行时调用级 | 中 | WITH ARGUMENTS中指定,灵活可变。 |
关键规则:
- work_group_name与scheduling_strategy共存:work_group_name作为AND约束追加到标签列表中(key为endpointId),不会覆盖或清除 scheduling_strategy 的约束。
- 多workgroup必须显式选择:同类型存在多个workgroup时,需要通过NodeLabelSchedulingStrategy或work_group_name指定目标,否则调度结果不可预测。
| 维度 | work_group_name | scheduling_strategy |
|---|---|---|
| 设置时机 | UDF注册时(CREATE FUNCTION) | 查询调用时(WITH ARGUMENTS) |
| 灵活性 | 一次注册,永久生效 | 每次查询可不同 |
| 生效范围 | 该UDF的所有调用 | 仅当前查询 |
| 变更成本 | 需重新注册UDF | 修改代码即可 |
| SQL 层级 | DDL 级 | DML级 |
| 场景 | 推荐做法 |
|---|---|
| UDF始终运行在同一个workgroup | 注册时通过work_group_name指定,避免每次查询重复设置 |
| UDF需要在不同workgroup间切换(灰度、多租户) | 注册时不设置work_group_name,通过scheduling_strategy运行时灵活指定 |