cpulimit设计理念及其思考

背景

前几天,同事咨询了我一个问题:IO占用能和cpu使用率那样,有方法来控制吗?这个问题的背景是因为客户提了两个需求,如下:

说实话,针对这两点需求,我的第一反应是有一点思路,但是并没有具体的方案。比如可以通过sleep的方式减少对CPU、IO的占用。但是如何去设计呢?令我比较有兴趣。

经讨论,进程CPU使用率可以通过开源工具cpulimit进行控制,但是进程的IO占用目前并没有好的工具可以实现。好奇心爆棚的我,比较想了解cpulimit的实现原理,以及在这之上是否能够对进程IO占用有借鉴意义。

开源工具cpulimit体积很小,就2千行代码左右,两个小时基本就能看完。了解其大致原理后,感觉对实现控制进程IO占用的功能也有一定的参考作用。通过本篇,希望能够和大家分享一下我的思路。若由任何不妥的地方或问题,欢迎评论区讨论。

cpulimit 使用及设计分析

开源工具cpulimit可通过git下载,本地编译,验证。

下载:

git clone https://github.com/opsengine/cpulimit.git

编译:

yihua@ubuntu:~/cpulimit$ make
cd src && make all
make[1]: Entering directory '/home/yihua/cpulimit/src'
cc -c list.c -Wall -g -D_GNU_SOURCE
cc -c process_iterator.c -Wall -g -D_GNU_SOURCE
cc -c process_group.c -Wall -g -D_GNU_SOURCE
cc -o cpulimit cpulimit.c list.o process_iterator.o process_group.o -Wall -g -D_GNU_SOURCE
cpulimit.c:46:18: warning: extra tokens at end of #ifdef directive
 #ifdef __APPLE__ || __FREEBSD__
                  
make[1]: Leaving directory '/home/yihua/cpulimit/src'
cd tests && make all
make[1]: Entering directory '/home/yihua/cpulimit/tests'
cc -o busy busy.c -lpthread -Wall -g
cc -I../src -o process_iterator_test process_iterator_test.c ../src/list.o ../src/process_iterator.o ../src/process_group.o -lpthread -Wall -g
process_iterator_test.c:31:18: warning: extra tokens at end of #ifdef directive
 #ifdef __APPLE__ || __FREEBSD__

make[1]: Leaving directory '/home/yihua/cpulimit/tests'
yihua@ubuntu:~/cpulimit$

验证:

  1. 通过stress工具模拟CPU密集型场景。stress -c 4,4表示创建4个子进程,因为我的环境是4核,故创建4个进程。
  2. 通过mpstat查看系统的cpu使用率。mpstat -P ALL 1,显示更新频率为1s。
yihua@ubuntu:~/cpulimit$ mpstat -P ALL 1
Linux 4.15.0-213-generic (ubuntu)       12/20/2023      _x86_64_        (4 CPU)

12:57:49 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
12:57:50 AM  all   99.25    0.00    0.75    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:50 AM    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:50 AM    1   97.00    0.00    3.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:50 AM    2  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:50 AM    3  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00

12:57:50 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
12:57:51 AM  all   99.50    0.00    0.50    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:51 AM    0  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:51 AM    1   98.00    0.00    2.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:51 AM    2  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:51 AM    3  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00

12:57:51 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
12:57:52 AM  all   99.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:52 AM    0   99.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:52 AM    1   97.98    0.00    2.02    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:52 AM    2  100.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00
12:57:52 AM    3   99.00    0.00    1.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00

由上可知,CPU占用率约100%。

  1. 通过cpulimit控制stress进程的cpu使用率。./src/cpulimit -p pid -l 50 -i
  2. 再观察系统的CPU使用率,如下:
yihua@ubuntu:~$ mpstat -P ALL 1
Linux 4.15.0-213-generic (ubuntu)       12/20/2023      _x86_64_        (4 CPU)

01:10:45 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
01:10:46 AM  all   13.40    0.00    1.99    0.00    0.00    0.00    0.00    0.00    0.00   84.62
01:10:46 AM    0   11.11    0.00    2.02    0.00    0.00    0.00    0.00    0.00    0.00   86.87
01:10:46 AM    1   15.84    0.00    3.96    0.00    0.00    0.00    0.00    0.00    0.00   80.20
01:10:46 AM    2   12.87    0.00    0.99    0.00    0.00    0.00    0.00    0.00    0.00   86.14
01:10:46 AM    3   13.13    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   86.87

01:10:46 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
01:10:47 AM  all   12.00    0.00    1.50    0.00    0.00    0.25    0.00    0.00    0.00   86.25
01:10:47 AM    0   10.00    0.00    2.00    0.00    0.00    0.00    0.00    0.00    0.00   88.00
01:10:47 AM    1   15.15    0.00    3.03    0.00    0.00    0.00    0.00    0.00    0.00   81.82
01:10:47 AM    2   12.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   88.00
01:10:47 AM    3   12.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   88.00

01:10:47 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
01:10:48 AM  all   12.78    0.00    0.75    0.00    0.00    0.00    0.00    0.00    0.00   86.47
01:10:48 AM    0   15.00    0.00    3.00    0.00    0.00    0.00    0.00    0.00    0.00   82.00
01:10:48 AM    1   12.87    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   87.13
01:10:48 AM    2   12.12    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   87.88
01:10:48 AM    3   11.88    0.00    0.00    0.00    0.00    0.00    0.00    0.00    0.00   88.12

由上可知,CPU0 + CPU1 + CPU2 + CPU3约等于50。

cpulimt设计流程分析

cpulimit真的很小,建议小伙伴们自己走读一遍,加强理解。cpulimit -p pid -l 50 -i其大致流程如下:

  1. 设定一个应用时间片TIME_SLOT=100ms。计算得到 T w o r k T_{work} Twork时间和 T s l e e p T_{sleep} Tsleep时间。即 T w o r k T_{work} Twork=TIME_SLOT*limit,$T_{sleep}=TIME_SLOT*(1-limit)
  2. 通过pid,在proc文件系统中,找到进程及其子进程的信息目录。
  3. 通过获取/proc/pid/stat文件中的utimestime的时长,utime+stime得到该进程已消耗CPU的节拍数。
  4. 将进程及其子进程的节拍数相加,得到该进程消耗的总的节拍数。即为实际运行时长 T r e l w o r k T_{rel_work} Trelwork
    1. T r e l w o r k T_{rel_work} Trelwork > T w o r k T_{work} Twork,说明超过了限定值。需要释放CPU使用权。cpulimit则会想所有的进程发送信号SIGSTOP,并自身nanosleep TIME_SLOT - T r e l w o r k T_{rel_work} Trelwork时长。
    2. T r e l w o r k T_{rel_work} Trelwork < T w o r k T_{work} Twork,说明为达到限定值,可以继续占用CPU使用权。cpulimit则会想所有的进程发送信号SIGCONT,并自身nanosleep T w o r k T_{work} Twork - T r e l w o r k T_{rel_work} Trelwork 时长。
  5. 重复1~3步骤。

伪代码大致流程如下:

while(true)
{
    //1. 更新进程组的资源消耗
    update_process_group(&pgroup);
    ...
    for (node = pgroup.proclist->first; node != NULL; node = node->next) {
        struct process *proc = (struct process*)(node->data);
        if (proc->cpu_usage < 0) {
            continue;
        }
        if (pcpu < 0) pcpu = 0;
        pcpu += proc->cpu_usage;
    }
    ...
    //2. 计算sleeptime、worktime
    workingrate = MIN(workingrate / pcpu * limit, 1);
    tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec;

    //3. 唤醒进程组
    while (node != NULL)
    {
        struct list_node *next_node = node->next;
        struct process *proc = (struct process*)(node->data);
        kill(proc->pid,SIGCONT);
        node = next_node;
    }
    //3.1 让进程组运行twork时长
    gettimeofday(&startwork, NULL);
    nanosleep(&twork, NULL);
    gettimeofday(&endwork, NULL);


    //3.2 让进程组sleep twork时长
    if (tsleep.tv_nsec>0) {
    node = pgroup.proclist->first;
    while (node != NULL)
    {
        struct list_node *next_node = node->next;
        struct process *proc = (struct process*)(node->data);
        kill(proc->pid,SIGSTOP);
        node = next_node;
    }
    nanosleep(&tsleep,NULL);
}

思考

进程IO占用是否能够采用上述的方式:通过监控进程发送SIGSTOPSIGCONT控制目标进程的运行和休眠呢?

其实略加思考,就知道是不可行的。我们可以思考一下这个问题:客户提出IO占用可控的目的是什么?

答:无非就是防止该进程一直占用IO资源,其它业务进程获取不到资源,影响正常业务执行。如果采用cpulimit的方案,那么就会出现一种情况:若目标进程正在持有该IO资源,即使操作系统通过SIGSTOP信号,将目标进程挂起,那么其它进程也无法获取该IO资源,并不能达到客户的预期

脑洞大开(仅供参考)

通过cpulimit的设计思路,以及我们程序的应用场景,于是乎我想到了一种解决方案,似乎也能达到IO占用控制的效果。如有任何不对的地方,还请不吝指教。

我们的程序IO主要就是read/write 分区。我可以封装自己的read/write接口。其逻辑大致如下:

  1. 设定一个应用时间片TIME_SLOT=100ms。计算得到 T w o r k T_{work} Twork时间和 T s l e e p T_{sleep} Tsleep时间。即 T w o r k T_{work} Twork=TIME_SLOT*limit T s l e e p T_{sleep} Tsleep=TIME_SLOT*(1-limit)
  2. 通过proc文件系统,获取进程当前已经消耗的cpu时间 T i o 1 T_{io1} Tio1。并记录当前时间系统时间 T 总 1 T_{总1} T1
  3. 执行read/write系统调用。
  4. 通过proc文件系统,获取进程当前已经消耗的cpu时间 T i o 2 T_{io2} Tio2。并记录当前时间系统时间 T 总 2 T_{总2} T2
    1. T i o 2 T_{io2} Tio2 - T i o 1 T_{io1} Tio1 < T w o r k T_{work} Twork T 总 2 T_{总2} T2- T 总 1 T_{总1} T1 < T w o r k T_{work} Twork ,说明还未达到限定值,可以继续执行IO。
    2. T i o 2 T_{io2} Tio2 - T i o 1 T_{io1} Tio1 > T w o r k T_{work} Twork,说明单位时间内,已达到占用比,执行下一步骤休眠。
    3. T 总 2 T_{总2} T2- T 总 1 T_{总1} T1 > T w o r k T_{work} Twork,说明单位时间内,IO被其它进程抢占,未达到限定值。回到步骤2。
  5. nanosleep T w o r k T_{work} Twork - ( T 总 2 T_{总2} T2- T 总 1 T_{总1} T1) 。

以上便是我暂时的设想,当然真正实现时,需要考虑一些细节。比如步骤3和步骤4.1,若不加处理,大量的时间会消耗在proc文件系统读取上。

总结

以上便是的初步设想,后续有时间会进行代码验证,有兴趣的朋友可以关注哈。
若我的内容对您有所帮助,还请关注我的公众号。不定期分享干活,剖析案例,也可以一起讨论分享。
我的宗旨:
踩完您工作中的所有坑并分享给您,让你的工作无bug,人生尽是坦途。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/259481.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第二节TypeScript 基础语法

1、typescript程序由以下几个部分组成&#xff1a; 模块函数变量语句和表达式注释 2、开始第一个typescript程序 创建一个typescript程序&#xff0c;使之输出“hello typescript”&#xff1a; 代码&#xff1a; var message:string "hello typescript" cons…

MaBatis使用`ResultMap`标签手动映射详解使用

文章目录 MaBatis使用ResultMap标签手动映射详解使用1、MyBatis只能自动维护库表”列名“与”属性名“相同时的对应关系&#xff0c;二者不同时无法自动ORM&#xff0c;如下&#xff1a;2、在SQL中使用 as 为查询字段添加列别名&#xff0c;以匹配属性名&#xff1a;但是如果我…

(7)Linux GDB以及gcc和g++

&#x1f4ad; 前言 本章我们将带着大家高雅的学一学令众多习惯图形化页面的朋友难受的 gdb 调试&#xff0c;这部分知识可以选择性学习学习&#xff0c;以后倘若遇到一些问题时能在 Linux 内简单调试&#xff0c;还是很香的。然后在讲讲 gcc 和 g&#xff0c;系统讲解程序运行…

基于STC89C51单片机实现的森林防火系统源码+仿真+原理图+设计报告,含视频讲解

森林防火 摘要 森林防火是非常必要的,火灾对森林的破坏是具有毁灭性的,有着很大的危害,在春秋季节森林火灾高发期,若发生火灾,对人民生活带来极大危害,不仅危害人们生产生活,而且对地球环境产生影响.本课题研究的内容是以单片机STC89C51为控制核心&#xff0c;以MQ-2型半导体电…

YZ系列工具之YZ02:字典的多功能应用

我给VBA下的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套一部VBA手册&#xff0c;教程分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的…

C : DS二叉排序树之删除

Description 给出一个数据序列&#xff0c;建立二叉排序树&#xff0c;并实现删除功能 对二叉排序树进行中序遍历&#xff0c;可以得到有序的数据序列 Input 第一行输入t&#xff0c;表示有t个数据序列 第二行输入n&#xff0c;表示首个序列包含n个数据 第三行输入n个数据…

【TCP服务器的演变过程】编写第一个TCP服务器:实现一对一的连接通信

编写第一个TCP服务器&#xff1a;实现一对一的连接通信 一、前言二、需要使用到的API2.1、socket()函数2.2、bind()函数2.3、listen()函数2.4、accept()函数2.5、recv()函数2.6、send()函数2.7、strerror()函数 三、实现步骤四、完整代码五、TCP客户端5.1、自己实现一个TCP客户…

OpenHarmony南向之TP触摸屏

概述 Touchscreen驱动用于驱动触摸屏使其正常工作&#xff0c;该驱动主要完成如下工作&#xff1a;对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口&#xff08;I2C或SPI&#xff09;、设定Input相关配置、下载及更新固件等操作。 Touchscreen驱…

代码随想录算法训练营第四十一天|198.打家劫舍 ,213.打家劫舍II ,337.打家劫舍III

198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#…

建行驻江门市分行纪检组党支部开展“以廉养人,以案警人”清廉文化现场教学活动

近日&#xff0c;建行驻江门市分行纪检组党支部联合建设支行党支部到江门市党群服务中心开展“以廉养人&#xff0c;以案警人”清廉文化现场教学活动。 名言语句亮初心。一楼展馆入口处竖立着“拔烂树、治病树、正歪树”“以猛药去疴刮骨疗毒的勇气反腐”“理想信念是共产党人的…

配置https环境

为什么要配置https环境 在使用 HTML5 的 API 时&#xff0c;很多 API 只能在 https 保证安全的情况下才能开启。这就要求我们在本地开发环境也能够配置 https&#xff0c;否则你需要每次部署到配有 https 的测试环境中才能看到预览效果&#xff0c;这对开发的敏捷度造成了极大…

机器学习--线性回归

目录 监督学习算法 线性回归 损失函数 梯度下降 目标函数 更新参数 批量梯度下降 随机梯度下降 小批量梯度下降法 数据预处理 特征标准化 正弦函数特征 多项式特征的函数 数据预处理步骤 线性回归代码实现 初始化步骤 实现梯度下降优化模块 损失与预测模块 …

【C++】对象特性:无参有参构造函数,拷贝构造函数,析构函数

目录 对象的初始化和清理1.1 构造函数和析构函数1.2 构造函数的分类及调用1.3 拷贝构造函数调用时机1.4 构造函数调用规则1.5 深拷贝与浅拷贝 对象的初始化和清理 生活中我们买的电子产品都基本会有出厂设置&#xff0c;在某一天我们不用时候也会删除一些自己信息数据保证安全。…

智慧食堂餐卡充值文件生成器使用说明

智慧食堂餐卡充值文件生成器 下载地址&#xff1a; https://download.csdn.net/download/boysoft2002/88646277 或者百度网盘下载&#xff1a; https://pan.baidu.com/s/16cxOa5aq0CU0T0xOr2A7-A 操作使用说明 一、文件结构 下载.rar文件后&#xff0c;释放到非系统盘符的…

数据库故障Waiting for table metadata lock

场景&#xff1a;早上来发现一个程序&#xff0c;链接mysql数据库有点问题&#xff0c;随后排查&#xff0c;因为容器在k8s里面。所以尝试重启了pod没有效果 一、重启pod: 这里是几种在Kubernetes中重启Pod的方法: 删除Pod,利用Deployment重建 kubectl delete pod mypodDepl…

【小呆的力学笔记】弹塑性力学的初步认知二:应力分析(1)

文章目录 1.1 一点的应力状态1.2 一点主应力状态1.3 应力偏张量、球张量、应力不变量 1.1 一点的应力状态 物体在受到外力或者自身不均匀的温度场等作用时&#xff0c;在其内部会产生内力&#xff0c;物体的内力与方向和截面都有关系。假设有一个受到外力作用的变形体&#xf…

Java经典面试题:冒泡算法的使用

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍Java经典面试题&#xff1a;冒泡算法的使用以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问题…

nodejs连接mongodb报错SyntaxError: Unexpected token .

nodejs连接mongodb报错SyntaxError: Unexpected token 如下图 经过排查&#xff0c;原因是npm默认安装的mongodb插件是最新版6.3.0 &#xff0c;而mongodb数据库版本是4.0.0 &#xff0c;两者版本不同导致nodejs报错。 解决方法是npm卸载新版本的mongodb插件&#xff0c;再安…

comfyUI + animateDiff video2video AI视频生成工作流介绍及实例

原文&#xff1a;comfyUI animateDiff video2video AI视频生成工作流介绍及实例 - 知乎 目录 收起 前言 准备工作环境 comfyUI相关及介绍 comfyUI安装 生成第一个视频 进一步生成更多视频 注意事项 保存为不同的格式 视频宽高设置 种子值设置 提示词与负向提示词…

uml用例图是什么?有哪些要素?

UML用例图是什么&#xff1f; UML用例图&#xff08;Unified Modeling Language Use Case Diagram&#xff09;是一种用于描述系统功能和用户之间交互的图形化建模工具。它是UML的一部分&#xff0c;主要用于识别和表示系统中的各个用例&#xff08;用户需求或功能点&#…