自学内容网 自学内容网

从automaxprocs库浅窥Linux容器的资源控制

automaxprocs能够自动调整Go程序中的Goroutine数量,以充分利用系统资源并提高程序的性能。

automaxprocs通过读取系统信息,如CPU核心数和Cgroups限制,来动态调整Goroutine的数量

automaxprocs获取CPU限额的关键方法在

// CPUQuotaToGOMAXPROCS converts the CPU quota applied to the calling process
// to a valid GOMAXPROCS value. The quota is converted from float to int using round.
// If round == nil, DefaultRoundFunc is used.
func CPUQuotaToGOMAXPROCS(minValue int, round func(v float64) int) (int, CPUQuotaStatus, error) {
if round == nil {
round = DefaultRoundFunc
}
cgroups, err := _newQueryer()
if err != nil {
return -1, CPUQuotaUndefined, err
}

quota, defined, err := cgroups.CPUQuota()
if !defined || err != nil {
return -1, CPUQuotaUndefined, err
}

maxProcs := round(quota)
if minValue > 0 && maxProcs < minValue {
return minValue, CPUQuotaMinUsed, nil
}
return maxProcs, CPUQuotaUsed, nil
}

可以看到是先获取到cgroup的实现,然后调用实现方法获取限制

获取cgroup2实现如下

func newCGroups2From(mountInfoPath, procPathCGroup string) (*CGroups2, error) {
  // 检查是否是cgroup2
  // 通过/proc/self/mountinfo中文件系统类型是否为cgroup2或者挂载点在/sys/fs/cgroup
isV2, err := isCGroupV2(mountInfoPath)
if err != nil {
return nil, err
}

if !isV2 {
return nil, ErrNotV2
}

  // 从/proc/self/cgroup解析子系统对应的cgroup
subsystems, err := parseCGroupSubsystems(procPathCGroup)
if err != nil {
return nil, err
}

// Find v2 subsystem by looking for the `0` id
  // 找到v2子系统
var v2subsys *CGroupSubsys
for _, subsys := range subsystems {
if subsys.ID == 0 {
v2subsys = subsys
break
}
}

if v2subsys == nil {
return nil, ErrNotV2
}

return &CGroups2{
mountPoint: _cgroupv2MountPoint,
groupPath:  v2subsys.Name,
cpuMaxFile: _cgroupv2CPUMax,
}, nil
}

具体算限制方法如下

其实就是取cpu.max文件中指定的限额

// CPUQuota returns the CPU quota applied with the CPU cgroup2 controller.
// It is a result of reading cpu quota and period from cpu.max file.
// It will return `cpu.max / cpu.period`. If cpu.max is set to max, it returns
// (-1, false, nil)
func (cg *CGroups2) CPUQuota() (float64, bool, error) {
  // 打开/sys/fs/cgroup下对应cgroup的cpu.max文件
cpuMaxParams, err := os.Open(path.Join(cg.mountPoint, cg.groupPath, cg.cpuMaxFile))
if err != nil {
if os.IsNotExist(err) {
return -1, false, nil
}
return -1, false, err
}
defer cpuMaxParams.Close()

scanner := bufio.NewScanner(cpuMaxParams)
if scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) == 0 || len(fields) > 2 {
return -1, false, fmt.Errorf("invalid format")
}

if fields[_cgroupv2CPUMaxQuotaIndex] == _cgroupV2CPUMaxQuotaMax {
return -1, false, nil
}

    // 解析最大额度
max, err := strconv.Atoi(fields[_cgroupv2CPUMaxQuotaIndex])
if err != nil {
return -1, false, err
}

var period int
if len(fields) == 1 {
period = _cgroupV2CPUMaxDefaultPeriod
} else {
period, err = strconv.Atoi(fields[_cgroupv2CPUMaxPeriodIndex])
if err != nil {
return -1, false, err
}

if period == 0 {
return -1, false, errors.New("zero value for period is not allowed")
}
}

    // 返回限额
    // 也就是最大额度除以周期
return float64(max) / float64(period), true, nil
}

if err := scanner.Err(); err != nil {
return -1, false, err
}

return 0, false, io.ErrUnexpectedEOF
}

cgroup2了解

cgroup允许对进程进行资源限制与管理,由负责分层组织进程的核心与负责沿层次

cgroup2则引入了更一致的设计和体验

统一层次结构

cgroup2引入统一层次结构,所有子系统(如cpu、memory)都共享同一个层次结构,从而减少了管理的复杂性

也简化了API,统一了配置接口,使其更加易用

基于权重的CPU调度

cgroup2以权重来控制CPU资源的分配。相对的权重越高,则获得的CPU时间越多。

如此,通过权重机制,用户可以很轻松地为不同任务分配 CPU 资源,而无需指定具体的 CPU 配额。这使得 CPU 使用更加灵活,同时调度系统也会根据实际负载动态调整资源分配

更安全的容器子树委派:

cgroup子树委派是将部分资源控制交予非特权用户的方式。

非特权用户可以管理自己子树下的 cgroup 控制器,而不会有权限修改父级或同级 cgroup 的资源控制设置

对内存管理进行更严格控制、记账

  • 内核内存和用户内存 的统一管理
  • 改进了内存压力下的行为,通过 压力感知提供实时的内存压力监控

内存控制相关文件

  • memory.high: 高水位线,超过这个值时,系统会尝试回收内存
  • memory.low: 若内存使用率在其有效下限内,则除非可以从不受保护的 cgroup 中回收内存,否则不会回收 cgroup 的内存
  • memory.max: 硬性内存限制,超出该值后将触发 OOM
  • memory.swap.max: 控制交换区使用的最大内存量。
  • memory.current: 实时显示当前 CGroup 使用的内存量

thread mode

cgroup v1 中,资源控制一般是基于进程组的,无法对同一进程中的不同线程进行独立的资源控制和隔离

为此在v2中,便支持thread mode,将进程中不同线程分配到不同cgroup中,这意味着可以对单个线程设置 CPU、内存等资源限制

在线程式子树中,只能启用线程式控制器。在线程子树中启用线程控制器时,它仅考虑和控制与 cgroup 及其后代中的线程关联的资源消耗。所有未绑定到特定线程的消费都属于线程域 cgroup。

控制PID

限制某个 CGroup 中允许的进程数量,防止某些容器或进程滥用系统资源

Ref

  1. https://kubernetes.io/docs/concepts/architecture/cgroups/
  2. https://github.com/uber-go/automaxprocs
  3. https://docs.kernel.org/admin-guide/cgroup-v2.html

原文地址:https://blog.csdn.net/iUcool/article/details/142865081

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!