利用 cgroup 的 cpuset 控制器限制进程的 CPU 使用
最近在做一些性能测试的事情,首要前提是控制住 CPU 的使用量。最直观的方法无疑是安装 Docker,在每个配置了参数的容器里运行基准程序。
对于计算密集型任务,在只限制 CPU 的需求下,直接用 Linux 原生的 cgroup 功能来限制 CPU 使用无疑是最方便的。
本文简要说明如何使用 cgroup 的 cpuset 控制器限制进程只使用某几个 CPU,更准确的说是某个几个逻辑核。
1. 查看 CPU 配置
常用的配置可以用如下 BASH 命令查看。
- cat /proc/cpuinfo | grep "physical id" | sort | uniq # 查看物理 CPU 数量
- cat /proc/cpuinfo | grep "cores" | uniq # 查看每块 CPU 的核心数
- cat /proc/cpuinfo | grep "processor" | wc -l # 查看主机总的逻辑线程数
特别地,启用了超线程的话,每个 CPU 物理核心会模拟出 2 个线程,也叫逻辑核。判断方式如下:
- 是否开启超线程 = 物理 CPU 数量 * 每块 CPU 核心数 / 总逻辑线程数 == 2
2. 什么是 NUMA
这里提到一个概念叫 NUMA,主机板上如果插有多块 CPU 的话,那么就是 NUMA 架构。每块 CPU 独占一块面积,一般都有独立风扇。
一个 NUMA 节点包含了直连在该区域的 CPU、内存等硬件设备,通信总线一般是 PCI-E。由此也引入了 CPU 亲和性的概念,即 CPU 访问同一个 NUMA 节点上的内存的速度大于访问另一个节点的。
执行以下命令,以查看本机的 NUMA 结构。
- numactl --harware
- # available: 2 nodes (0-1)
- # node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- # node 0 size: 127834 MB
- # node 0 free: 72415 MB
- # node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
- # node 1 size: 128990 MB
- # node 1 free: 68208 MB
- # node distances:
- # node 0 1
- # 0: 10 21
- # 1: 21 10
一个 NUMA 节点包括一个内存节点和属于同一块 CPU 的若干个逻辑核,请记住它们的编号,将在配置 cpuset 中用到。
在此解释下“node distance”,访问本节点的内存的通信成本是常量值 10,操作系统以此基准来量化访问其他 NUMA 节点上内存的代价。
3. 创建 cgroup 并配置资源使用
内核版本较高(>=2.6.24)的 Linux 发行版都内置了 cgroup,可以执行以下命令验证一下。
- mount | grep cgroup
- # tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
- # cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
- # cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
- # cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
- # cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
- # cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
- # cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
- # cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
- # cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
- # cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
- # cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
如果没有的话,也可以执行一段简单的脚本呢,来一次性挂载齐全。
- cgroot="${1:-/sys/fs/cgroup}"
- subsys="${2:-blkio cpu cpuacct cpuset devices freezer memory net_cls net_prio ns perf_event}"
- mount -t tmpfs cgroup_root "${cgroot}"
- for ss in $subsys; do
- mkdir -p "$cgroot/$ss"
- mount -t cgroup -o "$ss" "$ss" "$cgroot/$ss"
- done
cgroup 针对每一种资源都提供了相应的控制器来进行配置,在 Linux 中以文件系统的形式呈现。本文只涉及进程在物理核上的放置,因此来看一下 cpuset 目录下有什么。
- mkdir /sys/fs/cgroup/cpuset/tiger # 创建一个控制组,删除用 rmdir 命令
- ls /sys/fs/cgroup/cpuset/tiger
- # cgroup.clone_children cpuset.memory_pressure
- # cgroup.procs cpuset.memory_spread_page
- # cpuset.cpu_exclusive cpuset.memory_spread_slab
- # cpuset.cpus cpuset.mems
- # cpuset.effective_cpus cpuset.sched_load_balance
- # cpuset.effective_mems cpuset.sched_relax_domain_level
- # cpuset.mem_exclusive notify_on_release
- # cpuset.mem_hardwall tasks
- # cpuset.memory_migrate
如果要使用 cpuset 控制器,需要同时配置 cpuset.cpus 和 cpuset.mems 两个文件(参数)。这两个文件接受用短横线和逗号表示的区间,如“0-7,16-23”。如果对应的资源不存在,那么写入的时候会报错。
不建议直接在控制器的根目录下配置,通过创建子目录的形式可以同时维持多个控制器。执行如下命令,限制 tiger 控制组下所有进程只能使用逻辑核0和1。
- echo "0-1" > /sys/fs/cgroup/cpuset/tiger/cpuset.cpus
- echo 0 > /sys/fs/cgroup/cpuset/tiger/cpuset.mems
对于 cpuset.mems 参数而言,每个内存节点和 NUMA 节点一一对应。如果进程的内存需求量较大,可以把所有的 NUMA 节点都配置进去。这里就用到了 NUMA 的概念。出于性能的考虑,配置的逻辑核和内存节点一般属于同一个 NUMA 节点,可用“numactl --hardware”命令获知它们的映射关系。
4. 验证效果
在 cpuset 的所有配置文件中,tasks 和 cgroups.procs 是用来管理控制组中的进程的。执行以下命令,把当前会话加入刚刚创建的控制组里,本会话发起的所有命令(子进程)都会收到 cpu 使用的约束。
- echo $$ > /sys/fs/cgroup/cpuset/tiger/cgroup.procs # 写入当前进程编号
两个配置项基本是等价的,但有一小点不同。操作系统以线程为调度单位,将一个一般的 pid 写入到 tasks 中,只有这个 pid 对应的线程,以及由它产生的其他进程、线程会属于这个控制组。而把 pid 写入 cgroups.procs,操作系统则会把找到其所属进程的所有线程,把它们统统加入到当前控制组。
进程在加入一个控制组后,控制组所对应的限制会即时生效。启动一个计算密集型的任务,申请用 4 个逻辑核。
- stress -c 4 &
- # [1] 2958521
- # stress: info: [2958521] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
观察 CPU 的使用情况来验证效果,只有编号为 0 和 1 的两个逻辑核在工作,用户态的比例高达 100%。
- top # 在列表页按数字 1 键,切换到 CPU 看板
- # Tasks: 706 total, 3 running, 702 sleeping, 0 stopped, 1 zombie
- # %Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- # %Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- # %Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
- # %Cpu3 : 0.0 us, 1.7 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
利用 cgroup 的 cpuset 控制器限制进程的 CPU 使用的更多相关文章
- [daily][cgroup] 使用cgroup限制进程的CPU占用
参考: https://segmentfault.com/a/1190000008323952 1. 找到cgroup设置的地方. [root@D128 ~]# mount -l |grep cpu ...
- 利用JMX统计远程JAVA进程的CPU和Memory---jVM managerment API
从JAVA 5开始,JDK提供了一些JVM检测的API,这就是有名的java.lang.management 包,包里提供了许多MXBean的接口类,可以很方便的获取到JVM的内存.GC.线程.锁.c ...
- 利用JMX统计远程JAVA进程的CPU和Memory
http://songzi0206.iteye.com/blog/1541636 ******************** 从JAVA 5开始,JDK提供了一些JVM检测的API,这就是有名的java ...
- 利用lsof去查看Unix/Linux进程打开了哪些文件
利用lsof去查看Unix/Linux进程打开了哪些文件 今天用了一下lsof,发现这个linux的小工具,功能非常强大而且好用. 我们可以方便的用它查看应用程序进程打开了哪些文件或者对于特定的一个文 ...
- Windows中利用共享内存来实现不同进程间的通信
Windows中利用共享内存来实现不同进程间的通信 一.msdn详细介绍 https://docs.microsoft.com/zh-cn/windows/win32/memory/sharing-f ...
- 【转】进程与CPU
声明:本博客转自:http://blog.chinaunix.net/uid-20737871-id-1881246.html 简单地说,CPU 亲和性(affinity) 就是进程要在某个给定的 C ...
- 计算进程消费cpu和内存
Linux下没有直接可以调用系统函数知道CPU占用和内存占用.那么如何知道CPU和内存信息呢.只有通过proc伪文件系统来实现. proc伪文件就不介绍了,只说其中4个文件.一个是/proc/stat ...
- Linux下计算进程的CPU占用和内存占用的编程方法[转]
from:https://www.cnblogs.com/cxjchen/archive/2013/03/30/2990548.html Linux下没有直接可以调用系统函数知道CPU占用和内存占用. ...
- 使用taskset命令来限制进程的CPU
常常感觉系统资源不够用,一台机子上跑了不下3个比较重要的服务,但是每天我们还要在上面进行个备份压缩等处理,网络长时间传输,这在就很影响本就不够用的系统资源: 这个时候我们就可以把一些不太重要的比如co ...
随机推荐
- .Net Core with 微服务 - Seq 日志聚合
上一次我们介绍并演示了如果使用 Consul 做为我们微服务的注册中心,来实现服务的注册与发现.那么本次我们讲会演示如何做日志聚合.日志聚合比较常用的有 ELK 等,但是这次我想要介绍的是一款比较小众 ...
- 华为云数据库GaussDB(for Cassandra)揭秘第二期:内存异常增长的排查经历
摘要:华为云数据库GaussDB(for Cassandra) 是一款基于计算存储分离架构,兼容Cassandra生态的云原生NoSQL数据库:它依靠共享存储池实现了强一致,保证数据的安全可靠. 本文 ...
- 第11章 PADS功能使用技巧(1)-最全面
一.如何走蛇形线? 蛇形线是布线过程中常用的一种走线方式,其主要目的是为了调节延时满足系统时序设计要求,但是设计者应该有这样的认识:蛇形线会破坏信号质量,改变传输延时,布线时要尽量避免使用,因此一块P ...
- canvas小画板——(3)笔锋效果
画线准备 准备一个canvas <canvas id="canvasId" width="1000" height="800"> ...
- 《机器学习Python实现_10_10_集成学习_xgboost_原理介绍及回归树的简单实现》
一.简介 xgboost在集成学习中占有重要的一席之位,通常在各大竞赛中作为杀器使用,同时它在工业落地上也很方便,目前针对大数据领域也有各种分布式实现版本,比如xgboost4j-spark,xgbo ...
- Netty 框架学习 —— UDP 广播
UDP 广播 面向连接的传输(如 TCP)管理两个网络端点之间的连接的建立,在连接的生命周期的有序和可靠的消息传输,以及最后,连接的有序终止.相比之下,类似 UDP 的无连接协议中则没有持久化连接的概 ...
- Linux基础 -01
01Linux快速入门 1.计算机组成原理 1.1什么是计算机 计算机一般被称为"电脑",即通电的大脑 电脑二字蕴含了人类对计算机的终极期望; 希望它能像人脑一样为我们工作,从而取 ...
- AcWing 201. 可见的点
在一个平面直角坐标系的第一象限内,如果一个点(x,y)与原点(0,0)的连线中没有通过其他任何点,则称该点在原点处是可见的. 编写一个程序,计算给0<x,y<=n定整数N的情况下,满足的可 ...
- SpringCloud:SpringBoot整合SpringCloud项目
划分模块 这里我划分了四个模块 Common: 存放bean和Dao模块 Consumer: 消费者模块,提供对外暴露接口服务 EurekaServer: Eureka注册中心模块,主要用于启动注册中 ...
- PHP Kafka 消息队列使用
转载自:https://learnku.com/articles/44442 1. 安装 Kafka 服务# 直接到 kafka 官网 , 下载最新的 wget https://mirror.bi ...