码云代码仓库:https://gitee.com/tanjiajun/MysqlPool
代码仓库:https://github.com/asbectJ/swoole4.git
前言
在写这篇文章之前,看了好几篇实现连接池的文章,都是写的很不好的。摆明忽略了连接池的很多特性,很多都不具有抗高并发和连接复用。所以自己觉得有必须把最近几天,实现一个比较完整的php数据库连接池的点滴记录下来,望能帮助各位,感激者望多点赞和打赏。
说到做到,150粉丝福利安排PHP进阶资料,免费获取
一、数据库连接池基本概念
所谓的数据库连接池,一般指的就是程序和数据库保持一定数量的数据库连接不断开,并且各请求的连接可以相互复用,减少重复新建数据库连接的消耗和避免在高并发的情况下出现数据库max connections等错误。自己总结了一下,如果要实现一个数据库连接池,一般有几个特点:
连接复用,不同的请求连接,可以放回池中,等待下个请求发分配和调用
连接数量一般维持min-max的最大最少值之间
对于空闲连接的回收
可以抗一定程度的高并发,也就是说当一次并发请求完池中所有的连接时,获取不到连接的请求可等待其他连接的释放
总结几个特性后,一个基本连接池,大致要实现下图功能:
创建连接:连接池启动后,初始化一定的空闲连接,指定为最少的连接min。当连接池为空,不够用时,创建新的连接放到池里,但不能超过指定的最大连接max数量。
连接释放:每次使用完连接,一定要调用释放方法,把连接放回池中,给其他程序或请求使用。
连接分配:连接池中用pop和push的方式对等入队和出队分配与回收。能实现阻塞分配,也就是在池空并且已创建数量大于max,阻塞一定时间等待其他请求的连接释放,超时则返回null。
连接管理:对连接池中的连接,定时检活和释放空闲连接等
二、Fpm+数据库长连接的实现
- 利用fpm实现:例如你要实例一个100连接数的池,开启100个空闲fpm,然后每个fpm的连接都是数据库长连接。一般pm.max_spare_servers = 8这个配置项就是维持连接池的空闲数量,然后pm.max_children = 50就是最大的连接数量。和fpm的进程数量一致。
三、基于swoole的实现
- swoole简单介绍(更多参阅swoole官网)
swoole是一个PHP实现异步网络通信的引擎或者扩展,其中实现了很多传统PHP-fpm没有的东西,例如异步的客户端,异步Io,常驻内存,协程等等,一个个优秀的扩展,其中异步和协程等概念能应用于高并发场景。缺点是文档和入门的门槛都比较高,需要排坑。附上swoole的运行流程和进程结构图:
运行流程图
进程/线程架构图
- 基于swoole现实时的注意事项
首先,为了减少大家对之后运行示例代码产生不必要的天坑,先把注意事项和场景问题放前面:
1、程序中使用了协程的通信管道channel(与go的chan差不多的),其中swoole2是不支持chan->pop($timeout)中timeout超时等待的,所以必须用swoole4版本
2、使用swoole协程扩展的时候,一定不能装xdebug之类的扩展,否则报错。官方说明为:https://wiki.swoole.com/wiki/page/674.html,同时参考如下了解更多关于swoole协程的使用和注意:https://wiki.swoole.com/wiki/page/749.html
3、笔者使用的环境为:PHP 7.1.18和swoole4作为此次开发的环境
- 基于swoole现实连接池的方法
首先,此次利用swoole实现连接池,运用到swoole以下技术或者概念
1、连接变量池,这里可以看做一个数组或者队列,利用swoole全局变量的常驻内存特性,只要变量没主动unset掉,数组或队列中的连接对象可以一直保持,不释放。主要参考:https://wiki.swoole.com/wiki/page/p-zend_mm.html
2、协程。协程是纯用户状态的线程,通过协作的方式而不是抢占的方式来切换。首先此次的连接池两处用到协程:
一个是mysql的协程客户端,为什么要用协程客户端,因为如果是用同步客户端PDO,在一个进程处理内,就算有几百个连接池,swoole worker