PHP Swoole实战指南
引言
Swoole是一个为PHP提供高性能网络通信能力的扩展。本文将介绍如何使用Swoole构建高性能的PHP应用。
基础概念
什么是Swoole
Swoole是一个PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了多进程、异步IO、协程等特性。
环境搭建
安装Swoole
bash
# 通过PECL安装
pecl install swoole
# 或者从源码编译
wget https://github.com/swoole/swoole-src/archive/v4.8.12.tar.gz
tar zxvf v4.8.12.tar.gz
cd swoole-src-4.8.12
phpize
./configure
make && make install
配置PHP
ini
[swoole]
extension=swoole.so
HTTP服务器
基础HTTP服务器
php
<?php
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$server = new Server("0.0.0.0", 9501);
$server->on("start", function (Server $server) {
echo "Swoole http server is started at http://0.0.0.0:9501\n";
});
$server->on("request", function (Request $request, Response $response) {
$response->header("Content-Type", "text/plain");
$response->end("Hello World\n");
});
$server->start();
路由处理
php
<?php
class Router
{
private $routes = [];
public function get($path, $handler)
{
$this->routes["GET"][$path] = $handler;
}
public function post($path, $handler)
{
$this->routes["POST"][$path] = $handler;
}
public function dispatch($request)
{
$method = $request->server["request_method"];
$path = $request->server["request_uri"];
if (isset($this->routes[$method][$path])) {
return $this->routes[$method][$path]($request);
}
return ["status" => 404, "message" => "Not Found"];
}
}
// 使用路由
$router = new Router();
$router->get("/users", function ($request) {
return ["status" => 200, "data" => ["users" => []]];
});
WebSocket服务器
WebSocket实现
php
<?php
use Swoole\WebSocket\Server;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
$server = new Server("0.0.0.0", 9502);
$server->on("start", function (Server $server) {
echo "WebSocket server is started at ws://0.0.0.0:9502\n";
});
$server->on("open", function (Server $server, Request $request) {
echo "connection open: {$request->fd}\n";
});
$server->on("message", function (Server $server, Frame $frame) {
echo "received message: {$frame->data}\n";
$server->push($frame->fd, "server: {$frame->data}");
});
$server->on("close", function (Server $server, int $fd) {
echo "connection close: {$fd}\n";
});
$server->start();
协程编程
协程基础
php
<?php
use Swoole\Coroutine;
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
$server = new Server("0.0.0.0", 9501);
$server->on("request", function (Request $request, Response $response) {
// 创建协程
Coroutine::create(function () use ($response) {
// 模拟耗时操作
Coroutine::sleep(1);
$response->end("Hello from coroutine\n");
});
});
$server->start();
协程MySQL
php
<?php
use Swoole\Coroutine\MySQL;
Coroutine::create(function () {
$mysql = new MySQL();
$mysql->connect([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'test',
]);
$result = $mysql->query('SELECT * FROM users');
var_dump($result);
});
连接池
MySQL连接池
php
<?php
class MySQLPool
{
private $pool = [];
private $config;
private $size;
public function __construct($config, $size = 10)
{
$this->config = $config;
$this->size = $size;
}
public function get()
{
if (empty($this->pool)) {
$mysql = new Swoole\Coroutine\MySQL();
$mysql->connect($this->config);
return $mysql;
}
return array_pop($this->pool);
}
public function put($mysql)
{
if (count($this->pool) < $this->size) {
array_push($this->pool, $mysql);
}
}
}
// 使用连接池
$pool = new MySQLPool([
'host' => '127.0.0.1',
'user' => 'root',
'password' => 'root',
'database' => 'test',
]);
Coroutine::create(function () use ($pool) {
$mysql = $pool->get();
$result = $mysql->query('SELECT * FROM users');
$pool->put($mysql);
});
任务处理
异步任务
php
<?php
use Swoole\Server;
$server = new Server("127.0.0.1", 9503);
$server->set([
'task_worker_num' => 4,
]);
$server->on("receive", function (Server $server, $fd, $reactor_id, $data) {
// 投递异步任务
$task_id = $server->task($data);
$server->send($fd, "异步任务投递成功,task_id: {$task_id}\n");
});
$server->on("task", function (Server $server, $task_id, $reactor_id, $data) {
// 处理异步任务
echo "处理异步任务: {$data}\n";
// 返回任务处理结果
return "task {$task_id} 完成";
});
$server->on("finish", function (Server $server, $task_id, $data) {
echo "异步任务完成: {$data}\n";
});
$server->start();
性能优化
内存管理
php
<?php
// 设置进程内存限制
ini_set('memory_limit', '256M');
// 定时清理内存
$server->tick(60000, function () {
if (memory_get_usage() > 100 * 1024 * 1024) {
gc_collect_cycles();
}
});
进程管理
php
<?php
$server->set([
'worker_num' => 4, // 工作进程数
'max_request' => 10000, // 最大请求数
'max_conn' => 10000, // 最大连接数
]);
监控和日志
服务监控
php
<?php
use Swoole\Timer;
// 定时监控服务状态
Timer::tick(1000, function () use ($server) {
$stats = $server->stats();
echo "当前连接数: {$stats['connection_num']}\n";
echo "接受连接数: {$stats['accept_count']}\n";
echo "关闭连接数: {$stats['close_count']}\n";
echo "工作进程数: {$stats['worker_num']}\n";
});
日志记录
php
<?php
function log($message, $level = 'info')
{
$date = date('Y-m-d H:i:s');
$pid = posix_getpid();
file_put_contents(
'swoole.log',
"[{$date}] [{$level}] [{$pid}] {$message}\n",
FILE_APPEND
);
}
最佳实践
进程管理
- 合理设置进程数
- 及时回收资源
- 避免内存泄漏
连接池管理
- 合理设置池大小
- 定时检查连接
- 自动重连机制
错误处理
- 全局异常处理
- 日志记录
- 监控告警
性能优化
- 使用协程
- 合理使用连接池
- 异步任务处理
常见问题
内存泄漏
- 定期清理内存
- 避免循环引用
- 及时释放资源
连接管理
- 超时处理
- 心跳检测
- 自动重连
并发控制
- 使用信号量
- 原子操作
- 锁机制
参考资料
- Swoole官方文档
- PHP手册
- 高性能服务器编程
- 协程编程指南
- 网络编程实践