怎么调整CPU资源分配,如何将资源公平地分配给各个进程 但是,如果你需要给一个重要进程提高优先级时,该怎么做呢? 或者是,如何降低一个进程的优先级? 又或者,如何限制一组进程所使用的资源呢? 答案是需要由用户来为内核指定进程的优先级 大部分进程启动时的优先级是相同的,因此Linux内核会公平地进行调度。 如果想让一个CPU密集型的进程运行在较低优先级,那么你就得事先配置好调度器。

下面介绍3种控制进程运行时间的方法:

使用 nice 命令手动降低任务的优先级。 使用 cpulimit 命令不断的暂停进程,以控制进程所占用处理能力不超过特定限制。 使用linux内建的control groups(控制组)功能,它提供了限制进程资源消耗的机制。 我们来看一下这3个工具的工作原理和各自的优缺点。

模拟高cpu占用率

在分析这3种技术前,我们要先安装一个工具来模拟高CPU占用率的场景。我们会用到CentOS作为测试系统,并使用Mathomatic toolkit中的质数生成器来模拟CPU负载。

很不幸,在CentOS上这个工具没有预编译好的版本,所以必须要从源码进行安装。先从 http://mathomatic.orgserve.de/mathomatic-16.0.5.tar.bz2 这个链接下载源码包并解压。然后进入 mathomatic-16.0.5/primes 文件夹,运行 make 和 sudo make install 进行编译和安装。这样,就把 matho-primes 程序安装到了 /usr/local/bin 目录中。

接下来,通过命令行运行:

/usr/local/bin/matho-primes 09999999999>/dev/null& 程序运行后,将输出从0到9999999999之间的质数。因为我们并不需要这些输出结果,直接将输出重定向到/dev/null就好。

现在,使用top命令就可以看到matho-primes进程榨干了你所有的cpu资源。

好了,接下来(按q键)退出 top 并杀掉 matho-primes 进程(使用 fg 命令将进程切换到前台,再按 CTRL+C)

nice命令

下来介绍一下nice命令的使用方法,nice命令可以修改进程的优先级,这样就可以让进程运行得不那么频繁。 这个功能在运行cpu密集型的后台进程或批处理作业时尤为有用。 nice值的取值范围是[-20,19],-20表示最高优先级,而19表示最低优先级。 Linux进程的默认nice值为0。使用nice命令(不带任何参数时)可以将进程的nice值设置为10。这样调度器就会将此进程视为较低优先级的进程,从而减少cpu资源的分配。

下面来看一个例子,我们同时运行两个 matho-primes 进程,一个使用nice命令来启动运行,而另一个正常启动运行:

nice matho-primes 0 9999999999 >/dev/null& matho-primes 0 9999999999 >/dev/null& 再运行top命令。

看到没,正常运行的进程(nice值为0)获得了更多的cpu运行时间,相反的,用nice命令运行的进程占用的cpu时间会较少(nice值为10)。

在实际使用中,如果你要运行一个CPU密集型的程序,那么最好用nice命令来启动它,这样就可以保证其他进程获得更高的优先级。 也就是说,即使你的服务器或者台式机在重载的情况下,也可以快速响应。

nice 还有一个关联命令叫做 renice,它可以在运行时调整进程的 nice 值。使用 renice 命令时,要先找出进程的 PID。下面是一个例子:

renice +101234 其中,1234是进程的 PID。

测试完 nice 和 renice 命令后,记得要将 matho-primes 进程全部杀掉。

cpulimit命令

接下来介绍 cpulimit 命令的用法。 cpulimit 命令的工作原理是为进程预设一个 cpu 占用率门限,并实时监控进程是否超出此门限,若超出则让该进程暂停运行一段时间。cpulimit 使用 SIGSTOP 和 SIGCONT 这两个信号来控制进程。它不会修改进程的 nice 值,而是通过监控进程的 cpu 占用率来做出动态调整。

cpulimit 的优势是可以控制进程的cpu使用率的上限值。但与 nice 相比也有缺点,那就是即使 cpu 是空闲的,进程也不能完全使用整个 cpu 资源。

在 CentOS 上,可以用下面的方法来安装它:

wget -O cpulimit.zip https://github.com/opsengine/cpulimit/archive/master.zip unzip cpulimit.zip cd cpulimit-master make sudo cp src/cpulimit /usr/bin 上面的命令行,会先从从 GitHub 上将×××到本地,然后再解压、编译、并安装到 /usr/bin 目录下。

cpulimit 的使用方式和 nice 命令类似,但是需要用户使用 -l 选项显式地定义进程的 cpu 使用率上限值。举例说明:

cpulimit -l 50 matho-primes 09999999999>/dev/null&

从上面的例子可以看出 matho-primes 只使用了50%的 cpu 资源,剩余的 cpu 时间都在 idle。

cpulimit 还可以在运行时对进程进行动态限制,使用 -p 选项来指定进程的 PID,下面是一个实例:

cpulimit -l 50-p 1234 其中,1234是进程的 PID。

以下文档见:https://www.cnblogs.com/yanghuahui/p/3751826.html 即可:

本文用脚本运行示例进程,来验证Cgroups关于cpu、内存、io这三部分的隔离效果。

测试机器:CentOS release 6.4 (Final)

启动Cgroups

service cgconfig start #开启cgroups服务 chkconfig cgconfig on #开启启动 在/cgroup,有如下文件夹,默认是多挂载点的形式,即各个子系统的配置在不同的子文件夹下

[root@localhost /]# ls /cgroup/ blkio cpu cpuacct cpuset devices freezer memory net_cls

cgroups管理进程cpu资源 跑一个耗cpu的脚本

x=0 while [ True ];do x=$x+1 done; top可以看到这个脚本基本占了100%的cpu资源

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
30142 root 20 0 104m 2520 1024 R 99.7 0.1 14:38.97 sh 下面用cgroups控制这个进程的cpu资源

mkdir -p /cgroup/cpu/foo/ #新建一个控制组foo echo 50000 > /cgroup/cpu/foo/cpu.cfs_quota_us #将cpu.cfs_quota_us设为50000,相对于cpu.cfs_period_us的100000是50% echo 30142 > /cgroup/cpu/foo/tasks 然后top的实时统计数据如下,cpu占用率将近50%,看来cgroups关于cpu的控制起了效果

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 30142 root 20 0 105m 2884 1024 R 49.4 0.2 23:32.53 sh cpu控制组foo下面还有其他的控制,还可以做更多其他的关于cpu的控制

[root@localhost ~]# ls /cgroup/cpu/foo/ cgroup.event_control cgroup.procs cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_period_us cpu.rt_runtime_us cpu.shares cpu.stat notify_on_release tasks

cgroups管理进程内存资源 跑一个耗内存的脚本,内存不断增长

x="a" while [ True ];do x=$x$x done; top看内存占用稳步上升

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 30215 root 20 0 871m 501m 1036 R 99.8 26.7 0:38.69 sh
30215 root 20 0 1639m 721m 1036 R 98.7 38.4 1:03.99 sh 30215 root 20 0 1639m 929m 1036 R 98.6 49.5 1:13.73 sh 下面用cgroups控制这个进程的内存资源

mkdir -p /cgroup/memory/foo echo 1048576 > /cgroup/memory/foo/memory.limit_in_bytes #分配1MB的内存给这个控制组 echo 30215 > /cgroup/memory/foo/tasks
发现之前的脚本被kill掉

[root@localhost ~]# sh /home/test.sh 已杀死 因为这是强硬的限制内存,当进程试图占用的内存超过了cgroups的限制,会触发out of memory,导致进程被kill掉。

实际情况中对进程的内存使用会有一个预估,然后会给这个进程的限制超配50%比如,除非发生内存泄露等异常情况,才会因为cgroups的限制被kill掉。

也可以通过配置关掉cgroups oom kill进程,通过memory.oom_control来实现(oom_kill_disable 1),但是尽管进程不会被直接杀死,但进程也进入了休眠状态,无法继续执行,仍让无法服务。

关于内存的控制,还有以下配置文件,关于虚拟内存的控制,以及权值比重式的内存控制等

复制代码 [root@localhost /]# ls /cgroup/memory/foo/ cgroup.event_control memory.force_empty memory.memsw.failcnt
memory.memsw.usage_in_bytes memory.soft_limit_in_bytes memory.usage_in_bytes tasks cgroup.procs memory.limit_in_bytes memory.memsw.limit_in_bytes
memory.move_charge_at_immigrate memory.stat memory.use_hierarchy memory.failcnt memory.max_usage_in_bytes memory.memsw.max_usage_in_bytes
memory.oom_control memory.swappiness notify_on_release 复制代码

cgroups管理进程io资源 跑一个耗io的脚本

dd if=/dev/sda of=/dev/null & 通过iotop看io占用情况,磁盘速度到了284M/s

30252 be/4 root 284.71 M/s 0.00 B/s 0.00 % 0.00 % dd if=/dev/sda of=/dev/null
下面用cgroups控制这个进程的io资源

mkdir -p /cgroup/blkio/foo

echo '8:0 1048576' > /cgroup/blkio/foo/blkio.throttle.read_bps_device #8:0对应主设备号和副设备号,可以通过ls -l /dev/sda查看 echo 30252 > /cgroup/blkio/foo/tasks 再通过iotop看,确实将读速度降到了1M/s

30252 be/4 root 993.36 K/s 0.00 B/s 0.00 % 0.00 % dd if=/dev/sda of=/dev/null
对于io还有很多其他可以控制层面和方式,如下

复制代码 [root@localhost ~]# ls /cgroup/blkio/foo/ blkio.io_merged blkio.io_serviced blkio.reset_stats
blkio.throttle.io_serviced blkio.throttle.write_bps_device blkio.weight cgroup.procs blkio.io_queued blkio.io_service_time blkio.sectors
blkio.throttle.read_bps_device blkio.throttle.write_iops_device blkio.weight_device notify_on_release blkio.io_service_bytes blkio.io_wait_time blkio.throttle.io_service_bytes
blkio.throttle.read_iops_device blkio.time cgroup.event_control tasks 复制代码