最近Swoole发布了4.0.2版本,内置协程更加完善,利用Swoole\Coroutine\Channel和Swoole\Coroutine\MySQL可以轻松实现一个MySQL连接池。
实现代码
直接看代码,脚本mysql_connection_pool.php
:
1 |
|
运行效果
运行脚本:
1 | $ php mysql_connection_pool.php |
ab测试:
1 | $ ab -c 8 -n 8 http://127.0.0.1:9501/ |
间隔10秒后,再次测试:
1 | $ ab -c 8 -n 8 http://127.0.0.1:9501/ |
输出结果:
1 | 1532083141 do build one |
代码解释
首先代码里定义了两个类,分别是:
- MySqlCoroutine
- MySqlManager
MySqlCoroutine
MySqlCoroutine继承自Swoole\Coroutine\MySQL
,主要是为了增加一个属性used_at
和两个与之配套的get/set
方法:getUsedAt
和setUsedAt
。used_at
是个时间戳,记录MySqlCoroutine的被调用的时间点。而isConnected
方法是判断与服务器的连接是否有效。
MySqlManager
每个MySqlCoroutine实例与MySQL服务器维系一个连接,而MySqlManager来管理这些MySqlCoroutine,即管理整个连接池。
构建MySqlManager时,用到三个参数:
config
:用于构建MySqlCoroutine;max_number
:最大连接数;min_number
:最小连接数。
其实这里说的连接池,就是MySqlManager的mysql_channel
属性,实际的数据类型是Swoole\Coroutine\Channel
。而池内连接的数量,会用number
属性记录下来。
内部方法:build/rebuild/destroy
- build方法:如果当前连接的数量未达到最大值,则新建一个MySqlCoroutine实例作返回值,并且
number
属性加1;否则,返回false。 - rebuild方法:传入一个MySqlCoroutine实例,返回一个新的MySqlCoroutine实例。
- destroy方法:传入一个MySqlCoroutine实例,如果
number
大于0,那么number
减1。
公有方法:pop/push/autoRecycling
- pop方法:先执行build方法,若是返回MySqlCoroutine实例,则直接返回这个MySqlCoroutine实例;否则,从
mysql_channel
里pop
(如果mysql_channel
已经空了,当前协程会被挂起,等待其他协程往mysql_channel
放入MySqlCoroutine实例),若是取出的MySqlCoroutine实例的连接已无效(连接可能已经被MySQL服务器自动断开),那就返回rebuild方法的值,否则直接返回这个MySqlCoroutine实例。 - push方法:如果
mysql_channel
未满,就往mysql_channel
放入一个MySqlCoroutine;否则,什么也不做。 - autoRecycling方法:接收两个参数,
$timeou
和$sleep
;每隔$sleep
秒,就检查一次,当前连接的数量超过了最小值,那么就从mysql_channel
里pop
一个MySqlCoroutine实例,若是MySqlCoroutine实例上一次使用时间与现在时间间隔超过了$timeou
秒,说明这个MySqlCoroutine实例没有被频繁使用,可以回收;所谓回收,就是从mysql_channel
取出后,不再放回,并且number
减1。
调用
在Swoole\Http\Server
的workerStart
回调函数里,让MySqlManager实例开始自动回收MySqlCoroutine实例;而在Swoole\Http\Server
的request
回调函数里,需要MySqlCoroutine实例时,调用MySqlManager实例的pop方法从连接池里获取,用完再调用MySqlManager实例的push方法放回连接池。
最后
就这样,利用Swoole扩展,几十行PHP代码就能实现一个连接间可以并行使用,池内有最大/最小数量限制,有自动回收空闲连接机制的MySQL连接池。