easyswoole数据库连接池_如何在 Swoole 中优雅的实现 MySQL 连接池
如何在 Swoole 中優(yōu)雅的實(shí)現(xiàn) MySQL 連接池
一、為什么需要連接池 ?
數(shù)據(jù)庫(kù)連接池指的是程序和數(shù)據(jù)庫(kù)之間保持一定數(shù)量的連接不斷開,
并且各個(gè)請(qǐng)求的連接可以相互復(fù)用,
減少重復(fù)連接數(shù)據(jù)庫(kù)帶來(lái)的資源消耗,
一定程度上提高了程序的并發(fā)性能。
二、連接池實(shí)現(xiàn)要點(diǎn)
協(xié)程:使用 MySQL 協(xié)程客戶端。
使用 MySQL 協(xié)程客戶端,是為了能在一個(gè) Worker 阻塞的時(shí)候,
讓出 CPU 時(shí)間片去處理其他的請(qǐng)求,提高整個(gè) Worker 的并發(fā)能力。
連接池存儲(chǔ)介質(zhì):使用 \swoole\coroutine\channel 通道。
使用 channel 能夠設(shè)置等待時(shí)間,等待其他的請(qǐng)求釋放連接。
并且在等待期間,同樣也可以讓出 CPU 時(shí)間片去處理其他的請(qǐng)求。
假設(shè)選擇 array 或 splqueue,無(wú)法等待其他的請(qǐng)求釋放連接。
那么在高并發(fā)下的場(chǎng)景下,可能會(huì)出現(xiàn)連接池為空的現(xiàn)象。
如果連接池為空了,那么 pop 就直接返回 null 了,導(dǎo)致連接不可用。
注:因此不建議選擇 array 或 splqueue。
三、連接池的具體實(shí)現(xiàn)
use Swoole\Coroutine\Channel;
use Swoole\Coroutine\MySQL;
class MysqlPool
{
private $min; // 最小連接數(shù)
private $max; // 最大連接數(shù)
private $count; // 當(dāng)前連接數(shù)
private $connections; // 連接池
protected $freeTime; // 用于空閑連接回收判斷
public static $instance;
/**
* MysqlPool constructor.
*/
public function __construct()
{
$this->min = 10;
$this->max = 100;
$this->freeTime = 10 * 3600;
$this->connections = new Channel($this->max + 1);
}
/**
* @return MysqlPool
*/
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 創(chuàng)建連接
* @return MySQL
*/
protected function createConnection()
{
$conn = new MySQL();
$conn->connect([
'host' => 'mysql',
'port' => '3306',
'user' => 'root',
'password' => 'root',
'database' => 'fastadmin',
'timeout' => 5
]);
return $conn;
}
/**
* 創(chuàng)建連接對(duì)象
* @return array|null
*/
protected function createConnObject()
{
$conn = $this->createConnection();
return $conn ? ['last_used_time' => time(), 'conn' => $conn] : null;
}
/**
* 初始化連接
* @return $this
*/
public function init()
{
for ($i = 0; $i < $this->min; $i++) {
$obj = $this->createConnObject();
$this->count++;
$this->connections->push($obj);
}
return $this;
}
/**
* 獲取連接
* @param int $timeout
* @return mixed
*/
public function getConn($timeout = 3)
{
if ($this->connections->isEmpty()) {
if ($this->count < $this->max) {
$this->count++;
$obj = $this->createConnObject();
} else {
$obj = $this->connections->pop($timeout);
}
} else {
$obj = $this->connections->pop($timeout);
}
return $obj['conn']->connected ? $obj['conn'] : $this->getConn();
}
/**
* 回收連接
* @param $conn
*/
public function recycle($conn)
{
if ($conn->connected) {
$this->connections->push(['last_used_time' => time(), 'conn' => $conn]);
}
}
/**
* 回收空閑連接
*/
public function recycleFreeConnection()
{
// 每 2 分鐘檢測(cè)一下空閑連接
swoole_timer_tick(2 * 60 * 1000, function () {
if ($this->connections->length() < intval($this->max * 0.5)) {
// 請(qǐng)求連接數(shù)還比較多,暫時(shí)不回收空閑連接
return;
}
while (true) {
if ($this->connections->isEmpty()) {
break;
}
$connObj = $this->connections->pop(0.001);
$nowTime = time();
$lastUsedTime = $connObj['last_used_time'];
// 當(dāng)前連接數(shù)大于最小的連接數(shù),并且回收掉空閑的連接
if ($this->count > $this->min && ($nowTime - $lastUsedTime > $this->freeTime)) {
$connObj['conn']->close();
$this->count--;
} else {
$this->connections->push($connObj);
}
}
});
}
}
$httpServer = new swoole_http_server('127.0.0.1',9501);
$httpServer->set(['work_num' => 1]);
$httpServer->on('WorkerStart', function ($request, $response) {
MysqlPool::getInstance()->init()->recycleFreeConnection();
});
$httpServer->on('Request', function ($request, $response){
$conn = MysqlPool::getInstance()->getConn();
$conn->query('SELECT * FROM fa_admin WHERE id=1');
MysqlPool::getInstance()->recycle($conn);
});
$httpServer->start();
四、總結(jié)
定時(shí)維護(hù)空閑連接到最小值。
使用用完數(shù)據(jù)庫(kù)連接之后,需要手動(dòng)回收連接到連接池。
使用 channel 作為連接池的存儲(chǔ)介質(zhì)。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的easyswoole数据库连接池_如何在 Swoole 中优雅的实现 MySQL 连接池的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: roads 构筑极致用户体验_坚持用户思
- 下一篇: python中的大数据品牌运营专业公司_