Всем привет.
Сегодня я расскажу о том, как с помощью php собирать информацию о состоянии нагрузки сервера и выводить это в виде красивого графика Highcharts.
Данная задача была реализована на Yii2 на сервере с Debian.
Начнем!
Для начала нужно удостовериться, что у пользователя под которым будет выполняться процесс сбора статистики есть доступ на чтение к следующим файлам:
/proc/stat
/proc/meminfo
Информация которую будем собирать и хранить:
Загрузка процессора
Информация об оперативной памяти: объем доступной памяти в ГБ и в процентах
Информация о жестких дисках: доступный объем в ГБ и в процентах. На моем сервере установлен ssd диск и обычный sata. Будем собирать информацию по обоим.
Для хранения информации создадим таблицу в БД
CREATE TABLE `server_stat` (
`id` int(11) NOT NULL,
`date_create` datetime NOT NULL,
`cpu` double NOT NULL,
`memory` double NOT NULL,
`ssd` double NOT NULL,
`sata` double NOT NULL,
`memory_percent` int(11) NOT NULL,
`ssd_percent` int(11) NOT NULL,
`sata_percent` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `server_stat`
ADD PRIMARY KEY (`id`);
ALTER TABLE `server_stat`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Описание полей таблицы:
id - идентификатор записи
date_create - дата создания
cpu - загрузка процессора
memory - доступная память в ГБ
ssd - доступное место на ssd диске в ГБ
sata - доступное место на sata диске в ГБ
memory_percent - доступная память в %
ssd_percent - доступное место на ssd диске в %
sata_percent - доступное место на sata диске в %
После создания таблицы нужно создать модель ServerStat. Для упрощения этого действия воспользуйтесь Gii.
Далее в контролере, который будет заниматься сбором данных создайте метод actionServerStat
Чтобы не писать весь код к контроллере создадим хелпер StatHelper, который будет выполнять следующие дествия:
Вычисление загрузки процессора
Вычисления свободной оперативной памяти
Вычисление свободного места на дисках
Хелперы я храню в нэймспэйсе app\components\helpers
Код хелпера:
<?php
namespace app\components\helpers;
class StatHelper{
// загрузка процессора
static public function getCpu(){
$file = '/proc/stat';
//проверяем возможность чтения виртуальной директории
if (@is_readable($file)){
//делаем первый замер
$file_first = file($file);
//определяем значения состояний (описаны выше)
$tmp_first = explode(" ",$file_first[0]);
$cpu_user_first = $tmp_first[2];
$cpu_nice_first = $tmp_first[3];
$cpu_sys_first = $tmp_first[4];
$cpu_idle_first = $tmp_first[5];
$cpu_io_first = $tmp_first[6];
sleep(2);//промежуток до второго замера
//делаем второй замер
$file_second = file($file);
$tmp_second = explode(" ",$file_second[0]);
$cpu_user_second= $tmp_second[2];
$cpu_nice_second= $tmp_second[3];
$cpu_sys_second = $tmp_second[4];
$cpu_idle_second= $tmp_second[5];
$cpu_io_second = $tmp_second[6];
//определяем разницу использованного процессорного времени
$diff_used = ($cpu_user_second-$cpu_user_first)+($cpu_nice_second-$cpu_nice_first)+($cpu_sys_second-$cpu_sys_first)+($cpu_io_second-$cpu_io_first);
//определяем разницу общего процессорного времени
$diff_total = ($cpu_user_second-$cpu_user_first)+(
$cpu_nice_second-$cpu_nice_first)+($cpu_sys_second-$cpu_sys_first)+($cpu_io_second-$cpu_io_first)+($cpu_idle_second-$cpu_idle_first);
//определение загрузки cpu
$cpu = round($diff_used/$diff_total, 2);
return $cpu * 100;
}
return null;
}
// статистика памяти
static public function getMemory(){
$memory = [
'full' => 0,
'free' => 0
];
$fh = fopen('/proc/meminfo','r');
if(!$fh)
return null;
while ($line = fgets($fh)) {
$pieces = [];
if (preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces))
$memory['full'] = round($pieces[1]/1024, 2);
if (preg_match('/^MemAvailable:\s+(\d+)\skB$/', $line, $pieces))
$memory['free'] = round($pieces[1]/1024, 2);
if($memory['full'] && $memory['free'])
break;
}
fclose($fh);
return $memory;
}
//статистика дисков
static public function getHdd(){
$sata = [
'full' => 0,
'free' => 0,
];
foreach(['disk1', 'disk300', 'disk50', 'disk500'] as $disk){
$sata['full'] += disk_total_space('/media/'.$disk)/1024/1024/1024;
$sata['free'] += disk_free_space('/media/'.$disk)/1024/1024/1024;
}
return [
'ssd' => [
'full' => round(disk_total_space('/')/1024/1024/1024, 2),
'free' => round(disk_free_space('/')/1024/1024/1024, 2),
],
'sata' => [
'full' => round($sata['full'], 2),
'free' => round($sata['free'], 2)
]
];
}
}
К сожалению данный редактор не поддерживает красивое форматирование кода …
Теперь вкратце расскажу, что делают данные методы
Метод getCpu:
Данный метод берет показания процессорного времени из файл системы /proc/stat
Сначала делается первый замер и после небольшой задержки второй, после чего вычисляется разница общего и использованного процессорного времени. Отсюда вычисляется загрузка, как отношение использованного к общему
Метод getMemory:
Данный метод берет показания из файл системы /proc/meminfo
В нем ищем строки MemTotal и MemAvailable и разбираем их регулярным выражением
Метод getHdd:
В моем случае жесткие диски примонтированы следующим образом:
/ - ssd диск
/media/disk1, /media/disk300, /media/disk50, /media/disk500 - разделы sata диска
Так как я хочу получить общие показания, то будем суммировать собранную информацию по каждому разделу диска
Для вычислений используются php функции disk_total_space и disk_free_space
Теперь применим эти методы. Код контроллера:
use app\models\ServerStat;
….
public function actionServerStat(){
$cpu = StatHelper::getCpu();
$memory = StatHelper::getMemory();
$hdd = StatHelper::getHdd();
$stat = new ServerStat();
$stat->date_create = (new \DateTime)->format('Y-m-d H:i:s');
$stat->cpu = $cpu;
$stat->memory = $memory['free'];
$stat->ssd = $hdd['ssd']['free'];
$stat->sata = $hdd['sata']['free'];
$stat->memory_percent = 100 - intval($memory['free'] * 100 / $memory['full']);
$stat->ssd_percent = 100 - intval($hdd['ssd']['free'] * 100 / $hdd['ssd']['full']);
$stat->sata_percent = 100 - intval($hdd['sata']['free'] * 100 / $hdd['sata']['full']);
$stat->save();
}
Собираем всю информацию, вычисляем процентные значения и записываем в таблицу.
Далее ставим данный скрипт в крон. Если не делали этого на Yii2, воспользуйтесь моим небольшим руководством Yii2 cron задачи
Во второй части опишу процесс вывода собранных данных в виде графика HighCharts.
Есть вопросы, пишите в комментарии.
Спасибо за внимание.