本文目录导读:

在 PHP 项目中使用 Swoole 扩展搭建服务,核心是利用 Swoole 提供的 Server 类(如 Http\Server、WebSocket\Server 或 TCP/UDP Server)来替代传统的 Apache/Nginx + PHP-FPM 架构。
以下是详细的搭建步骤,以最常见的 HTTP 服务为例,涵盖环境准备、代码编写、启动运行和守护进程化。
第一步:环境准备与安装 Swoole 扩展
-
确认 PHP 版本:Swoole 需要 PHP 7.2 或更高版本(推荐 PHP 8.x)。
php -v
-
安装 Swoole 扩展(推荐使用 PECL,更简单):
sudo pecl install swoole
编译安装(PECL 失败,或者需要自定义编译参数):
# 下载源码 git clone https://github.com/swoole/swoole-src.git cd swoole-src # 初始化子模块(如果编译报错缺头文件) git checkout v5.1.x # 指定版本 phpize ./configure make -j$(nproc) sudo make install
-
启用扩展:在
php.ini中添加extension=swoole,然后重启 PHP 或 FPM。echo "extension=swoole" | sudo tee -a /etc/php/8.x/cli/conf.d/swoole.ini php -m | grep swoole # 确认已安装
第二步:创建 HTTP 服务(核心步骤)
Swoole 服务是一个常驻内存的进程,通过 CLI 模式运行,而不是通过 Web 服务器转发。
创建文件 server.php:
<?php
// 创建一个 HTTP 服务器对象
// 参数1:监听地址(0.0.0.0 表示所有 IP)
// 参数2:监听端口(建议 9501 及以上,避免权限问题)
$server = new Swoole\Http\Server('0.0.0.0', 9501);
// 设置运行时参数(重要)
$server->set([
'worker_num' => 4, // Worker 进程数,建议为 CPU 核心数的 1-4 倍
'daemonize' => false, // 是否守护进程化(开发时设为 false,生产设为 true)
'max_request' => 10000, // 每个 Worker 进程处理完多少请求后重启(防止内存泄漏)
'log_file' => '/tmp/swoole_http.log', // 错误日志路径
]);
// 注册事件回调函数:当有请求到达时
$server->on('request', function ($request, $response) {
// $request 对象包含请求信息:GET, POST, HEADER, SERVER 等
// $response 对象用于返回响应
$uri = $request->server['request_uri'];
// 简单的路由分发示例
if ($uri === '/') {
$response->header('Content-Type', 'text/html; charset=utf-8');
$response->end('<h1>Hello, Swoole!</h1>');
} elseif ($uri === '/api/user') {
$response->header('Content-Type', 'application/json');
$data = ['name' => 'Tom', 'age' => 25];
$response->end(json_encode($data));
} else {
$response->status(404);
$response->end('Not Found');
}
});
// 启动服务器(阻塞在这里)
echo "Server started at http://0.0.0.0:9501\n";
$server->start();
代码解释:
- 服务器运行在 CLI 模式,与 Nginx/FPM 完全独立。
on('request')是最常用的回调,每次 HTTP 请求都会触发。$response->end()必须调用,否则连接会挂起。
第三步:启动与测试
-
启动服务:
php server.php
你会在控制台看到:
Server started at http://0.0.0.0:9501 -
测试访问(另开一个终端):
curl http://127.0.0.1:9501/ # 输出: <h1>Hello, Swoole!</h1> curl http://127.0.0.1:9501/api/user # 输出: {"name":"Tom","age":25}
第四步:生产环境配置(守护进程 + 进程管理)
-
修改
server.php配置:将'daemonize' => false改为true,并设置log_file。 -
使用 Supervisor 管理进程(强烈推荐,自动重启、日志轮转):
- 安装 Supervisor:
sudo apt install supervisor(Ubuntu) 或yum install supervisor - 添加配置
/etc/supervisor/conf.d/swoole-http.conf:[program:swoole-http] command=php /path/to/your/server.php user=www-data autostart=true autorestart=true startretries=3 stderr_logfile=/var/log/swoole-http.err.log stdout_logfile=/var/log/swoole-http.out.log
- 启动:
sudo supervisorctl reread && sudo supervisorctl update
- 安装 Supervisor:
第五步:高级配置与优化
-
配置 Nginx 反向代理(如果需要对外网暴露且想保留静态文件处理能力):
server { listen 80; server_name yourdomain.com; # 静态文件由 Nginx 直接处理 location /static/ { root /path/to/your/static; } # 动态请求转发到 Swoole location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://127.0.0.1:9501; # 转发到 Swoole HTTP 服务 } } -
处理热重载(代码变更后不停止服务): Swoole 自带
Reload机制,修改代码后执行:# 假设你的主进程 PID 为 12345 kill -USR1 12345 # 重启所有 Worker 进程
或者使用 Swoole 的
--reload参数(如果你通过start脚本管理)。 -
使用常量连接池(操作 Redis/MySQL): Swoole 的 Worker 进程是常驻内存的,可以在
onWorkerStart回调中初始化数据库连接池,避免每次请求都建立新连接。$server->on('WorkerStart', function ($server, $workerId) { // 每个 Worker 启动时,创建一次 Redis 连接 RedisPool::getInstance()->createConnections(); });
常见问题与注意点
| 问题 | 解决方案 |
|---|---|
| 端口被占用 | sudo lsof -i :9501 查看占用进程,kill -9 PID 或改端口。 |
| 内存泄漏 | 合理设置 max_request(如 10000),让 Worker 定期重启。 |
| 协程环境下的全局变量 | 避免使用 static 或 global 变量跨协程共享数据,使用 Swoole\Table 或 Redis。 |
| 代码修改未生效 | 需要重启 Swoole 服务或发送 USR1 信号,不能像 FPM 那样热加载 PHP 文件。 |
| 异步任务 | 使用 $server->task($data) 和 on('Task') 回调处理耗时操作(如发送邮件)。 |
总结流程
- 环境:安装 Swoole 扩展 (
pecl install swoole)。 - 创建:写一个
server.php,使用Swoole\Http\Server监听端口并注册on('request')。 - 启动:
php server.php(开发)或通过 Supervisord 管理(生产)。 - 访问:
http://ip:9501/。 - 优化:Nginx 反向代理(可选)、代码热重载、连接池。
Swoole 的优势在于性能高(常驻内存、协程调度)、资源消耗低(相比 FPM 减少 80% 的上下文切换),适合开发长连接服务(WebSocket/IM)、高性能 API 网关或实时游戏后端。