getrusage() 是一个 PHP 原生函数,用于获取当前进程或其子进程的资源使用情况。它返回一个数组,包含了多个系统层面的数据,例如用户态/内核态 CPU 时间、内存页故障次数、上下文切换次数等。
$usage = getrusage();
常用的几个字段包括:
ru_utime.tv_sec 与 ru_utime.tv_usec:用户态消耗的时间(秒和微秒)
ru_stime.tv_sec 与 ru_stime.tv_usec:系统态消耗的时间(秒和微秒)
ru_minflt:无需从磁盘调入的页错误数量(软缺页)
ru_majflt:从磁盘调入的页错误数量(硬缺页)
ru_nvcsw 和 ru_nivcsw:自愿和非自愿上下文切换次数
要监控数据库查询对系统的影响,最直接的方式是:
在查询前记录一次 getrusage();
执行查询;
查询后再次记录一次 getrusage();
对比两次记录的差值。
示例代码如下:
function getResourceUsageDiff($start, $end) {
$diff = [];
foreach ($end as $key => $value) {
if (isset($start[$key])) {
$diff[$key] = $value - $start[$key];
}
}
return $diff;
}
$before = getrusage();
// 模拟数据库查询
$mysqli = new mysqli("localhost", "user", "password", "database");
$result = $mysqli->query("SELECT * FROM users WHERE email LIKE '%@example.com'");
$after = getrusage();
$usageDiff = getResourceUsageDiff($before, $after);
echo "<pre>";
print_r($usageDiff);
echo "
";
此代码可以输出查询所产生的系统资源变化。例如,如果你看到 ru_stime.tv_usec 明显上升,则说明该查询引起了系统态 CPU 的增加,可能存在大量 I/O 操作。
为了更实用,可以将测量过程封装成一个函数,支持自动记录查询语句和资源变化:
function profileQuery($query, $mysqli) {
$before = getrusage();
$result = $mysqli->query($query);
$after = getrusage();
$usageDiff = getResourceUsageDiff($before, $after);
file_put_contents("/var/log/db_profile.log", json_encode([
'query' => $query,
'usage' => $usageDiff,
'time' => date('c')
]) . PHP_EOL, FILE_APPEND);
return $result;
}
这种方式可以让你在不打扰正常逻辑的同时,持续收集查询对系统资源的影响,从而为后续优化提供依据。
对比不同索引结构的影响
使用相同条件、不同索引结构的查询,比较系统资源占用,可以直观评估索引调整是否有效。
监控批量查询或大数据分页性能
当面对分页或批量查询时,观察 ru_majflt、ru_nvcsw 是否增长,可以判断查询是否触发了大量内存调页或上下文切换。
在压力测试中对比资源使用
配合 Apache Benchmark、JMeter 等工具进行并发测试,记录资源占用变化,分析系统在高负载下的表现。
如果你希望调试时在浏览器中更清晰地查看 getrusage() 的变化,可以使用如下代码格式化输出:
function formatUsage(array $usage) {
return sprintf(
"User CPU: %.4fs, System CPU: %.4fs, Major Faults: %d, Voluntary CS: %d",
$usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1e6,
$usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1e6,
$usage['ru_majflt'] ?? 0,
$usage['ru_nvcsw'] ?? 0
);
}
echo formatUsage($usageDiff);