Из энциклопедии Baidu:
Пул соединений с базой данных отвечает за выделение, управление и освобождение соединений с базой данных.Он позволяет приложениям повторно использовать существующее соединение с базой данных вместо его повторной установки; освобождать соединения с базой данных, время простоя которых превышает максимальное время простоя, чтобы избежать сбоя из-за сбоя освободить соединения с базой данных. Вызвано отсутствием соединений с базой данных. Этот метод может значительно повысить производительность операций с базой данных.
Подключения к базе данных являются важным, ограниченным и дорогостоящим ресурсом, особенно в многопользовательских веб-приложениях. Управление подключениями к базе данных может существенно повлиять на масштабируемость и надежность всего приложения, а также повлиять на показатели производительности программы. Для решения этой проблемы предлагается пул соединений с базой данных.
Установка минимального количества соединений и максимального количества соединений в пуле соединений с базой данных должна учитывать следующие факторы:
1. Минимальное количество подключений
Это соединение с базой данных, которое всегда поддерживается пулом соединений, поэтому, если приложение не использует соединение с базой данных, много ресурсов соединения с базой данных будет потрачено впустую.
2. Максимальное количество подключений
Это максимальное количество подключений, к которым может обратиться пул подключений.Если запрос на подключение к базе данных превышает это число, последующие запросы на подключение к базе данных будут добавлены в очередь ожидания, что повлияет на последующие операции с базой данных.
3. Разрыв между минимальным количеством подключений и максимальным количеством подключений
Если разница между минимальным количеством подключений и максимальным количеством подключений слишком велика, первый запрос на подключение будет прибыльным, а запрос на подключение, превышающий минимальное количество подключений, эквивалентен установлению нового подключения к базе данных. Однако эти подключения к базе данных, число которых превышает минимальное количество подключений, не будут разъединяться сразу после использования, они будут помещены в пул соединений для ожидания повторного использования или будут разъединены по истечении времени простоя.
В PHP-FPM база данных не имеет пула соединения. Запрос начинается, а соединение базы данных устанавливается, когда данные должны быть запрошены, а затем данные запрашиваются, и соединение закрывается после завершения запроса. Следующий запрос продолжает повторять эту операцию, недостаток заключается в том, что операция подключения к базе данных должна быть инициализирована в каждом запросе.
В Swoole за счет персистентности объектов определенное количество подключений к базе данных может быть установлено заранее в начале запуска сервера и помещено туда.Когда приложению нужно подключение, его можно получить, и приложение будет подключаться к базе данных каждый раз время от времени Поддерживайте между min-max и отправляйте простой запрос в базу данных, чтобы поддерживать постоянное соединение с базой данных, тем самым исключая процесс установления соединения.
Swoole уже предоставляет асинхронный клиент Mysql. Далее будет использоваться асинхронный клиент Mysql для реализации пула соединений.
<?php
/**
* author : rookiejin <mrjnamei@gmail.com>
* createTime : 2018/1/16 14:32
* description: Server.php - swoole-demo
*/
class Pool
{
// 连接池数组 .
protected $connections ;
// 最大连接数
protected $max ;
// 最小连接数
protected $min ;
// 已连接数
protected $count = 0 ;
protected $inited = false ;
// 单例
private static $instance ;
//数据库配置
protected $config = array(
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'password' => 'rootpassword',
'database' => 'swoole',
'charset' => 'utf8',
'timeout' => 2,
);
public function __construct()
{
//初始化连接是一个Spl队列
$this->connections = new SplQueue() ;
$this->max = 30 ;
$this->min = 5 ;
// 绑定单例
self::$instance = & $this ;
}
// worker启动的时候 建立 min 个连接
public function init()
{
if($this->inited){
return ;
}
for($i = 0; $i < $this->min ; $i ++){
$this->generate();
}
return $this ;
}
/**
* 维持当前的连接数不断线,并且剔除断线的链接 .
*/
public function keepAlive()
{
// 2分钟检测一次连接
swoole_timer_tick( 1000 , function(){
// 维持连接
while ($this->connections->count() >0 && $next=$this->connections->shift()){
$next->query("select 1" , function($db ,$res){
if($res == false){
return ;
}
echo "当前连接数:" . $this->connections->count() . PHP_EOL ;
$this->connections->push($db);
});
}
});
swoole_timer_tick(1000 , function(){
// 维持活跃的链接数在 min-max之间
if($this->connections->count() > $this->max) {
while($this->max < $this->connections->count()){
$next = $this->connections->shift();
$next->close();
$this->count-- ;
echo "关闭连接...\n" ;
}
}
});
}
// 建立一个新的连接
public function generate($callback = null)
{
$db = new swoole_mysql ;
$db->connect($this->config , function($db , $res) use($callback) {
if($res == false){
throw new Exception("数据库连接错误::" . $db->connect_errno . $db->connect_error);
}
$this->count ++ ;
$this->addConnections($db);
if(is_callable($callback)){
call_user_func($callback);
}
});
}
// 连接推进队列
public function addConnections($db)
{
$this->connections->push($db);
return $this;
}
// 执行数据库命令 . 会判断连接数够不够,够就直接执行,不够就新建连接执行
public function query($query , $callback)
{
if($this->connections->count() == 0) {
$this->generate(function() use($query,$callback){
$this->exec($query,$callback);
});
}
else{
$this->exec($query,$callback);
}
}
// 直接执行数据库命令并且 callback();
private function exec($query, $callback)
{
$db = $this->connections->shift();
$db->query($query ,function($db , $result) use($callback){
$this->connections->push($db);
$callback($result);
});
}
public static function getInstance()
{
if(is_null(self::$instance)){
new Pool();
}
return self::$instance;
}
}
$server = new swoole_http_server("0.0.0.0",9501);
$server->set([
'worker_num' => 4 ,
]);
$server->on("WorkerStart",function($server , $wid){
Pool::getInstance()->init()->keepAlive();
});
$server->on("request",function($request,$response){
$pool = Pool::getInstance()->query("select * from users", function($res) use($response) {
$response->end(json_encode($res));
});
});
$server->start();
Интерпретация кода:
- Когда workerStart впервые создает экземпляр пула синглтона, пул инициализирует конфигурацию и привязывает синглтон к себе.
- Выполните функцию init(), которая в основном предназначена для инициализации количества пулов соединений до числа Pool::min.
- Выполните команду keepAlive(), которая в основном использует два таймера для регулярной проверки состояния соединения с базой данных и количества соединений. Конкретное время может быть определено в зависимости от бизнеса.
- Слушайте http-запросы и выполняйте sql там, где вам нужно использовать базу данных. Вы можете инкапсулировать sql в форму для работы.
- Наконец верните ответ.
Хотя пул соединений и реализован, в процессе разработки нас беспокоит бесконечная вложенность callback-функций.
В следующем разделе будет показано, как использовать синхронную запись для реализации асинхронных операций.
Если есть ошибка, пожалуйста, исправьте ее!
Этот код был размещен на github:clearcodecn/swoole-demo
Кроме того:clearcode.cnЭто сообщество, которое я создаю. Оно направлено на объяснение серверных технологий и принципов, а также на отстаивание духа открытого исходного кода. Лучше научить людей ловить рыбу, чем учить их, как ловить рыбу. Из-за нехватки времени , прогресс идет медленно.Я надеюсь, что заинтересованные друзья объединятся.
Группа QQ: 139348611
Перепечатка просьба указывать источник!