连接池
easyswoole/pool 是基于 Swoole 协程 Channel 实现的通用对象池。它不只可以管理数据库连接,也可以管理 Redis 客户端、HTTP 客户端以及其他创建成本较高、能够重复使用的对象。
连接池主要负责:
- 限制每个进程最多创建多少个对象。
- 在多个协程之间借出和归还对象。
- 借出前检查对象是否仍然可用。
- 定期检查空闲对象并补足最小数量。
- 在负载较低时回收一部分空闲对象。
- 在对象损坏时关闭对象并释放池容量。
安装
在项目根目录执行:
composer require easyswoole/pool:^3.0
Pool 3.x 要求 PHP 8.1 及以上,并依赖 Swoole 的协程、Channel 和 Timer 能力。安装后可以确认实际版本:
composer show easyswoole/pool
运行模型
EasySwoole 的 Worker 是独立进程,PHP 对象不会在 Worker 之间共享。因此每个 Worker 都有自己的连接池:
HTTP 请求
↓
Worker 进程
↓
Manager 中的连接池
├── 空闲连接 A
├── 空闲连接 B
└── 已借出连接 C → 当前请求协程
如果服务有 4 个 Worker,每个池的 maxObjectNum 为 20,那么下游服务最多可能收到 4 × 20 = 80 个连接。设置池大小时必须按所有 Worker、TaskWorker 和自定义进程的总量计算。
连接池实例应在实际使用它的进程中创建。不要在服务 fork Worker 前建立数据库或 Redis 长连接,否则多个进程可能继承同一个文件描述符,造成协议数据错乱。
最小可运行示例
先新建 App/Pool/DemoConnection.php,定义一个可以被池管理的对象:
<?php
namespace App\Pool;
use EasySwoole\Pool\ObjectInterface;
final class DemoConnection implements ObjectInterface
{
private bool $connected = true;
private array $context = [];
public function execute(string $command): string
{
if (!$this->connected) {
throw new \RuntimeException('connection is closed');
}
return "executed: {$command}";
}
public function beforeUse(): bool
{
return $this->connected;
}
public function intervalCheck(): bool
{
return $this->connected;
}
public function objectRestore(): void
{
$this->context = [];
}
public function gc(): void
{
$this->connected = false;
}
}
再新建 App/Pool/DemoPool.php:
<?php
namespace App\Pool;
use EasySwoole\Pool\AbstractPool;
use EasySwoole\Pool\ObjectInterface;
final class DemoPool extends AbstractPool
{
protected function createObject(): ObjectInterface
{
return new DemoConnection();
}
}
最后在项目根目录新建 pool-demo.php。前两步的 App/Pool/... 文件会通过安装器配置的 App\ 自动加载;这个脚本则需要显式加载 vendor/autoload.php:
<?php
require __DIR__ . '/vendor/autoload.php';
use App\Pool\DemoConnection;
use App\Pool\DemoPool;
use EasySwoole\Pool\Config;
use Swoole\Coroutine;
Coroutine\run(function (): void {
$pool = new DemoPool(new Config([
'minObjectNum' => 0,
'maxObjectNum' => 10,
]));
$result = $pool->invoke(
fn (DemoConnection $connection) => $connection->execute('ping')
);
echo $result, PHP_EOL;
});
运行 php pool-demo.php,预期输出 executed: ping。这个演示对象不连接数据库或 Redis,所以不需要启动外部服务。invoke() 会获取一个对象,把它传给回调,并在回调结束后自动归还。控制器中的一次性操作优先使用这种方式,可以避免遗漏归还。接入框架时不要每次请求都 new DemoPool();先按Manager 与框架接入在全局初始化事件注册,再在控制器中获取。
学习顺序
建议按下面顺序阅读:
- 连接对象与生命周期:理解池为什么需要四个生命周期方法。
- 连接池配置:确定容量、等待时间和检查周期。
- Manager 与框架接入:在框架全局初始化事件中注册连接池。
- 获取、归还与销毁:选择
invoke()、defer()或getObj()。 - 预热、检查与监控:处理冷启动、健康检查和状态观测。