PHP 애플리케이션에서 매 요청마다 새로운 DB 연결을 생성하면 성능 저하와 리소스 낭비가 발생합니다. Connection Pool을 활용한 효율적인 DB 연결 관리 방법들을 알아보겠습니다.
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;
}
}
애플리케이션 내에서 단일 연결 인스턴스를 재사용합니다.
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";
}
}
비동기 환경에서 효율적인 연결 풀을 구현합니다.
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();
}
}
}
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);
}
}
간단한 자체 구현 연결 풀입니다.
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']);
}
}
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,
],
],
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);
}
}
연결 풀의 상태를 모니터링하는 기능을 추가합니다.
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));
}
}