1. ホーム
  2. マイスル

Swooleデータベース接続プールの解析と実装

2022-02-27 05:24:41
<パス

PHPのswooleを使用して、そのメモリ常駐と並列機能のために、一般的にリンク作成の費用を削減するためにデータベースリンクプーリングを使用する必要があります、ここで接続プールの実装の難しさは、次の分析である。

1: 新しいリンクを取得する時期かどうかは、どのように判断するのですか?
A: デフォルトのルールでは、連結はデータベース接続に対応し、同じリンクを同じ連結で返すこと、つまり連結IDをリンク保存時のキーにすることが望ましいとされています。

2:接続が使用されているかどうかを確認するにはどうしたらよいですか?
接続を取得するとき、使用中の接続を他のプロセスに投げることはできません。さもなければ、データが混乱する危険があります。データベース接続オブジェクトを取得するとき、接続は使用中としてマークされるべきで、プロセスの終了時にアイドルとしてマークされるべきです(コールバック関数を登録する Coroutine::defer )。

3:リサイクルのタイミングは?
データベース接続を使い切ったとき、多すぎるアイドル接続は自動的に再生されるべきで、接続プール接続再生は、最小リンク数を超えるアイドル接続を検出して再生する時限タスクが必要であること

4:コネクションプールの最大リンク数を超えたデータベース接続を取得した場合、どのように対処すればよいですか?
通常、これはリンクが再取得されるか、タイムアウトがfalseを返すまでブロッキング状態(swooleチャネル実装)であるべきである

以下はswooleで実装した疑似コードで、完全なコードではありません。

/**
Pseudo-code for database connection pool implementation of * swoole
*/
class DbPool {

    private $maxNum;
    private $minNum;
    private $unUseChannel=null; //Save idle available database links Channel, implemented by swoole Channel, can block and wait
    private $useChannel=null; //Save the database links that are already in use
    private static $install=null;

    private function __construct($config)
    {
        $this->init($config);
    }

    //initialize
     private function init($config){

         //todo process configuration,generate
         $this->maxNum=$config['maxNum'];
         $this->minNum=$config['minNum'];
         $this->unUseChannel = new Channel($this->maxNum + 8);
         $this->useChannel = [];
         $this->initConent($this->minNum);
         //Enable timed task checking
         $this->checkItems();

     }

    //initialize the database link
    private function initConent($min){
        if (!empty($this->unUseChannel)){
            for ($i=0;$i<$min;$i++){
                $connect=new Connect();
                $this->unUseChannel->push($connect);
         }
        }
    }


     //initialize registration
     public static function register($config){
         if (!empty(self::$install)){
             //registered
             return false;
         }
       return self::$install=new static($config);
     }

     //return connection pool instance
     public static function getInstant(){
         if (empty(self::$install)){
             //not registered
           return false;

         }
         return self::$install;
    }

    //Timed task to check available links swoole timer to implement timed task
    private function checkItems(){
        //check every 5s
        Timer::tick(5*1000,function (){
            //exceeds the number of
            $dels=$this->unUseChannel->length()-$this->minNum;
            if ($dels>0){
                for ($i=0;$i<$dels;$i++){
                    $connect=$this->unUseChannel->pop(0.01);
                    //close the connection
                    $connect->close();
                }
            }

        });
    }

    // return an available link
    public function getConnect(){
        //Get the current concatenation id
        $cid=Coroutine::getCid();
        // determine whether the current process already has a link, and the link is available
        if (!empty($this->useChannel[$cid])&&$this->useChannel[$cid]->status==1){
       		 return $this->useChannel[$cid];
        }

        // determine if a new link is to be created
        if (count($this->useChannel)<$this->maxNum&&$this->unUseChannel->length()==0){
             $connect=new Connect();
            $this->useChannel[$cid]=$connect;
            return $connect;
        }


        //Get one from the idle queue
        //Channel->pop(float $timeout = 0) : mixed;
        //return value can be any type of PHP variable, including anonymous functions and resources
        //Channel and close when the execution fails to return false
        //$timeout specifies the timeout, floating point, in seconds, minimum granularity is milliseconds, no producer push data within the specified time, will return false
        $connect=$this->unUseChannel->pop(0.5);

        //register the concurrent close callback
        if (!empty($connect)){
            $this->useChannel[$cid]=$connect;
            $this->defer($cid);
            return $connect;
        }else{
            throw new Exception("get connect time out");
        }

    }


    //recycle the link, called when the concurrent thread is closed
    private function recycleConnect($cid){
        $connect=$this->useChannel[$cid];
        if (!empty($connect)&&$connect->status==1){
            unset($this->useChannel[$cid]);
            $this->use-Channel->push($connect);
            return true;
        }

        return false;
    }

    //register the callback function for closing the concurrent process, swoole Coroutine implementation
    public function defer($cid){
        Coroutine::defer(function () use ($cid) {
            $this->recycleConnect($cid);
        });
    }


}