场景介绍
在高并发、高可用的服务架构中,核心服务(如 Redis、API 接口服务等)的稳定性直接影响业务连续性。一旦服务宕机,即使是短时间中断也可能造成重大损失。传统 Linux 定时任务 crontab 最小粒度为分钟级,无法满足实时监控需求。
Swoole 提供的毫秒级定时器可实现高频次服务状态检测,结合报警机制(短信、邮件等),能快速响应服务异常,为运维人员争取修复时间,是保障服务高可用的重要方案。
环境要求
1. 基础环境
已安装 PHP 运行环境(版本需与 Swoole 扩展兼容)。
2. 核心依赖
已安装 Swoole 扩展(推荐使用最新稳定版,确保定时器功能兼容性)。
3. 系统权限
运行脚本的用户需具备执行系统命令(如 netstat)、读写日志文件的权限。
核心实现思路
1. 监控目标
通过端口检测服务存活状态(如 Redis 默认端口 6379、自定义服务端口 8811)。
2. 检测频率
利用 Swoole 毫秒定时器(swoole_timer_tick),每 2 秒执行一次检测(可按需调整频率)。
3. 报警逻辑
服务异常时触发报警(短信、邮件),并停止该服务的监控定时器,避免重复报警。
4. 后台运行
通过 nohup 命令让脚本在后台持续运行,确保监控不中断。
代码实现
脚本文件:ServiceMonitoring.php
<?php
declare(strict_types = 1);
/**
* Swoole 服务监控类
* 基于端口检测服务存活状态,结合毫秒定时器实现实时监控与报警
*/
class ServiceMonitoring
{
/**
* 监控指定端口的服务是否正常运行
* 原理:通过 netstat 命令查询端口监听状态,统计监听进程数
*
* @param int $port 待监控服务端口号
* @return bool 服务正常返回 true,异常返回 false
*/
public function monitoringPort(int $port): bool
{
// 系统命令:查询指定端口的监听进程数(2>/dev/null 忽略错误输出)
$shellCommand = "netstat -anp 2>/dev/null | grep {$port} | grep LISTEN | wc -l";
// 执行 shell 命令并获取结果
$result = shell_exec($shellCommand);
// 结果判断:返回 1 表示端口正常监听(服务运行中),否则服务异常
if (trim($result) != 1) {
$errorMsg = date('Y-m-d H:i:s') . "---- 端口号为 {$port} 的服务已挂掉 -----". PHP_EOL;
echo $errorMsg;
// TODO:添加报警逻辑(按需启用)
// $this->sendEmailAlert($port); // 发送邮件给管理员
// $this->sendSmsAlert($port); // 发送短信给管理员
return false;
} else {
$successMsg = date('Y-m-d H:i:s') . "---- 端口号为 {$port} 的服务正常运行 -----". PHP_EOL;
echo $successMsg;
return true;
}
}
/**
* (可选)发送邮件报警
* @param int $port 异常服务端口
*/
private function sendEmailAlert(int $port): void
{
$to = 'admin@example.com'; // 管理员邮箱
$subject = "【服务异常报警】端口 {$port} 服务宕机";
$message = "报警时间:" . date('Y-m-d H:i:s') . "\n异常服务:端口 {$port} 的服务已停止运行,请及时排查修复!";
// 邮件发送逻辑(可使用 PHP mail 函数或第三方邮件 SDK)
mail($to, $subject, $message);
}
/**
* (可选)发送短信报警
* @param int $port 异常服务端口
*/
private function sendSmsAlert(int $port): void
{
$phone = '13800138000'; // 管理员手机号
$content = "【服务异常报警】端口 {$port} 的服务于 " . date('Y-m-d H:i:s') . " 宕机,请及时处理!";
// 短信发送逻辑(对接第三方短信 API,如阿里云短信、腾讯云短信等)
// $this->callSmsApi($phone, $content);
}
}
/**
* 初始化毫秒定时器,开始监控指定端口
* 定时器频率:2000 毫秒(2 秒/次),可根据需求调整(如 1000 毫秒 = 1 秒/次)
* 逻辑:服务异常时清除定时器,避免重复报警;服务修复后需重启脚本恢复监控
*/
// 监控端口 8811(示例:自定义 API 服务)
swoole_timer_tick(2000, function ($timerId) {
$monitor = new ServiceMonitoring();
if (!$monitor->monitoringPort(8811)) {
swoole_timer_clear($timerId); // 服务异常,停止该端口监控
echo date('Y-m-d H:i:s') . "---- 端口 8811 监控已暂停,待服务修复后重启脚本 -----\n";
}
});
// 监控端口 6379(示例:Redis 服务)
swoole_timer_tick(2000, function ($timerId) {
$monitor = new ServiceMonitoring();
if (!$monitor->monitoringPort(6379)) {
swoole_timer_clear($timerId); // 服务异常,停止该端口监控
echo date('Y-m-d H:i:s') . "---- 端口 6379 监控已暂停,待服务修复后重启脚本 -----\n";
}
});
代码说明
类与方法:
-
ServiceMonitoring类:封装服务监控核心逻辑,包含端口检测、报警触发方法。 -
monitoringPort(int $port):核心检测方法,通过netstat命令查询端口监听状态,返回服务存活结果。 -
可选报警方法:
sendEmailAlert、sendSmsAlert,可根据实际业务对接邮件/短信服务。
定时器逻辑:
-
swoole_timer_tick(2000, $callback):创建周期性定时器,每 2000 毫秒执行一次回调函数。 -
swoole_timer_clear($timerId):服务异常时清除定时器,避免重复发送报警信息。
脚本运行与日志配置
1. 后台运行脚本
由于脚本需要持续监控,需通过 nohup 命令让其在后台运行(断开 SSH 连接后仍可正常工作),命令格式如下:
nohup /usr/local/php/bin/php /data/script/swoole/ServiceMonitoring.php > /logs/script/monitor.log 2>&1 &
2. 参数详解
| 部分 | 说明 |
|---|---|
nohup |
忽略挂起信号,确保脚本后台持续运行 |
/usr/local/php/bin/php |
PHP 解释器的绝对路径(需根据实际安装路径调整,可通过 which php 命令查询) |
/data/script/swoole/ServiceMonitoring.php |
监控脚本的绝对路径(需替换为实际存放路径) |
> /logs/script/monitor.log |
重定向脚本输出日志到指定文件(需确保目录存在且有写入权限) |
2>&1 |
将错误输出合并到日志文件(便于排查脚本运行异常) |
& |
让命令在后台运行 |
实现效果与验证
1. 正常运行效果
脚本运行后,日志文件(monitor.log)会持续输出服务状态信息:
2024-05-20 14:30:00---- 端口号为 8811 的服务正常运行 -----
2024-05-20 14:30:00---- 端口号为 6379 的服务正常运行 -----
2024-05-20 14:30:02---- 端口号为 8811 的服务正常运行 -----
2024-05-20 14:30:02---- 端口号为 6379 的服务正常运行 -----
2. 服务异常效果
当某端口服务宕机时,日志会输出报警信息,并暂停该端口监控:
2024-05-20 14:30:04---- 端口号为 6379 的服务已挂掉 -----
2024-05-20 14:30:04---- 端口 6379 监控已暂停,待服务修复后重启脚本 -----
3. 服务恢复流程
-
运维人员通过报警信息(邮件/短信)排查并修复异常服务。
-
修复完成后,重新执行
nohup命令启动脚本,恢复该端口的监控。
扩展与优化
1. 监控扩展:除端口检测外,可新增监控项,如:
-
内存使用率:通过
free -m命令监控服务器内存占用。 -
硬盘空间:通过
df -h命令监控磁盘剩余空间。 -
接口响应时间:通过
curl命令请求核心接口,判断响应是否超时。
2. 报警优化:
-
避免报警风暴:可添加“连续 N 次检测异常才触发报警”的逻辑(如连续 3 次检测到服务宕机再发送报警)。
-
多渠道报警:同时集成邮件、短信、企业微信/钉钉机器人,确保报警信息及时触达。
3. 脚本稳定性:
-
添加进程守护:结合 Swoole Process 或第三方工具(如 Supervisor),确保脚本意外退出后自动重启。
-
日志轮转:配置日志轮转工具(如 logrotate),避免日志文件过大。
4. 端口配置:将待监控端口整理为配置数组,便于批量管理,示例:
$monitorPorts = [8811, 6379, 8080]; // 待监控端口列表
foreach ($monitorPorts as $port) {
swoole_timer_tick(2000, function ($timerId) use ($port) {
$monitor = new ServiceMonitoring();
if (!$monitor->monitoringPort($port)) {
swoole_timer_clear($timerId);
echo date('Y-m-d H:i:s') . "---- 端口 {$port} 监控已暂停,待服务修复后重启脚本 -----\n";
}
});
}
注意事项
1. 权限问题
确保运行脚本的用户有权限执行 netstat 命令(部分系统可能需要 root 权限)。
2. 端口占用
避免监控端口被非目标服务占用,导致误报警。
3. Swoole 版本
低版本 Swoole 可能存在定时器bug,务必确保版本 ≥ 2.2。
4. 资源占用
监控频率过高(如 ≤ 500 毫秒/次)可能占用较多系统资源,需根据服务器配置合理调整。


