Swoole-Demo(3) Пул соединений с базой данных Swoole

PHP Swoole

Из энциклопедии 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

Перепечатка просьба указывать источник!