PHP에서 DB Connection Pool 미사용 문제와 해결책

프리터코더·2025년 6월 21일
0

php 문제 해결

목록 보기
70/79

PHP 애플리케이션에서 매 요청마다 새로운 DB 연결을 생성하면 성능 저하와 리소스 낭비가 발생합니다. Connection Pool을 활용한 효율적인 DB 연결 관리 방법들을 알아보겠습니다.

1. PDO Persistent Connection 사용

PHP의 내장 지속 연결 기능을 활용합니다.

class Database {
    private static $instance = null;
    
    public static function getInstance() {
        if (self::$instance === null) {
            $dsn = "mysql:host=localhost;dbname=myapp;charset=utf8mb4";
            self::$instance = new PDO($dsn, $username, $password, [
                PDO::ATTR_PERSISTENT => true,
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
            ]);
        }
        return self::$instance;
    }
}

2. 싱글톤 패턴으로 연결 재사용

애플리케이션 내에서 단일 연결 인스턴스를 재사용합니다.

class ConnectionManager {
    private static $connections = [];
    
    public static function getConnection($name = 'default') {
        if (!isset(self::$connections[$name])) {
            $config = self::getConfig($name);
            self::$connections[$name] = new PDO(
                $config['dsn'], 
                $config['username'], 
                $config['password'],
                $config['options']
            );
        }
        return self::$connections[$name];
    }
    
    private static function getConfig($name) {
        return require "config/database.php";
    }
}

3. ReactPHP를 이용한 비동기 Connection Pool

비동기 환경에서 효율적인 연결 풀을 구현합니다.

use React\MySQL\Factory;
use React\MySQL\ConnectionInterface;

class AsyncConnectionPool {
    private $factory;
    private $connections = [];
    private $maxConnections = 10;
    
    public function __construct() {
        $this->factory = new Factory();
    }
    
    public function getConnection(): Promise {
        if (count($this->connections) > 0) {
            return resolve(array_pop($this->connections));
        }
        
        return $this->factory->createConnection('mysql://user:pass@localhost/db');
    }
    
    public function releaseConnection(ConnectionInterface $connection) {
        if (count($this->connections) < $this->maxConnections) {
            $this->connections[] = $connection;
        } else {
            $connection->close();
        }
    }
}

4. Swoole Connection Pool 활용

Swoole 확장을 사용한 고성능 연결 풀입니다.

use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;

class DatabasePool {
    private static $pool;
    
    public static function init() {
        $config = (new PDOConfig())
            ->withHost('127.0.0.1')
            ->withPort(3306)
            ->withDbName('test')
            ->withCharset('utf8mb4')
            ->withUsername('root')
            ->withPassword('password');
            
        self::$pool = new PDOPool($config, 64);
    }
    
    public static function getConnection() {
        return self::$pool->get();
    }
    
    public static function putConnection($connection) {
        self::$pool->put($connection);
    }
}

5. 커스텀 Connection Pool 클래스

간단한 자체 구현 연결 풀입니다.

class SimpleConnectionPool {
    private $pool = [];
    private $config;
    private $maxSize = 10;
    private $currentSize = 0;
    
    public function __construct($config) {
        $this->config = $config;
    }
    
    public function getConnection() {
        if (!empty($this->pool)) {
            return array_pop($this->pool);
        }
        
        if ($this->currentSize < $this->maxSize) {
            $this->currentSize++;
            return $this->createConnection();
        }
        
        throw new Exception("Connection pool exhausted");
    }
    
    public function returnConnection($connection) {
        if (count($this->pool) < $this->maxSize) {
            $this->pool[] = $connection;
        }
    }
    
    private function createConnection() {
        return new PDO($this->config['dsn'], $this->config['user'], $this->config['pass']);
    }
}

6. Laravel의 DB Connection Pool 설정

Laravel에서 연결 풀을 효율적으로 설정합니다.

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'options' => [
        PDO::ATTR_PERSISTENT => true,
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET SESSION wait_timeout=600'
    ],
    'pool' => [
        'min_connections' => 1,
        'max_connections' => 10,
        'connect_timeout' => 10.0,
        'wait_timeout' => 3.0,
    ],
],

7. Redis를 이용한 Connection Pool 관리

Redis로 연결 상태를 관리하는 분산 환경 대응 방법입니다.

class RedisConnectionPool {
    private $redis;
    private $poolKey = 'db_connection_pool';
    
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    
    public function getConnection() {
        $connectionId = $this->redis->spop($this->poolKey);
        
        if ($connectionId) {
            return $this->restoreConnection($connectionId);
        }
        
        return $this->createNewConnection();
    }
    
    public function returnConnection($connection, $connectionId) {
        $this->redis->sadd($this->poolKey, $connectionId);
        // 연결 정보를 Redis에 저장
    }
    
    private function createNewConnection() {
        return new PDO($dsn, $username, $password);
    }
}

8. 연결 상태 모니터링

연결 풀의 상태를 모니터링하는 기능을 추가합니다.

class PoolMonitor {
    public static function getPoolStats($pool) {
        return [
            'active_connections' => $pool->getActiveCount(),
            'idle_connections' => $pool->getIdleCount(),
            'total_connections' => $pool->getTotalCount(),
            'pool_utilization' => $pool->getUtilization(),
            'created_connections' => $pool->getCreatedCount(),
            'destroyed_connections' => $pool->getDestroyedCount()
        ];
    }
    
    public static function logPoolStats($pool) {
        $stats = self::getPoolStats($pool);
        error_log("DB Pool Stats: " . json_encode($stats));
    }
}
profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글