Swoole协程模式实现Mysql连接池

连接池定义

永不断开,要求我们的这个程序是一个常驻内存的程序。数据库连接池(Connection pooling)是程序启 动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。

为什么需要连接池?

当并发量很低的时候,连接可以临时建立,但当服务吞吐达到几百、几千的时候,频繁 建立连接 Connect销毁连接 Close 就有可能会成为服务的一个瓶颈,那么当服务启动的时候,先建立好若干个连接并存放于一个队列中,当需要使用时从队列中取出一个并使用,使用完后再反还到队列去,而对这个队列数据结构进行维护的,就是连接池。

使用channel实现连接池

必须在协程模式下

Pool.php

<?php


class PdoPool
{
    /**
     * @var Swoole\Coroutine\Channel
     */
    protected $channel;

    /**
     * @var int 最大连接数
     */
    protected $maxActive = 30;

    /**
     * @var int 最少连接数
     */
    protected $minActive = 10;

    /**
     * @var int 最大等待连接数
     */
    protected $maxWait = 200;

    /**
     * @var float 最大等待时间 -1 永不超时
     */
    protected $maxWaitTime = 1.2;

    /**
     * @var int 最大空闲时间s
     */
    protected $maxIdleTime = 5;

    /**
     * @var int 自动检查时间ms
     */
    protected $checkTime = 3000;

    /**
     * @var int 当前连接数
     */
    protected $count = 0;

    /**
     * @var self
     */
    protected static $instance = null;


    /**
     * PdoPool constructor.
     */
    private function __construct()
    {
        // 初始化连接池
        $this->init();
        // 定时器进行空闲连接释放
        $this->recovery();
    }

    /**
     * @return PdoPool|null
     */
    public static function getInstance()
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 连接池初始化
     */
    protected function init()
    {
        for ($i = 0; $i < $this->minActive; $i++) {
            $connection = $this->getConnection();
            if ($connection) $this->channel->push($connection);
        }
    }

    public function getConnection(){
        return $this->getConnectionByChannel();
    }

    private function getConnectionByChannel()
    {
        // 创建Channel
        if ($this->channel === null) {
            $this->channel = new Swoole\Coroutine\Channel($this->maxActive);
        }

        // 小于连接池内最小连接数
        if ($this->count < $this->minActive) {
            return $this->createConnection();
        }

        // 取出连接
        $connection = null;
        if (!$this->channel->isEmpty()) {
            $connection = $this->popConnection();
        }

        //检测连接是否正常
        if ($connection !== null && $connection['connection'] instanceof PDO) {
            return $connection;
        }

        //未取出连接 判断是否大于最大连接数进行创建
        if ($this->count < $this->maxActive) {
            return $this->createConnection();
        }


        //查看协程挂起数
        $stats = $this->channel->stats();
        if ($this->maxWait > 0 && $stats['consumer_num'] >= $this->maxWait) {
            echo '协程挂起数已大于最大等待数' . PHP_EOL;
        }

        //重新取出连接
        $connection = $this->channel->pop($this->maxWaitTime);
        if ($connection == false) {
            echo '获取连接失败' . PHP_EOL;
        }
        return $connection;
    }

    private function createConnection()
    {
        // 因为堵塞问题 会造成当前连接数大于最大连接数 先进行++
        $this->count++;
        try {
            $connection = new PDO('mysql:host=localhost;dbname=test', 'root', 'gaobinzhan');
            $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return [
                'connection' => $connection,
                'lastUsedTime' => time()
            ];
        } catch (\Throwable $throwable) {
            //失败--
            $this->count--;
        }
    }


    private function popConnection()
    {
        while (!$this->channel->isEmpty()) {
            $connection = $this->channel->pop();
            return $connection;
        }
        return null;
    }

    public function freeConnection($connection)
    {
        //放入连接池
        $stats = $this->channel->stats();
        if ($stats['queue_num'] < $this->maxActive) {
            $connection['lastUsedTime'] = time();
            $this->channel->push($connection);
        }
    }

    /**
     * 自动回收空闲连接
     */
    private function recovery()
    {
        swoole_timer_tick($this->checkTime, function () {
            while ($this->count > $this->minActive && !$this->channel->isEmpty()) {
                $connection = $this->channel->pop($this->maxWaitTime);
                if (!$connection) {
                    continue;
                }
                if ((time() - $connection['lastUsedTime']) > $this->maxIdleTime) {
                    $this->count--;
                    $connection['connection'] = null;
                    echo "回收成功" . PHP_EOL;
                } else {
                    $this->channel->push($connection);
                }
            }
        });
    }

    private function __clone()
    {

    }

}

这里生成的是Pdo连接池同理可自行修改createConnection方法生成其它连接池

可用AST语法树进行多种连接池配置

大佬勿喷 嘿嘿!


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容