pdo mysql 连接池_Swoole协程模式实现Mysql连接池

连接池定义

永不断开,要求我们的这个程序是一个常驻内存的程序。数据库连接池(Connection pooling)是程序启 动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。

为什么需要连接池?

当并发量很低的时候,连接可以临时建立,但当服务吞吐达到几百、几千的时候,频繁 建立连接 Connect 和 销毁连接 Close 就有可能会成为服务的一个瓶颈,那么当服务启动的时候,先建立好若干个连接并存放于一个队列中,当需要使用时从队列中取出一个并使用,使用完后再反还到队列去,而对这个队列数据结构进行维护的,就是连接池。

使用channel实现连接池

必须在协程模式下

Pool.php

class PdoPool

{

/**

* @var Swoole\Coroutine\Channel

*/

protected $channel;

/**

* @var int 最大连接数

*/

protected $maxActive = 30;

/**

* @var int 最少连接数

*/

protected $minActive = 10;

/**

* @var int 最大等待连接数

*/

protected $maxWait = 200;

/**

* @var float 最大等待时间 -1 永不超时

*/

protected $maxWaitTime = 1.2;

/**

* @var int 最大空闲时间s

*/

protected $maxIdleTime = 5;

/**

* @var int 自动检查时间ms

*/

protected $checkTime = 3000;

/**

* @var int 当前连接数

*/

protected $count = 0;

/**

* @var self

*/

protected static $instance = null;

/**

* PdoPool constructor.

*/

private function __construct()

{

// 初始化连接池

$this->init();

// 定时器进行空闲连接释放

$this->recovery();

}

/**

* @return PdoPool|null

*/

public static function getInstance()

{

if (!self::$instance instanceof self) {

self::$instance = new self();

}

return self::$instance;

}

/**

* 连接池初始化

*/

protected function init()

{

for ($i = 0; $i < $this->minActive; $i++) {

$connection = $this->getConnection();

if ($connection) $this->channel->push($connection);

}

}

public function getConnection(){

return $this->getConnectionByChannel();

}

private function getConnectionByChannel()

{

// 创建Channel

if ($this->channel === null) {

$this->channel = new Swoole\Coroutine\Channel($this->maxActive);

}

// 小于连接池内最小连接数

if ($this->count < $this->minActive) {

return $this->createConnection();

}

// 取出连接

$connection = null;

if (!$this->channel->isEmpty()) {

$connection = $this->popConnection();

}

//检测连接是否正常

if ($connection !== null && $connection['connection'] instanceof PDO) {

return $connection;

}

//未取出连接 判断是否大于最大连接数进行创建

if ($this->count < $this->maxActive) {

return $this->createConnection();

}

//查看协程挂起数

$stats = $this->channel->stats();

if ($this->maxWait > 0 && $stats['consumer_num'] >= $this->maxWait) {

echo '协程挂起数已大于最大等待数' . PHP_EOL;

}

//重新取出连接

$connection = $this->channel->pop($this->maxWaitTime);

if ($connection == false) {

echo '获取连接失败' . PHP_EOL;

}

return $connection;

}

private function createConnection()

{

// 因为堵塞问题 会造成当前连接数大于最大连接数 先进行++

$this->count++;

try {

$connection = new PDO('mysql:host=localhost;dbname=test', 'root', 'gaobinzhan');

$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

return [

'connection' => $connection,

'lastUsedTime' => time()

];

} catch (\Throwable $throwable) {

//失败--

$this->count--;

}

}

private function popConnection()

{

while (!$this->channel->isEmpty()) {

$connection = $this->channel->pop();

return $connection;

}

return null;

}

public function freeConnection($connection)

{

//放入连接池

$stats = $this->channel->stats();

if ($stats['queue_num'] < $this->maxActive) {

$connection['lastUsedTime'] = time();

$this->channel->push($connection);

}

}

/**

* 自动回收空闲连接

*/

private function recovery()

{

swoole_timer_tick($this->checkTime, function () {

while ($this->count > $this->minActive && !$this->channel->isEmpty()) {

$connection = $this->channel->pop($this->maxWaitTime);

if (!$connection) {

continue;

}

if ((time() - $connection['lastUsedTime']) > $this->maxIdleTime) {

$this->count--;

$connection['connection'] = null;

echo "回收成功" . PHP_EOL;

} else {

$this->channel->push($connection);

}

}

});

}

private function __clone()

{

}

}

这里生成的是Pdo连接池同理可自行修改createConnection方法生成其它连接池

可用AST语法树进行多种连接池配置

大佬勿喷 嘿嘿!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值