PHP服务器监控与性能指标采集
PHP服务器监控与性能指标采集
服务器监控是运维的重要环节。PHP可以直接采集系统指标,包括CPU、内存、磁盘、网络等。今天说说PHP服务器监控的实现。
PHP可以通过读取/proc文件系统获取系统状态。
```php
class SystemMonitor
{
public function getCpuUsage(): array
{
$cpuInfo = file_get_contents('/proc/stat');
preg_match('/^cpu\s+(.*)$/m', $cpuInfo, $matches);
$parts = preg_split('/\s+/', $matches[1]);
$total = array_sum($parts);
$idle = $parts[3];
return [
'user' => round($parts[0] / $total * 100, 2),
'system' => round($parts[2] / $total * 100, 2),
'idle' => round($idle / $total * 100, 2),
'iowait' => round(($parts[4] ?? 0) / $total * 100, 2),
];
}
public function getMemoryUsage(): array
{
$memInfo = file_get_contents('/proc/meminfo');
$data = [];
preg_match_all('/^(\w+):\s+(\d+)\skB$/m', $memInfo, $matches);
foreach ($matches[1] as $i => $name) {
$data[$name] = (int)$matches[2][$i];
}
$total = $data['MemTotal'] ?? 0;
$free = $data['MemFree'] ?? 0;
$available = $data['MemAvailable'] ?? $free;
$used = $total - $available;
return [
'total_mb' => round($total / 1024, 2),
'used_mb' => round($used / 1024, 2),
'free_mb' => round($available / 1024, 2),
'usage_percent' => $total > 0 ? round($used / $total * 100, 2) : 0,
];
}
public function getDiskUsage(): array
{
$path = '/';
return [
'total_gb' => round(disk_total_space($path) / 1024 / 1024 / 1024, 2),
'free_gb' => round(disk_free_space($path) / 1024 / 1024 / 1024, 2),
'used_gb' => round((disk_total_space($path) - disk_free_space($path)) / 1024 / 1024 / 1024, 2),
'usage_percent' => round((1 - disk_free_space($path) / disk_total_space($path)) * 100, 2),
];
}
public function getLoadAverage(): array
{
$load = sys_getloadavg();
return [
'1min' => round($load[0], 2),
'5min' => round($load[1], 2),
'15min' => round($load[2], 2),
];
}
public function getUptime(): array
{
$uptime = (int)file_get_contents('/proc/uptime');
return [
'seconds' => $uptime,
'formatted' => sprintf(
'%d天 %02d:%02d:%02d',
intdiv($uptime, 86400),
intdiv($uptime % 86400, 3600),
intdiv($uptime % 3600, 60),
$uptime % 60
),
];
}
public function getNetworkStats(): array
{
$netInfo = file_get_contents('/proc/net/dev');
$interfaces = [];
preg_match_all('/^\s*(eth\d+|ens\d+|enp\d+s\d+):\s*(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)/m', $netInfo, $matches);
foreach ($matches[1] as $i => $iface) {
$interfaces[$iface] = [
'rx_bytes' => (int)$matches[2][$i],
'tx_bytes' => (int)$matches[3][$i],
];
}
return $interfaces;
}
public function getPhpInfo(): array
{
return [
'version' => PHP_VERSION,
'sapi' => php_sapi_name(),
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'post_max_size' => ini_get('post_max_size'),
'upload_max_filesize' => ini_get('upload_max_filesize'),
'opcache_enabled' => function_exists('opcache_get_status') ? true : false,
];
}
public function getAllMetrics(): array
{
return [
'timestamp' => date('Y-m-d H:i:s'),
'uptime' => $this->getUptime(),
'cpu' => $this->getCpuUsage(),
'memory' => $this->getMemoryUsage(),
'disk' => $this->getDiskUsage(),
'load' => $this->getLoadAverage(),
'network' => $this->getNetworkStats(),
'php' => $this->getPhpInfo(),
];
}
}
$monitor = new SystemMonitor();
$metrics = $monitor->getAllMetrics();
echo json_encode($metrics, JSON_PRETTY_PRINT) . "\n";
?>
```
监控指标的持久化和告警。
```php
class MetricsStorage
{
private PDO $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
$this->initTable();
}
private function initTable(): void
{
$this->pdo->exec("
CREATE TABLE IF NOT EXISTS metrics (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
metric_name VARCHAR(100) NOT NULL,
metric_value DECIMAL(15, 4) NOT NULL,
tags JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_name_created (metric_name, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
}
public function store(string $name, float $value, array $tags = []): void
{
$stmt = $this->pdo->prepare("INSERT INTO metrics (metric_name, metric_value, tags) VALUES (?, ?, ?)");
$stmt->execute([$name, $value, json_encode($tags)]);
}
public function getHistory(string $name, int $minutes = 60): array
{
$stmt = $this->pdo->prepare("
SELECT metric_value, created_at FROM metrics
WHERE metric_name = ? AND created_at > DATE_SUB(NOW(), INTERVAL ? MINUTE)
ORDER BY created_at ASC
");
$stmt->execute([$name, $minutes]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function cleanup(int $keepDays = 30): int
{
$stmt = $this->pdo->prepare("DELETE FROM metrics WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)");
$stmt->execute([$keepDays]);
return $stmt->rowCount();
}
}
class AlertRule
{
public function __construct(
public string $metric,
public float $threshold,
public string $operator = '>',
public string $message = ''
) {}
public function check(float $value): bool
{
return match ($this->operator) {
'>' => $value > $this->threshold,
'<' => $value < $this->threshold,
'>=' => $value >= $this->threshold,
'<=' => $value <= $this->threshold,
'==' => $value == $this->threshold,
default => false,
};
}
}
class AlertManager
{
private array $rules = [];
public function addRule(AlertRule $rule): void
{
$this->rules[] = $rule;
}
public function checkMetrics(array $metrics): array
{
$alerts = [];
foreach ($this->rules as $rule) {
$value = $this->extractMetric($metrics, $rule->metric);
if ($value !== null && $rule->check($value)) {
$alerts[] = [
'metric' => $rule->metric,
'value' => $value,
'threshold' => $rule->threshold,
'message' => $rule->message ?: "{$rule->metric} {$rule->operator} {$rule->threshold},当前值: {$value}",
'time' => date('Y-m-d H:i:s'),
];
}
}
return $alerts;
}
private function extractMetric(array $metrics, string $path): ?float
{
$parts = explode('.', $path);
$current = $metrics;
foreach ($parts as $part) {
if (!isset($current[$part])) return null;
$current = $current[$part];
}
return is_numeric($current) ? (float)$current : null;
}
}
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$storage = new MetricsStorage($pdo);
$monitor = new SystemMonitor();
$alertManager = new AlertManager();
$alertManager->addRule(new AlertRule('cpu.user', 80, '>', 'CPU使用率超过80%'));
$alertManager->addRule(new AlertRule('memory.usage_percent', 90, '>', '内存使用率超过90%'));
$alertManager->addRule(new AlertRule('disk.usage_percent', 85, '>', '磁盘使用率超过85%'));
$alertManager->addRule(new AlertRule('load.1min', 8, '>', '系统负载过高'));
// 采集并检查
$metrics = $monitor->getAllMetrics();
$storage->store('cpu.user', $metrics['cpu']['user']);
$storage->store('memory.usage', $metrics['memory']['usage_percent']);
$storage->store('disk.usage', $metrics['disk']['usage_percent']);
$alerts = $alertManager->checkMetrics($metrics);
if (!empty($alerts)) {
foreach ($alerts as $alert) {
echo "[告警] {$alert['message']}\n";
}
} else {
echo "系统运行正常\n";
}
?>
```
服务器监控是运维自动化的基础。PHP虽然不是专门的监控工具,但通过读取系统文件和调用系统命令,可以实现基本的监控功能。生产环境建议使用Prometheus、Grafana等专业的监控系统。
