如何在 Swoole 中优雅的实现 MySQL 连接池

一、为什么需要连接池 ?

数据库连接池指的是程序和数据库之间保持一定数量的连接不断开,

并且各个请求的连接可以相互复用,

减少重复连接数据库带来的资源消耗,

一定程度上提高了程序的并发性能。

二、连接池实现要点

协程:使用 MySQL 协程客户端。

使用 MySQL 协程客户端,是为了能在一个 Worker 阻塞的时候,

让出 CPU 时间片去处理其他的请求,提高整个 Worker 的并发能力。

连接池存储介质:使用 \swoole\coroutine\channel 通道。

使用 channel 能够设置等待时间,等待其他的请求释放连接。

并且在等待期间,同样也可以让出 CPU 时间片去处理其他的请求。

假设选择 array 或 splqueue,无法等待其他的请求释放连接。

那么在高并发下的场景下,可能会出现连接池为空的现象。

如果连接池为空了,那么 pop 就直接返回 null 了,导致连接不可用。

注:因此不建议选择 array 或 splqueue。

三、连接池的具体实现

use Swoole\Coroutine\Channel;

use Swoole\Coroutine\MySQL;

class MysqlPool

{

private $min; // 最小连接数

private $max; // 最大连接数

private $count; // 当前连接数

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;

}

/**

* 创建连接

* @return MySQL

*/

protected function createConnection()

{

$conn = new MySQL();

$conn->connect([

'host' => 'mysql',

'port' => '3306',

'user' => 'root',

'password' => 'root',

'database' => 'fastadmin',

'timeout' => 5

]);

return $conn;

}

/**

* 创建连接对象

* @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 分钟检测一下空闲连接

swoole_timer_tick(2 * 60 * 1000, function () {

if ($this->connections->length() < intval($this->max * 0.5)) {

// 请求连接数还比较多,暂时不回收空闲连接

return;

}

while (true) {

if ($this->connections->isEmpty()) {

break;

}

$connObj = $this->connections->pop(0.001);

$nowTime = time();

$lastUsedTime = $connObj['last_used_time'];

// 当前连接数大于最小的连接数,并且回收掉空闲的连接

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();

四、总结

定时维护空闲连接到最小值。

使用用完数据库连接之后,需要手动回收连接到连接池。

使用 channel 作为连接池的存储介质。

easyswoole数据库连接池_如何在 Swoole 中优雅的实现 MySQL 连接池相关推荐

  1. mysql多个字符串连接池_使用Coroutine\Channel实现一个简单的MySQL连接池

    Channel通道,类似于go语言的chan,支持多生产者协程和多消费者协程,Swoole底层自动实现了协程的切换和调度 Channel实现原理 通道与PHP的Array类似,仅占用内存,没有其他额外 ...

  2. java mongodb 关闭连接_如何在mongodb上使用java驱动程序保持连接池关闭?

    我正在从 java驱动程序2.12.3升级到3.3.0.奇怪的是,收集池似乎突然"起作用". 我的设置如下: Connection在主线程中建立: mongoClient = ne ...

  3. kylin版本_如何在 Kylin 中优雅地使用 Spark

    前言 Kylin 用户在使用 Spark的过程中,经常会遇到任务提交缓慢.构建节点不稳定的问题.为了更方便地向 Spark 提交.管理和监控任务,有些用户会使用 Livy 作为 Spark 的交互接口 ...

  4. 怎么在linux上修改mysql端口映射_如何在Linux中更改默认的MySQL / MariaDB端口

    在本指南中,我们将学习如何更改MySQL / MariaDB数据库在CentOS 7和基于Debian的Linux发行版中绑定的默认端口. MySQL数据库服务器在Linux和Unix下运行的默认端口 ...

  5. macos远程桌面连接_如何在macOS中使用Microsoft远程桌面连接Amazon EC2

    macos远程桌面连接 I created this guide because of an experience I had while teaching. My students needed t ...

  6. 日志的log中如何输出变量_如何在kubernetes中优雅的输出日志

    背景 我们经常需要在kubernetes中运行一些任务性质的Job或者Pod.在调试过程中,我们对日志有如下两个需求 需求一:日志输出到stdout.因为stdout的输出,可以非常方便的通过kube ...

  7. swoole mysql 连接数_用swoole简单实现MySQL连接池

    MySQL连接池 在传统的网站开发中,比如LNMP模式,由Nginx的master进程接收请求然后分给多个worker进程,每个worker进程再链接php-fpm的master进程,php-fpm再 ...

  8. Django使用mysql连接池_Django db使用MySQL连接池

    Django db使用MySQL连接池 Sep 25 2016 Django db模块本身不支持MySQL连接池,只有一个配置CONN_MAX_AGE连接最大存活时间,如果WSGI服务器使用了线程池技 ...

  9. figma设计_如何在Figma中构建设计入门套件(第1部分)

    figma设计 Figma教程 (Figma Tutorial) Do you like staring at a blank canvas every time you start a new pr ...

最新文章

  1. 销售订单屏幕增强及功能增强
  2. Linux cached过高问题
  3. 有些事情现在不做一辈子就都不会做了
  4. GhostNet网络
  5. UOS U盘已经复制成功,有时卡死
  6. xise菜刀千万不要随便下载!(警惕!)
  7. TSINSEE青犀视频/海康合作的RTMP推流安防摄像头的移动侦测功能介绍
  8. wifi android kernel,android wifi 驱动框架简介
  9. 蚂蚁金服AntV开源地理可视化引擎 L7 2.0——聊聊AntV背后那些事
  10. 非宁静无以致远,借以静化心灵
  11. kneighbors()返回值indices、distances详解
  12. java 办公_Java003-协同办公OA
  13. jmeter与lr区别
  14. 6级20190601
  15. 关于在《python编程从入门到实践》书中练习“外星人大战”报错“AttributeError: ‘AlienInvasion‘ object has no attribute ‘blit‘”
  16. linux终端cd未找到命令,Linux cd 命令 command not found cd 命令详解 cd 命令未找到 cd 命令安装 - CommandNotFound ⚡️ 坑否...
  17. 用事实说话,用行动回报大家的支持!
  18. STM32 LL库 I2C的个人笔记
  19. Things3 Mac版(mac任务管理软件)中文版
  20. python实现大乐透号码生成器

热门文章

  1. 浅谈工业无线遥控器的基本定义及原理
  2. oracle 测试试题,oracle试题
  3. linux 安装mongodb 64,在CentOS 6.x 64bit上安装MongoDB 3.2社区版
  4. oracle 调整dbw0,求助:DBW的内存占用率高,可能是什么原因?
  5. Boole‘s,Doob‘s inequality,中心极限定理Central Limit Theorem,Kolmogorov extension theorem, Lebesgue‘s domin
  6. linux内核函数open源码,open()在Linux内核的实现(1)-基本实现
  7. 传智杯Java志愿者传智专修学院总共召集了n位志愿者来负责打扫活动,现在需要你负责帮忙统计每位志愿者的工作情况,用来制作光荣榜,给他们发小花花
  8. FPGA(8)--频率计检测控制系统
  9. 【chromium】 Chromium OS的oom机制
  10. Python非递归实现二叉树的后续遍历