侧边栏壁纸
博主头像
我的学习心得 博主等级

行动起来,活在当下

  • 累计撰写 223 篇文章
  • 累计创建 60 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Docker 容器对磁盘I/O、CPU和内存资源的使用控制

Administrator
2024-11-29 / 0 评论 / 1 点赞 / 165 阅读 / 0 字

原文

## 磁盘
--blkio-weight uint16              Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
--blkio-weight-device list         Block IO weight (relative device weight) (default [])

## CPU
--cpus decimal                     Number of CPUs
--cpu-period int                   Limit CPU CFS (Completely Fair Scheduler) period
--cpu-quota int                    Limit CPU CFS (Completely Fair Scheduler) quota
--cpu-rt-period int                Limit CPU real-time period in microseconds
--cpu-rt-runtime int               Limit CPU real-time runtime in microseconds
--cpu-shares int                   CPU shares (relative weight)
--cpuset-cpus string               CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string               MEMs in which to allow execution (0-3, 0,1)

## 内存
--memory bytes                     Memory limit
--memory-reservation bytes         Memory soft limit
--memory-swap bytes                Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int            Tune container memory swappiness (0 to 100) (default -1)

磁盘读写优先级

--blkio-weight: 全局磁盘读写优先级

--blkio-weight 控制容器在磁盘 I/O 方面的优先级。

  • 当宿主机上有多个容器同时尝试进行磁盘读写操作时,此相对权重决定了每个容器能够获得的磁盘 I/O 资源。
  • 此参数的取值范围为 10 ~ 1000 之间的整数。默认为 0,表示不对磁盘 I/O 进行限制。相对权重越大,容器在磁盘 I/O 方面的优先级越高。
  • 此参数不能完全决定磁盘 I/O 优先级,容器实际获得的磁盘 I/O 资源还受其他容器的影响。
  • 此参数仅适用于支持 CFS (Completely Fair Scheduler, 完全公平调度程序) 的 Linux 内核版本。

示例:

docker run --name "container_A" --blkio-weight 600 ubuntu
docker run --name "container_B" --blkio-weight 300 ubuntu

--blkio-weight-device: 执行磁盘读写优先级

--blkio-weight-device 用于为特定的设备(如磁盘或者分区)设置容器的 I/O 权重。

  • 取代全局设置(--blkio-weight),更精细地控制容器在不同设备上的 I/O 操作的优先级
  • 如果希望数据库在存储其数据的设备上高性能运行时,可以调高此参数
  • 如果希望某些关键容器在某些设备上高性能运行时,可以调高此参数
  • --blkio-weight 一样,取值范围为 10 ~ 1000,仅支持 CFS

示例:

docker run --name db_container --blkio-weight-device="/dev/nvme0n1:800" mysql

CPU 资源控制

--cpu-period & --cpu-quota: CPU使用率

--cpu-period 用于配置 CPU CFS 周期的时间长度,单位为微秒,默认为 100000 微秒(100毫秒)。

通常与 --cpu-quota 一起使用,用来限制容器的 CPU 使用资源。

--cpu-quota 定义了容器在指定周期内可以使用的 CPU 时间的配额(CPU 资源是按照计算时间计算的)。

一般不需要手动设置这两个参数的值,通过设置另一个参数 --cpus,Docker 会自动计算和设置这两个参数。

示例:

docker run --cpu-period=100000 --cpu-quota=25000 ubuntu

--cpus: CPU使用率

相对于 --cpu-period--cpu-quota--cpus 更加直观(事实上它就是前者的简化版本),它直接指定了容器可以使用了 CPU 核心数量。

  • 如果宿主机上的 CPU 资源紧张,--cpus 设置不当可能导致容器无法获得所需的 CPU 资源,导致性能下降
  • --cpus 同样依赖于 Linux 内核的 CFS 功能
  • --cpus 可以是小数,表示使用部分核心

示例:

docker run --cpus=2.5 ubuntu

--cpu-rt-period & --cpu-rt-runtime: 实时调度

--cpu-rt-period 的默认值一般为 1000000 微秒(1 秒)。

这两个参数的描述类似于 --cpu-period--cpu-quota,但它们针对的是不同的 CPU 调度机制,使用场景和功能有所不同。

前者针对 实时调度器(RTS, Real-Time Scheduler),后者针对普通调度器(CFS, Completely Fair Scheduler)。

🍉 RTS 和 CFS 的区别?

RTS 和 CFS 是 Linux 内核中用于处理任务调度的两种不同的机制,他们的主要区别在于 任务优先级响应时间 的要求上。

实时调度器(RTS)完全公平调度器(CFS)
优先级根据任务的优先级对任务进行调度,实时任务通常具有较高的优先级,能够立即得到处理根据任务的虚拟运行时间来调度任务,确保所有任务都能公平的获得 CPU 时间
响应时间响应时间可预测提供公平的 CPU 时间分配,一个任务执行完一个周期后会被放到队列末尾重新排队,响应时间取决于队列长度,不可预测
调度策略提供多种调度策略,例如 FIFO(先进先出,栈)、RR(时间片轮转)等使用 红黑树 来管理任务的调度,确保公平!
使用场景适用于需要严格时间保证的场景,例如实时控制系统、音频处理、网络路由器、医疗设备等适用于需要公平分配 CPU 时间的场景:一般计算任务,如服务器、桌面系统、嵌入式系统等,这些任务对公平性要求较高,对响应时间没那么严格
配置和管理通过设置 调度策略任务优先级 来管理,可以使用 chrt 命令或系统调用来设置任务的实时优先级通过设置任务的 nice 值来调整任务的优先级:nice 值越高,优先级越低
内核接口使用 SCHED_FIFO, SCHED_RR 等实时调度策略使用 SCHED_NORMAL, SCHED_BATCH 等非实时策略

🍉 容器已经设置了 CFS,为什么还需要设置 RTS?

普通的任务 CFS 已经够用了,但是如果我们的容器中有对执行时间有严格要求的任务时,CFS 无法满足我们的需求,因为它是公平分配 CPU 时间的,而我们需要这些特殊任务总是优先执行,但是又不能一直霸占 CPU,不然其他任务就假死了。这个时候就需要 RTS 来确保这些任务能够获得更高的优先级和可预测的响应时间。RTS 能够更加精细控制任务的调度。

🍉 容器内部如何为任务设置实时调度策略?

使用 chrt 命令:

chrt -f 99 some_command

但是容器默认是没有这个权限的,需要在启动容器时添加 --cap-add 参数授予容器设置任务实时策略的权限:

docker run --cap-add=sys_nice -it --rm ubuntu /bin/bash

🍉 --cap-add=sys_nice 是什么意思?

--cap-add 用于授予容器特定的 Linux 能力(capabilities),sys_nice 是 Linux 内核提供的一种能力,它允许进程(这里指容器)

  • 提高自身或者另一个任务的优先级(chrt 命令)
  • 设置任务的调度策略(如实时调度策略 SCHED_FIFO, SCHED_RR 等,sched_setscheduler, setpriority 等命令)
  • 调整任务的 nice 值(CFS 调度,renice 命令)

Linux 能力将传统的 root 权限拆分成多个独立的单元,每个单元(能力)可以单独启用和禁用。

🍉 设置了 --cpu-rt-period 还需要添加 --cap-add=sys_nice 吗?

这两个选项没有必然的关联:

  • --cpu-rt-period--cpu-rt-runtime 用于设定 CPU 执行时间
  • --cap-add=sys_nice 用于授予容器调整任务调度策略和优先级的能力

--cpu-shares

CPU 资源紧张时容器需要共享 CPU 资源,共享资源就涉及到优先级的问题,此参数就是用来控制容器在共享 CPU 资源时的相对优先级的。

当发生竞争时,不同容器可以获得的 CPU 时间比例由它们的 CPU 份额(--cpu-shares)决定。例如下面两个容器在竞争时,db2 将获得两倍于 db1 的 CPU 时间。-cpu-shared 默认值为 1024。

docker run -d --name db1 --cpu-shares=512 mariadb
docker run -d --name db2 --cpu-shares=1024 mariadb

适用场景:

  • 希望某些容器在 CPU 资源紧张是能够获得更多的 CPU 时间
  • 确保不会因为其他任务的资源抢占影响关键任务的性能
  • 多容器环境中根据任务的特性分配 CPU 份额以平衡系统的整体性能

注意点:

  • --cpu-shares 是一个相对值,容器最终能获得多少 CPU 份额由所有容器共同决定
  • --cpu-shares 只在 CPU 资源紧张时才发挥作用

--cpuset-cpus

在多核系统中,将容器绑定到指定的物理 CPU 上。

任务可能在不同的 CPU 核心之间迁移,可能导致缓存未命中和性能下降,通过将容器固定在指定的 CPU 上,可以提高容器的性能,适用于需要高吞吐量或者低延迟的任务。

docker run -it --cpuset-cpus="1,2" ubuntu /bin/bash
docker run -it --cpuset-cpus="0-3" ubuntu /bin/bash

内存资源控制

--cpuset-mems

指定容器可以访问的内存节点。

对于高性能计算任务或者低延迟实时任务,将容器绑定到特定的内存节点可以减少内存访问延迟。

docker run -it --cpuset-mems="1,2" ubuntu /bin/bash
docker run -it --cpuset-mems="0-3" ubuntu /bin/bash

🍉 如何获取系统中可用的内存节点?

lscpu

$ lscpu
...
NUMA:                     
  NUMA node(s):           1
  NUMA node0 CPU(s):      0-15
...

NUMA node(s) 行为内存节点个数。

numactl

$ sudo apt install numactl
$ numactl --hardware
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
node 0 size: 32027 MB
node 0 free: 11680 MB
node distances:
node   0 
  0:  10

available 行为内存节点个数。

numastat

$ numastat
                           node0
numa_hit               324174572
numa_miss                      0
numa_foreign                   0
interleave_hit              1706
local_node             324174572
other_node                     0

有几列就有几个内存节点。

🍉 NUMA 是什么意思?

NUMA 是 Non-Uniform Memory Access 的缩写,意为“非一致性内存访问”,用于在高性能服务器和工作站中优化 多核处理器 的内存访问性能。

在传统的系统中,所有处理器共享一个全局内存空间,这在内存资源充足的情况下是最优、最简单、最易于管理的方案。但是一旦任务负载过大,尤其是在高性能计算服务器中,内存资源会变得非常紧张,多核处理器使用共享内存的竞争造成的延迟问题极大影响任务性能。一个解决思路就是将内存划分成多个子区域,每个处理器主要使用分配给自己的区域,有需要时也可以访问其他区域(但是延迟会高很多),这就是 NUMA 架构。

综上,NUMA 将内存划分成多个小区域并与处理器绑定,以提高多核系统的任务执行性能。

--memory

限制容器可以使用的最大物理内存。

容器在运行时如果超过这个限制,会触发 OOM (Out Of Memory) 被强行终止。

参数值支持带单位:512, 512b, 512k, 512m, 512g, ...

虽然 --oom-kill-disable 参数可以禁用 OOM 终止行为,但是不建议使用该选项。

docker run -d --name web_server --memory="512m" nginx
docker run -d --name database --memory="1g" mariadb

--memory-reservation

--memory 一样用来限制容器可使用的最大内存,但是是软限制。

在内存充足时,容器可使用内存可以超过此限制;但是在内存紧张时,Docker 会尝试降低该容器的内存到预设值之下。

该参数优先级低于 --memory。同时设置时,只有此参数值小于 --memory 的参数值,软限制才能发挥作用。

docker run -it --memory="1g" --memory-reservation="512m" ubuntu /bin/bash

--memory-swap

设置容器可以使用的虚拟内存(物理内存+交换空间)总量。

交换空间是当物理内存(RAM)不足时,用于存放内存数据的磁盘空间。

如果只设置了 --memory 而没有设置 --memory-swap,Docker 会将 --memory-swap 设置为 --memory 的两倍(交换空间=物理内存)。

--memory-swap 设置为 -1,容器可以无限制的使用交换空间。

--memory-swap 设置为与 --memory 相同的值,禁用交换空间。

--memory-swappiness

控制容器内进程使用交换空间的倾向性。

swappiness 是一个内核参数,取值范围为 0 ~ 100,值越大,操作系统越倾向于使用交换空间;值越小,操作系统越倾向于保留物理内存。

减小 swappiness 的值,可以减少交换空间的使用,提高内存访问速度,提升容器性能。

# 尽可能多的使用交换空间
docker run -it --memory-swappiness=100 ubuntu /bin/bash

# 完全禁用交换空间
docker run -it --memory-swappiness=0 ubuntu /bin/bash

🍉 如何查看系统默认的 swappiness?

$ sysctl vm.swappiness
vm.swappiness = 60

$ cat /proc/sys/vm/swappiness 
60
1

评论区