基于laravel、swoole的mysql连接池

冉子石
2023-12-01

基于swoole的mysql连接池

基于swoole协程的mysql连接池

前言

​ 传统的nginx+FPM模式的PHP程序而言,每次请求FPM的worker都会连接一次mysql,然后请求结束便会断开连接。对于并发小的应用来说这不会有什么问题,但是对于高并发的应用来说,频繁建立连接Connect和销毁连接Close,数据库便会成为瓶颈,相信不少人也遇到过to many connection的mysql报错吧。

连接池的优势

​ 连接池采用的是长连接模式,会一直保持与MySQL的连接,用完后会重新放回连接池,从而节省了建立连接和断开连接的消耗,大大降低了系统IO的消耗,一定程度上提高了程序的并发性能。如果连接池空闲,就从连接池分配一个连接,否则,请求将被加入到等待队列中。

连接池的缺点

​ 目前的laravel+swoole中使用连接池,只能使用原生的sql语句,查询构建器会失效

适合场景

​ 连接池仅在超大型应用中才有价值,连接池并没有提高sql的查询速度,连接池是用来保护数据库的,限制连接数,为了避免连接过多导致数据库崩溃,不是用来提升性能的

mysql连接池

mysqlPool 封装目录结构
├─Provider --------- 服务提供者
│ ├─AppServiceProvider.php ------ 注册服务提供者
├─pool --------- 主目录
│ ├─Core
│ │ ├─MySQLPool.php ------ mysql操作类
│ ├─Database
│ │ ├─DBPool.php ------- DB连接池封装类
│ ├─DB.php ---------------- swoole一键协程封装
AppServiceProvider.php - 注册服务提供者
use App\pool\Core\MySQLPool;
use App\pool\Database\DbPool;
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    $this->app->bind('mysql_pool',function (){
        return new MySQL(new DbPool($this->app));
    });
}
MySQLPool.php - 操作类
<?php
namespace App\pool\Core;

class MySQLPool
{
    /**
     * @var
     *  在实例化时获取到的连接池对象
     */
    protected $pool;

    public function __construct($pool)
    {
        $this->pool = $pool;
    }

    /**
     * @return mixed
     *  从连接池中获取连接
     */
    public function connection()
    {
        return $this->pool->get();
    }

	/**
     * 归还连接池
     * @param $pdo
     */
    public function put($pdo)
    {
        $this->pool->put($pdo);
    }
    
	/**
     * 执行语句查询
     * @param $sql
     * @return string
     */
    public function query($sql)
    {
        try{
            $pdo = $this->connection();
            
            $return = $pdo->query($sql)->fetch();
            $this->put($pdo);
            
            return $return;
        }catch (\PDOException $e){
            $this->put($pdo);
            return $e->getMessage();
        }
    }
    
	/**
     * 执行语句操作
     * @param $sql
     * @return bool|string
     */
    public function execute($sql)
    {
        try{
            $pdo = $this->connection();
            
            $pdo->exec($sql);
            $this->put($pdo);
            
            return true;
        }catch (\PDOException $e){
            $this->put($pdo);
            return $e->getMessage();
        }
    }
}

DBPool.php - 连接池封装类
<?php

namespace App\pool\Database;

use Illuminate\Foundation\Application;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;

class DbPool
{
    protected  $app;

    protected $pool;

    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->init();
    }

    public function init()
    {
        
        $cofig = (new PDOConfig)
            ->withHost(env('DB_HOST'))
            ->withPort(env('DB_PORT'))
            ->withDbname(env('DB_DATABASE'))
            ->withUsername(env('DB_USERNAME'))
            ->withPassword(env('DB_PASSWORD'));
        
        $this->pool = new PDOPool($cofig,env('DB_SIZE'));

    }

    public function get($schema)
    {
        return $this->pool->get();
    }

    public function put($pdo,$schema)
    {
        $this->pool->put($pdo);
    }
}
DB.php - swoole一键协程封装
<?php

namespace App\pool;

use Swoole\Runtime;
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

class DB
{
    public static function getDriver()
    {
        return app('mysql_pool');
    }

    public static function __callStatic($name, $arguments)
    {
        //一键协程化
        Runtime::enableCoroutine();
        
        //设置一个容量为1的通道
        $chan = new Channel(1);
        
        创建一个新的协程
        Coroutine::create(function () use ($chan,$name,$arguments){
            $pdo = self::getDriver();
            
            //执行mysql相关 操作
            $return = $pdo->$name(...$arguments);
            $chan->push($return);
        });
        return $chan->pop();
    }
}

在控制层调用 ProductController
<?php

namespace App\Http\Controllers;

use App\pool\DB;
use Illuminate\Http\Request;

class ProductController extends Controller
{
	public function index(Request $request){
        
        $sql = "insert into orders(id,user_id) values (64,3)";
        
        #执行操作
        $result = DB::execute($sql);
        
        $sql = "select * from t where id = 1","users";
        
        //执行查询
        $data = DB::query($sql);
        
        return response()->json($data);
    }
}
 类似资料: