这很奇怪,我搜索并尝试了所有内容,但我认为我只是在这里犯了一个愚蠢的语法错误。
我正在尝试对CPU运行压力测试,然后立即将其CPU使用率限制为30%,所有这些都是通过PHP进行的。该测试也在另一个用户下运行,并具有指定的名称,因此可以对其进行限制。压力测试开始正常,但我可以看到 PHP 文件仍在加载,并且在压力测试结束时结束。
这是我尝试的一些方法
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30"');
$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s > /dev/null & cpulimit -e MyUniqueProcessName -l 30"');
这样做的全部目的是因为我正在为游戏托管网站编写脚本,我想限制每台服务器的资源消耗以提高质量,而不是让某人占用所有资源。基本上,游戏服务器将运行,而不是压力测试。
编辑::
这是我现在拥有的:
我需要在"测试"下运行压力,但是 sudo apache 或 root 下的 cpulimit,因为它需要特殊权限。压力仍然很好,但它吃了99.9%
passthru('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s &" & sudo cpulimit -e MyUniqueProcessName -l 30 -i -z');
执行此操作后,我在进程列表中看不到 cpulimit https://i.stack.imgur.com/730Eu.png
不幸的是,&&
或多或少与你想要的相反。当您在 Bash 中执行A && B
时,这意味着"运行命令 A 并等待它完成;如果成功,则运行命令 B。
相比之下,A & B
的意思是"运行命令 A,然后立即运行命令 B"。
因此,您的命令接近正确,但只是通过使用两个bash
命令(应该只需要一个)和&&
而被绊倒。
另外,您是否尝试在 PHP 之外的两个终端中分别运行每个命令?我刚刚下载并构建了压力和cpulimit(我假设这些是你正在使用的?),分别运行命令,并发现了一个问题:cpulimit
仍然没有限制百分比。
查看stress
的文档,我看到它通过分叉子进程来工作,因此您尝试限制 CPU 的进程是父进程,但这不是使用 CPU 的进程。 cpulimit --help
揭示了选项-i
,其中包括有限的子进程。
这使我能够在一个终端中输入它(第一行在提示符下显示输入;随后显示输出):
$> exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i
[1] 20229
MyUniqueProcessName: info: [20229] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
Process 20229 found
然后,在另一个运行top
的终端中,我看到:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
20237 stackov+ 20 0 7164 100 0 R 30.2 0.0 0:04.38 stress
好多了。(请注意,在 Bash shell 外部,您用 exec -a
将其别名化,您将看到进程名称为 stress
。不幸的是,我还看到了另一个问题,即cpulimit
"侦听"使用该名称的更多进程。返回 cpulimit --help
,其中显示了-z
选项。
只是为了稍微降低复杂性,您可以关闭别名并通过特殊的 Bash 变量 $!
使用 stress
进程的 PID,它指的是最后一个启动的进程的 PID。在终端中运行以下命令似乎可以执行您想要的所有操作:
stress -c 1 -t 60s & cpulimit -p $! -l 30 -i -z
所以现在,只需用我们学到的东西更改 PHP 脚本:
exec('bash -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i -z"');
。或者,更简单的版本:
exec('bash -c "stress -c 1 -t 60s & cpulimit -p '$! -l 30 -i -z"');
(请注意,$!
中的 $ 必须使用反斜杠转义,'$!
,因为它在传递给 bash -c
时被引用的方式。
最终答案:
根据您修改问题的最后一个示例,您需要这样的东西:
passthru('bash -c "sudo -u test stress -c 1 -t 60s & sudo -u root cpulimit -p '$! -l 30 -i -z"');
当我使用 php stackoverflow-question.php
运行它时,它会输出以下内容:
stress: info: [3374] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [3374] successful run completed in 60s
Process 3371 found
(后两行仅在 PHP 脚本完成后出现,所以不要被误导。使用top
进行检查。
在 PHP 脚本运行的 60 秒内,在另一个终端中运行top
,我看到:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3472 test 20 0 7160 92 0 R 29.5 0.0 0:07.50 stress
3470 root 9 -11 4236 712 580 S 9.0 0.0 0:02.28 cpulimit
这正是您所描述的:stress
在用户test
下运行,cpulimit
在用户root
下运行(如果需要,您可以在命令中更改两者)。 stress
限制在 30% 左右。
我不熟悉runuser
,也没有看到适用性,因为sudo
是以其他用户身份运行进程的标准方式。要使其正常工作,您可能需要在/etc/sudoers 中调整您的设置(这将需要 root 访问权限,但您显然已经拥有了)。这完全超出了本次讨论的范围,但作为示例,我添加了以下规则:
my-user ALL=(test) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/stress
my-user ALL=(root) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/cpulimit