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);
});
}
}
関連
-
[解決済み】autoカラムは1つしか存在できない
-
[解決済み] 親の行を削除または更新できない: 外部キー制約に失敗 - MYSQL
-
[解決済み】MySQLで日付を比較する
-
[解決済み] テーブル 'performance_schema.session_variables' は存在しません。
-
[解決済み] エラー:テーブル '<table-name>' に対するユーザー '<userid>'@'<ip-address>' への select コマンドが拒否されました。
-
[解決済み] エラー 1049 (42000)。不明なデータベース
-
[解決済み] Node.jsでSequelizeを使用して結合クエリを作成する方法
-
[解決済み] MySQLのgroup_concat_max_lenの最大許容値を教えてください。
-
[解決済み] 'PDOException' with message 'SQLSTATE[HY000] [2002] No route to host
-
Centos7 インストール mysql+keepalived 高可用性環境
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】MySQLエラー#1071 - 指定されたキーが長すぎる; キーの最大長は767バイトです。
-
[解決済み】MySQL 派生テーブルはすべて独自のエイリアスを持つ必要があります。
-
[解決済み] MySQLにおけるOracleのRowIDに相当する。
-
[解決済み] Mysql: const テーブルを読み込んだ後、不可能な場所に気づいた。
-
[解決済み] mysqlステートメントの*アスタリスクは何を意味するのですか?
-
[解決済み] MySQLワークベンチで更新クエリが機能しない
-
[解決済み] MySQL エラー 1153 - 'max_allowed_packet' バイトより大きいパケットを受け取りました。
-
MySQLサーバへの接続が「初期通信パケットの読み込み」で切断され、システムエラー:0が発生する場合の対処法
-
[解決済み] 127.0.0.1' の MySQL サーバーに接続できない (10061) (2003)
-
[解決済み] sequelize for nodeを使用してレコードを更新するにはどうすればよいですか?