特性介绍
Pod CPU 优先级
rubik 支持业务 CPU 优先级配置,针对在/离线业务混合部署的场景,确保在线业务相对离线业务的 CPU 资源抢占。
前置条件:
- 建议使用 openEuler-22.03以上版本。在上述版本中内核支持针对 cgroup 的 cpu 优先级配置,即 cpu 子系统存在接口 cpu.qos_level。
CPU 优先级内核接口
- /sys/fs/cgroup/cpu 目录下容器的 cgroup 中,如
/sys/fs/cgroup/cpu/kubepods/burstable/<PodUID>/<container-longid>
目录- cpu.qos_level:开启 CPU 优先级配置,默认值为 0, 有效值为 0 和-1。
- 0:标识为在线业务
- -1:标识为离线业务
- cpu.qos_level:开启 CPU 优先级配置,默认值为 0, 有效值为 0 和-1。
CPU 优先级配置详解
rubik 会根据 Pod 的 yaml 文件中的注解volcano.sh/preemptable
自动配置 cpu.qos_level, 默认为 false。
annotations:
volcano.sh/preemptable: true
- true:代表业务为离线业务
- false:代表业务为在线业务
Pod 内存优先级
rubik 支持业务 memory 优先级配置,针对在/离线业务混合部署的场景,确保 OOM 时优先 kill 离线业务。
前置条件:
- 建议使用 openEuler-22.03以上版本。在上述版本的内核中支持针对 cgroup 的 memory 优先级配置,即 memory 子系统存在接口 memory.qos_level。
- 开启内存优先级支持:
echo 1 > /proc/sys/vm/memcg_qos_enable
内存优先级内核接口
/proc/sys/vm/memcg_qos_enable:开启内存优先级特性,默认值为 0,有效值为 0 和 1。开启命令为:
echo 1 > /proc/sys/vm/memcg_qos_enable
- 0:表示关闭特性
- 1:表示开启特性。
/sys/fs/cgroup/memory 目录下容器的 cgroup 中,如
/sys/fs/cgroup/memory/kubepods/burstable/<PodUID>/<container-longid>
目录- memory.qos_level:开启内存优先级配置,默认值为 0,有效值为 0 和-1。
- 0:标识为在线业务
- -1:标识为离线业务
- memory.qos_level:开启内存优先级配置,默认值为 0,有效值为 0 和-1。
内存优先级配置详解
rubik 会根据 Pod 的 yaml 文件中的注解volcano.sh/preemptable
自动配置 memory.qos_level,参考CPU 优先级配置详解
dynCache 访存带宽和 LLC 限制
rubik 支持业务的 Pod 访存带宽(memory bandwidth)和 LLC(Last Level Cache)限制,通过限制离线业务的访存带宽/LLC 使用,减少其对在线业务的干扰。
前置条件:
cache/访存限制功能仅支持物理机,不支持虚拟机。
- x86 物理机,需要 OS 支持且开启 intel RDT 的 CAT 和 MBA 功能,内核启动项 cmdline 需要添加
rdt=l3cat,mba
- ARM 物理机,需要 OS 支持且开启 mpam 功能,内核启动项需要添加
mpam=acpi
。
- x86 物理机,需要 OS 支持且开启 intel RDT 的 CAT 和 MBA 功能,内核启动项 cmdline 需要添加
由于内核限制,RDT mode 当前不支持 pseudo-locksetup 模式。
rubik 新增权限和目录:
- 挂载目录:
/sys/fs/resctrl
。 rubik 需要读取和设置/sys/fs/resctrl 目录下的文件,该目录需在 rubik 启动前挂载,且需保障在 rubik 运行过程中不被卸载。 - 权限:SYS_ADMIN. 设置主机/sys/fs/resctrl 目录下的文件需要 rubik 容器被赋有 SYS_ADMIN 权限。
- namepsace: pid namespace. rubik 需要获取业务容器进程在主机上的 pid,所以 rubik 容器需与主机共享 pid namespace。
rubik rdt 控制组:
rubik 在 RDT resctrl 目录(默认为 /sys/fs/resctrl)下创建 5 个控制组,分别为 rubik_max、rubik_high、rubik_middle、rubik_low、rubik_dynamic。rubik 启动后,将水位线写入对应控制组的 schemata。其中,low、middle、high 的水位线可在 cacheConfig 中配置;max 控制组为默认最大值,dynamic 控制组初始水位线和 low 控制组一致。
离线业务 Pod 启动时通过注解volcano.sh/cache-limit
设置其 cache level,并被加入到指定的控制组中,如下列配置的 Pod 将被加入 rubik_low 控制组:
annotations:
volcano.sh/cache-limit: "low"
rubik dynamic 控制组:
当存在 level 为 dynamic 的离线 Pod 时,rubik 通过采集当前节点在线业务 Pod 的 cache miss 和 llc miss 指标,调整 rubik_dynamic 控制组的水位线,实现对 dynamic 控制组内离线应用 Pod 的动态控制。
dynCache 内核接口
- /sys/fs/resctrl: 在该目录下创建 5 个控制组目录,并修改其 schemata 和 tasks 文件。
dynCache 配置详解
dynCache 功能相关的配置在cacheConfig
中:
"cacheConfig": {
"enable": false,
"defaultLimitMode": "static",
"adjustInterval": 1000,
"perfDuration": 1000,
"l3Percent": {
"low": 20,
"mid": 30,
"high": 50
},
"memBandPercent": {
"low": 10,
"mid": 30,
"high": 50
}
},
l3Percent 和 memBandPercent: 通过 l3Percent 和 memBandPercent 配置 low, mid, high 控制组的水位线。
比如当环境的
rdt bitmask=fffff, numa=2
时,rubik_low 的控制组将根据 l3Percent low=20 和 memBandPercent low=10 两个参数,将为/sys/fs/resctrl/rubik_low 控制组配置:L3:0=f;1=f MB:0=10;1=10
defaultLimitMode: 如果离线 Pod 未指定
volcano.sh/cache-limit
注解,将根据 cacheConfig 的 defaultLimitMode 来决定 Pod 将被加入哪个控制组:- defaultLimitMode 为 static 时,Pod 将被加入到 rubik_max 控制组
- defaultLimitMode 为 dynamic 时,Pod 将被加入到 rubik_dynamic 控制组
adjustInterval: dynCache 动态调整 rubik_dynamic 控制组的间隔时间,单位 ms,默认 1000ms
perfDuration: dynCache 性能 perf 执行时长,单位 ms,默认 1000ms
dynCache 注意事项
- dynCache 仅针对离线 Pod,对在线业务不生效。
- 若业务容器运行过程中被手动重启(容器 ID 不变但容器进程 PID 变化),针对该容器的 dynCache 无法生效。
- 业务容器启动并已设置 dynCache 级别后,不支持对其限制级别进行修改。
- 动态限制组的调控灵敏度受到 rubik 配置文件内 adjustInterval、perfDuration 值以及节点在线业务 Pod 数量的影响,每次调整(若干扰检测结果为需要调整)间隔在区间【adjustInterval+perfDuration, adjustInterval+perfDuration*Pod 数量】内波动,用户可根据灵敏度需求调整配置项。
blkio
Pod 的 blkio 的配置以volcano.sh/blkio-limit
注解的形式,在 Pod 创建的时候配置,或者在 Pod 运行期间通过 kubectl annotate 进行动态的修改,支持离线和在线 Pod。
配置内容为 4 个列表:
项 | 说明 |
---|---|
device_read_bps | 用于设定设备执行“读”操作字节的上限。该配置为 list,可以对多个 device 进行配置,device 指定需要限制的块设备,value 限定上限值,单位为 byte |
device_read_iops | 用于设定设备执行“读”操作次数的上限。该配置为 list,可以对多个 device 进行配置,device 指定需要限制的块设备 |
device_write_bps | 用于设定设备执行 “写” 操作次数的上限。该配置为 list,可以对多个 device 进行配置,device 指定需要限制的块设备,value 限定上限值,单位为 byte |
device_write_iops | 用于设定设备执行“写”操作字节的上限。该配置为 list,可以对多个 device 进行配置,device 指定需要限制的块设备 |
blkio 内核接口
- /sys/fs/cgroup/blkio 目录下容器的 cgroup 中,如
/sys/fs/cgroup/blkio/kubepods/burstable/<PodUID>/<container-longid>
目录:- blkio.throttle.read_bps_device
- blkio.throttle.read_iops_device
- blkio.throttle.write_bps_device
- blkio.throttle.write_iops_device
配置的 key:value 和 cgroup 的 key:value 的配置规则一致:
- 写入时会转换成环境 page size 的倍数
- 只有 minor 为 0 的 device 配置才会生效
- 如果取消限速,可将值设为 0
blkio 配置详解
rubik 开启关闭 blkio 功能:
rubik 提供 blkio 配置功能的开关,在blkioConfig
中
"blkioConfig": {
"enable": true
}
- enable: IO 控制模块使能开关, 默认为 false
Pod 配置样例:
通过 Pod 的注解配置时可提供四个列表,分别是 write_bps, write_iops, read_bps, read_iops, read_byte.
创建时:在 yaml 文件中
volcano.sh/blkio-limit: '{"device_read_bps":[{"device":"/dev/sda1","value":"10485760"}, {"device":"/dev/sda","value":"20971520"}], "device_write_bps":[{"device":"/dev/sda1","value":"20971520"}], "device_read_iops":[{"device":"/dev/sda1","value":"200"}], "device_write_iops":[{"device":"/dev/sda1","value":"300"}]}'
修改 annotation: 可通过 kubectl annotate 动态修改,如:
kubectl annotate --overwrite pods <podname> volcano.sh/blkio-limit='{"device_read_bps":[{"device":"/dev/vda", "value":"211715200"}]}'
memory
rubik 中支持多种内存策略。针对不同场景使用不同的内存分配方案,以解决多场景内存分配。
dynlevel 策略:基于内核 cgroup 的多级别控制。通过监测节点内存压力,多级别动态调整离线业务的 memory cgroup,尽可能地保障在线业务服务质量。
fssr 策略:基于内核 cgroup 的动态水位线控制。memory.high 是内核提供的 memcg 级的水位线接口,rubik 动态检测内存压力,动态调整离线应用的 memory.high 上限,实现对离线业务的内存压制,保障在线业务的服务质量。
memory dynlevel 策略内核接口
/sys/fs/cgroup/memory 目录下容器的 cgroup 中,如
/sys/fs/cgroup/memory/kubepods/burstable/<PodUID>/<container-longid>
目录。dynlevel 策略会依据当前节点的内存压力大小,依次调整节点离线应用容器的下列值:- memory.soft_limit_in_bytes
- memory.force_empty
- memory.limit_in_bytes
- /proc/sys/vm/drop_caches
memory dynlevel 策略配置详解
rubik 提供 memory 的指定策略和控制间隔,在memoryConfig
中
"memoryConfig": {
"enable": true,
"strategy": "none",
"checkInterval": 5
}
enable 为是否打开该配置的开关
strategy 为 memory 的策略名称,现支持 dynlevel/fssr/none,默认为 none。
- none: 即不设置任何策略,不会对内存进行调整。
- dynlevel: 动态分级调整策略。
- fssr: 快压制慢恢复策略。1)rubik 启动时,默认配置所有离线的 memory.high 为总内存的 80%。2)当内存压力增加,可用内存 freeMemory < reservedMemory(预留内存,totalMemory * 5%) 时认为内存紧张,此时压缩所有离线的 memory.high, 压缩量为总内存的 10%,即最新的 memory.high=memory.high-totalMemory * 10%。3)当持续一段时间总内存比较富裕,即可用内存 freeMemory > 3 * reservedMemory(totalMemory * 5%)时认为内存富裕,此时释放总内存的 1%给离线应用,memory.high=memory.high+totalMemory * 1%, 直到 memory free 介于 reservedMemory 与 3 * reservedMemory 之间。
checkInterval 为策略的周期性检查的时间,单位为秒,默认为 5。
memory fssr 策略内核接口
- /sys/fs/cgroup/memory 目录下容器的 cgroup 中,如
/sys/fs/cgroup/memory/kubepods/burstable/<PodUID>/<container-longid>
目录。fssr 策略会依据当前节点的内存压力大小,依次调整节点离线应用容器的下列值: - memory.high
memory fssr 策略配置详解
rubik 提供 memory 的指定策略和控制间隔,在memoryConfig
中
"memoryConfig": {
"enable": true,
"strategy": "fssr",
"checkInterval": 5
}
enable 为是否打开该配置的开关
strategy 为 memory 的策略名称,现支持 dynlevel/fssr/none 两个选项,默认为 none。
- none: 即不设置任何策略,不会对内存进行调整。
- dynlevel: 动态分级调整策略。
- fssr: 快压制慢恢复策略。1)rubik 启动时,默认配置所有离线的 memory.high 为总内存的 80%。2)当内存压力增加,可用内存 freeMemory < reservedMemory(预留内存,totalMemory * 5%) 时认为内存紧张,此时压缩所有离线的 memory.high, 压缩量为总内存的 10%,即最新的 memory.high=memory.high-totalMemory * 10%。3)当持续一段时间总内存比较富裕,即可用内存 freeMemory > 3 * reservedMemory(totalMemory * 5%)时认为内存富裕,此时释放总内存的 1%给离线应用,memory.high=memory.high+totalMemory * 1%, 直到 memory free 介于 reservedMemory 与 3 * reservedMemory 之间。
checkInterval 为策略的周期性检查的时间,单位为秒,默认为 5。
quota burst
Pod 的 quota burst 的配置以volcano.sh/quota-burst-time
注解的形式,在 Pod 创建的时候配置,或者在 Pod 运行期间通过 kubectl annotate 进行动态的修改,支持离线和在线 Pod。
Pod 的 quota burst 默认单位是 microseconds, 其允许容器的 cpu 使用率低于 quota 时累积 cpu 资源,并在 cpu 利用率超过 quota 时,使用容器累积的 cpu 资源。
quota burst 内核接口
/sys/fs/cgroup/cpu 目录下容器的 cgroup 中,如
/sys/fs/cgroup/cpu/kubepods/burstable/<PodUID>/<container-longid>
目录,注解的值将被写入下列文件中:- cpu.cfs_burst_us
注解
volcano.sh/quota-burst-time
的值和 cpu.cfs_burst_us 的约束一致:- 当 cpu.cfs_quota_us 不为-1,需满足 cpu.cfs_burst_us + cpu.cfs_quota_us <= 2^44-1 且 cpu.cfs_burst_us <= cpu.cfs_quota_us
- 当 cpu.cfs_quota_us 为-1,cpu.cfs_burst_us 最大没有限制,取决于系统最大可设置的值
Pod 配置样例
创建时:在 yaml 文件中
metadata: annotations: volcano.sh/quota-burst-time : "2000"
修改 annotation: 可通过 kubectl annotate 动态修改,如:
kubectl annotate --overwrite pods <podname> volcano.sh/quota-burst-time='3000'
基于 iocost 的 io 权重控制
依赖说明
rubik 支持通过在 cgroup v1 下的 iocost 控制不同 Pod 的 io 权重分配。因此需要内核支持如下特性:
- 内核支持 cgroup v1 blkcg iocost
- 内核支持 cgroup v1 writeback
rubik 实现说明
步骤如下
- 部署 rubik 时,rubik 解析配置并设置 iocost 相关参数
- rubik 注册检测事件到 k8s api-server
- Pod 被部署时将 Pod 配置信息等回调到 rubik
- rubik 解析 Pod 配置信息,并根据 qos level 配置 Pod iocost 权重
rubik 协议说明
"nodeConfig": [
{
"nodeName": "slaver01",
"iocostEnable": true,
"iocostConfig": [
{
"dev": "sda",
"enable": false,
"model": "linear",
"param": {
"rbps": 174610612,
"rseqiops": 41788,
"rrandiops": 371,
"wbps": 178587889,
"wseqiops": 42792,
"wrandiops": 379
}
}
]
}
]
配置项 | 类型 | 说明 |
---|---|---|
nodeConfig | 数组 | node 节点配置信息 |
nodeName | string | 要配置的节点名称 |
iocostEnable | bool | 该 node 节点是否使用 iocost |
iocostConfig | 数组 | 针对不同物理磁盘的配置数组,当 iocostEnable 为 true 时会被读取 |
dev | string | 物理磁盘名称 |
enable | bool | 该物理磁盘是否启用 iocost |
model | string | iocost 的模型名称,linear 为内核自带线性模型 |
param | object | 该参数针对 model 参数配置,当 model 为 linear 时,下面的参数都是 linear 相关参数 |
r(w)bps | int64 | 该物理块设备最大读(写)带宽 |
r(w)seqiops | int64 | 该物理块设备最大顺序读(写)iops |
r(w)randiops | int64 | 该物理块设备最大随机读(写)iops |
其他
iocost linear 模型相关参数可以通过 iocost_coef_gen.py 脚本获取,可以从link获得。
在 blkcg 根系统文件下存在
blkio.cost.qos
和blkio.cost.model
两个文件接口。实现方式和接口说明可以访问 openEuler 内核文档。