实现一个协程版mysql连接池

实现一个协程版的mysql连接池,该连接池支持自动创建最小连接数,自动检测mysql健康;基于swoole的chanel。
最近事情忙,心态也有点不积极。技术倒是没有落下,只是越来越不想写博客了。想到平时自己上网上找资料的痛苦,于是将自己这篇连接池的文章放出来,给需要的程序员一点帮助。

<?php

/**
 * 实现一个协程版的mysql 连接池
 * Created by PhpStorm.
 * User: roverliang
 * Date: 2018/12/10
 * Time: 23:27
 */

namespace console\libs;

use Swoole\Coroutine\MySQL as coMysql;
use Swoole\Coroutine\Channel;

class CoMysqlPool extends coMysql
{
    protected $maxNums;   //最大连接数
    protected $minNums;   //最小连接数
    protected $mysqlConfig = array(
        'host'     => '127.0.0.1',
        'port'     => 3306,
        'user'     => 'root',
        'password' => '',
        'database' => 'hifuli',
        'timeout'  => -1,
    );  //mysql配置
    protected $chan;      //channel
    protected $currentConnectedNums;  //当前连接数
    protected $tag;       //标识

    /**
     * 初始化连接池
     * CoMysqlPool constructor.
     * @param int $maxNums 最大连接数
     * @param int $minNums 最小连接数
     * @param array $mysqlConfig mysql配置
     */
    public function __construct($maxNums = 20, $minNums = 5, $mysqlConfig = [])
    {
        $this->maxNums = $maxNums;
        $this->minNums = $minNums;
        if (!empty($mysqlConfig) && is_array($mysqlConfig)) {
            $this->mysqlConfig = $mysqlConfig;
        }
        $this->chan = new Channel($maxNums);
        $this->tag  = true;
    }


    /**
     * 从连接池中获取一个mysql连接对象
     * Created by 梁子(roverliang) <mr.roverliang@gmail.com>
     * 2018/12/10
     */
    public function pop()
    {
        if (!$this->tag) return false;

        if ($mysql = $this->getMysqlInstance()) {
            echo "创建了一个mysql".PHP_EOL;
            return $mysql;
        }

        $mysql = $this->chan->pop();
        if (!$this->checkMysqlHealth($mysql)) {
            $mysql = $this->getMysqlInstance();
        } else {
            echo "复用mysql".PHP_EOL;
        }
        return $mysql;
    }


    /**
     * 将mysql对象放回连接池
     * Created by 梁子(roverliang) <mr.roverliang@gmail.com>
     * 2018/12/10
     * @param $obj
     */
    public function push($mysql)
    {
        if (!$this->tag) return false;
        if (!$this->chan->isFull()) {
            echo "将mysql放入连接池".PHP_EOL;
            $this->chan->push($mysql);
        }
        return true;
    }


    /**
     * 获取mysql实例
     * Created by 梁子(roverliang) <mr.roverliang@gmail.com>
     * 2018/12/10
     * @return bool
     */
    protected function getMysqlInstance()
    {
        if (!$this->chan->isFull()) {
            $mysqlInstance = new \Swoole\Coroutine\MySQL();
            $mysqlInstance->connect($this->mysqlConfig);
            return $mysqlInstance;
        }
        return false;
    }


    /**
     * 检测mysql连接是否健康
     * Created by 梁子(roverliang) <mr.roverliang@gmail.com>
     * 2018/12/10
     */
    protected function checkMysqlHealth($mysql)
    {
        if (!$mysql->connected) return false;
        return true;
    }


    /**
     * 销毁连接池
     * Created by 梁子(roverliang) <mr.roverliang@gmail.com>
     * 2018/12/11
     */
    public function destroyPool()
    {
        $this->tag = false;
        while ($this->chan->length()) {
            $mysql = $this->chan->pop();
            $mysql->close();
            echo "销毁mysql".PHP_EOL;
        }
        return true;
    }


    /**
     * 监控进程池
     * Created by Roverliang.
     * Date: 2018/12/12 Time: 17:12
     */
    public function monitorPool()
    {
        declare(ticks=10);
        $self = $this;
        register_tick_function(function () use ($self) {
            if (($self->chan->length() < $self->minNums) && $self->tag) {
                $mysql = $self->pop();
                if ($self->checkMysqlHealth($mysql)) {
                    echo "mysql进程监控池自动创建mysql".PHP_EOL;
                    $self->push($mysql);
                }
            }
        });
    }

}



go(function(){
    $mysqlPool = new CoMysqlPool(10, 2);
    $mysqlPool->monitorPool();

    for($i=0; $i<20;$i++) {
        $mysqlPool->monitorPool();
        $mysql = $mysqlPool->pop();
        $mysqlPool->push($mysql);
        \Swoole\Coroutine::sleep(1);
    }

    $mysqlPool->destroyPool();
});
posted @ 2018-12-12 18:35  roverliang  阅读(1187)  评论(0编辑  收藏  举报