更新时间:2026-07-03 GMT+08:00
分享

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)
SAME_REQUIRED首次分发限制:首次分发时pod上不存在同查询已分发实例标签,无法满足required约束,会返回ERROR。仅在多个Actor按序分发时有效。生产推荐SAME_PREFERRED或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_PREFERRED即可,无需自定义label:
# 优先共置,允许回退——不需要 SAME_REQUIRED 的简单场景
scheduling_strategy=InstanceSchedulingStrategy(mode=InstanceAffinityMode.SAME_PREFERRED),

Label命名规范:

  • 最大63个字符
  • 必须以字母或数字开头和结尾
  • 中间只能使用字母、数字、-、_、.
  • 禁止使用保留前缀 actor_

策略2:NodeLabelSchedulingStrategy 节点选择

基于Kubernetes节点标签,约束Actor放置位置:
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。

通过NodeLabelSchedulingStrategy可以在运行时指定目标workgroup
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),
    ],
)
表1 workgroup调度的优先级和共存规则

来源

级别

优先级

说明

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指定目标,否则调度结果不可预测。
表2 注册时与运行时:两种设置方式的差异

维度

work_group_name

scheduling_strategy

设置时机

UDF注册时(CREATE FUNCTION)

查询调用时(WITH ARGUMENTS)

灵活性

一次注册,永久生效

每次查询可不同

生效范围

该UDF的所有调用

仅当前查询

变更成本

需重新注册UDF

修改代码即可

SQL 层级

DDL 级

DML级

表3 选型建议

场景

推荐做法

UDF始终运行在同一个workgroup

注册时通过work_group_name指定,避免每次查询重复设置

UDF需要在不同workgroup间切换(灰度、多租户)

注册时不设置work_group_name,通过scheduling_strategy运行时灵活指定

相关文档