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

一、为什么需要连接池 ?

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

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

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

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

二、连接池实现要点

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

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

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

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

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

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

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

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

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

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

三、连接池的具体实现

<?php

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 作为连接池的存储介质。

如何在 Swoole 中优雅的实现 MySQL 连接池的更多相关文章

  1. 用swoole简单实现MySQL连接池

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

  2. 转 Swoole】用swoole简单实现MySQL连接池

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

  3. Django db使用MySQL连接池

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

  4. 如何在MyBatis中优雅的使用枚举

    问题 在编码过程中,经常会遇到用某个数值来表示某种状态.类型或者阶段的情况,比如有这样一个枚举:   public enum ComputerState { OPEN(10), //开启 CLOSE( ...

  5. Swoole MySQL 连接池的实现

    目录 概述 代码 扩展 小结 概述 这是关于 Swoole 入门学习的第八篇文章:Swoole MySQL 连接池的实现. 第七篇:Swoole RPC 的实现 第六篇:Swoole 整合成一个小框架 ...

  6. tomcat中使用mysql连接池的配置

    1.下载相应的jar包,添加到工程中 需要下载的包主要有commons-pool2-2.2 commons-dbcp2-2.0.1-src commons-dbcp2-2.0.1  commons-c ...

  7. python中实现mysql连接池

    python中实现mysql连接池 import pymysql from DBUtils.PooledDB import PooledDB MYSQL_HOST = 'localhost' USER ...

  8. 实现一个协程版mysql连接池

    实现一个协程版的mysql连接池,该连接池支持自动创建最小连接数,自动检测mysql健康:基于swoole的chanel. 最近事情忙,心态也有点不积极.技术倒是没有落下,只是越来越不想写博客了.想到 ...

  9. Swoole4-swoole创建Mysql连接池

    一 .什么是mysql连接池 场景:每秒同时有1000个并发,但是这个mysql同时只能处理400个连接,mysql会宕机. 解决方案:连接池,这个连接池建立了200个和mysql的连接,这1000个 ...

随机推荐

  1. 3597: [Scoi2014]方伯伯运椰子[分数规划]

    3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 404  Solved: 249 [Submit][Sta ...

  2. android菜鸟学习笔记12----Android控件(一) 几个常用的简单控件

    主要参考<第一行代码> 1.TextView: 功能与传统的桌面应用开发中的Label控件相似,用于显示文本信息 如: <TextView android:layout_width= ...

  3. 20179209《Linux内核原理与分析》第一周作业

    如何揭开Linux操作系统的最大面纱 个人认为,真正理解一个操作系统最根本的就是理解其文件系统结构. 自windows图形界面诞生,国内大多数用户都选择了windows操作系统,很多人觉得window ...

  4. Webpack探索【10】--- 懒加载详解

    本文主要讲懒加载方面相关内容.

  5. keras: 在构建LSTM模型时,使用变长序列的方法

    众所周知,LSTM的一大优势就是其能够处理变长序列.而在使用keras搭建模型时,如果直接使用LSTM层作为网络输入的第一层,需要指定输入的大小.如果需要使用变长序列,那么,只需要在LSTM层前加一个 ...

  6. 剑指Offer:对称的二叉树【28】

    剑指Offer:对称的二叉树[28] 题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. 题目分析 Java题解 /* publi ...

  7. Spark与缓存

    预期成果 1.1   当前问题 当前以图搜图应用存在的问题: 当前使用spark RDD方案无法达到数据实时加载(每10分钟加载一次,虽然可配,但太短可能会有问题) Spark RDD内存会被分为两部 ...

  8. Android RelativeLayout相对布局

    RelativeLayout是相对布局控件:以控件之间相对位置或相对父容器位置进行排列. 相对布局常用属性: 子类控件相对子类控件:值是另外一个控件的id android:layout_above-- ...

  9. 《CSS权威指南(第三版)》---第七章 基本视觉格式化

    主要知识记录: 1.给一个元素指定内容区宽度,如果设置了内边距,边框和外边距,这些因素都会影响CSS的width属性. 2.在水平格式化的7个属性中,width,margin-left,margin- ...

  10. SpringBoot之外部Tomcat运行Spring Boot项目

    内置tomcat8.5.28 外置的要高于此版本才OK spring boot1.5是访问不了jsp页面的 以后要以2.0版本为主流的