Connection Pooling ด้วย MySQL Proxy

เมื่อแอปพลิเคชันมีผู้ใช้งานจำนวนมากพร้อมกัน การเปิดและปิดการเชื่อมต่อไปยังฐานข้อมูลทุกครั้งที่มี Request เข้ามาจะสร้างภาระหนักให้กับเซิร์ฟเวอร์ฐานข้อมูล เพราะแต่ละการเชื่อมต่อต้องผ่านกระบวนการ TCP Handshake, Authentication และจัดสรร Thread ซึ่งใช้ทั้งเวลาและทรัพยากร

Connection Pooling เป็นเทคนิคที่แก้ปัญหานี้โดยสร้างชุดการเชื่อมต่อสำเร็จรูปไว้ล่วงหน้า แล้วนำกลับมาใช้ซ้ำแทนการสร้างใหม่ทุกครั้ง บทความนี้จะอธิบายหลักการทำงานของเทคนิคนี้, เครื่องมือ Proxy ที่นิยมใช้ได้แก่ ProxySQL และ MySQL Router รวมถึงการตั้งค่า Pooling ในฝั่ง Application ด้วย

Connection Pooling คืออะไร

Connection Pooling คือกลไกที่จัดเก็บการเชื่อมต่อฐานข้อมูลที่เปิดไว้แล้วในชุดสำรอง (Pool) เมื่อแอปพลิเคชันต้องการติดต่อฐานข้อมูล จะดึงการเชื่อมต่อจากชุดสำรองไปใช้แทนการสร้างใหม่ และเมื่อใช้เสร็จจะคืนกลับเข้าชุดสำรองแทนการปิดทิ้ง วิธีนี้ลดเวลาที่ใช้ในการสร้างและทำลายการเชื่อมต่อลงอย่างมาก

ปัญหาเมื่อไม่มี Pooling

หากแอปพลิเคชันเปิดการเชื่อมต่อใหม่ทุกครั้งที่ต้อง Query ข้อมูล ปัญหาที่มักพบ ได้แก่ การสร้างการเชื่อมต่อแต่ละครั้งใช้เวลา 5-50 ms ขึ้นอยู่กับ Network Latency และการ Authenticate ทำให้ Response Time ช้าลงโดยไม่จำเป็น นอกจากนี้ ฐานข้อมูลต้องจัดสรร Thread และหน่วยความจำให้แต่ละการเชื่อมต่อ (ประมาณ 1-10 MB ต่อการเชื่อมต่อ) เมื่อมี Request พร้อมกันหลายร้อยจะกิน RAM จำนวนมาก และค่า max_connections ของ MySQL มีขีดจำกัด (ค่าเริ่มต้น 151) เมื่อเต็มก็จะเกิด Error “Too many connections” ทำให้ผู้ใช้ไม่สามารถเข้าถึงระบบได้

วิธีการทำงานของ Pool

กระบวนการทำงานแบ่งเป็นขั้นตอนหลัก ได้แก่ เมื่อแอปพลิเคชันเริ่มต้น ชุดสำรองจะถูกสร้างไว้ล่วงหน้าตามจำนวนที่กำหนด (min_connections) เมื่อมี Request เข้ามา แอปพลิเคชันจะขอการเชื่อมต่อจากชุดสำรอง โดยจะตรวจสอบว่ามีช่องว่างอยู่หรือไม่ ถ้ามีจะส่งให้ทันที ถ้าไม่มีแต่ยังไม่ถึงขีดจำกัดจะสร้างใหม่ให้ แต่ถ้าเต็มแล้ว Request จะถูกจัดคิวรอ เมื่อ Query เสร็จ การเชื่อมต่อจะถูกคืนกลับเข้าชุดสำรองพร้อมรีเซ็ตสถานะให้สะอาดสำหรับการใช้งานครั้งถัดไป

ประเภทของ Pooling

การทำ Pooling แบ่งออกเป็น 2 ระดับหลัก คือ Client-Side ที่จัดการในฝั่ง Application และ Server-Side ที่จัดการผ่าน Proxy ตัวกลาง แต่ละแบบมีข้อดีและกรณีใช้งานที่แตกต่างกัน

Client-Side Pooling

เป็นการจัดการชุดการเชื่อมต่อภายใน Application เอง โดยใช้ Library หรือ Framework ที่รองรับ เช่น HikariCP ใน Java, SQLAlchemy ใน Python หรือ mysql2 ใน Node.js ข้อดีคือตั้งค่าง่าย ไม่ต้องติดตั้งซอฟต์แวร์เพิ่ม แต่ข้อจำกัดคือแต่ละ Instance ของแอปพลิเคชันจะมีชุดสำรองของตัวเอง หากมีหลาย Instance (เช่น รันบนหลาย Container) จำนวนการเชื่อมต่อรวมจะเป็นผลคูณของขนาดชุดสำรองกับจำนวน Instance ซึ่งอาจเกินขีดจำกัดของฐานข้อมูล

Server-Side Pooling (Proxy-Based)

เป็นการวาง Proxy ตัวกลางระหว่าง Application กับฐานข้อมูล โดย Proxy จะรับการเชื่อมต่อจาก Application ทุกตัว แล้วใช้การเชื่อมต่อจำนวนน้อยกว่าไปยังฐานข้อมูลจริง (Multiplexing) วิธีนี้เหมาะกับระบบที่มีหลาย Application Server เพราะ Proxy จะควบคุมจำนวนการเชื่อมต่อไปยังฐานข้อมูลให้อยู่ในขอบเขตที่เหมาะสม นอกจากนี้ Proxy ยังมีความสามารถเพิ่มเติม เช่น Query Routing, Load Balancing และ Query Caching

ProxySQL — Proxy ยอดนิยมสำหรับ MySQL

ProxySQL เป็น Proxy แบบ Open Source ที่ออกแบบมาสำหรับฐานข้อมูล MySQL โดยเฉพาะ รองรับทั้ง Pooling, Query Routing, Query Caching, Read/Write Splitting และ Failover อัตโนมัติ เป็นเครื่องมือที่ใช้กันอย่างแพร่หลายในระบบ Production ขนาดใหญ่

ติดตั้ง ProxySQL บน Ubuntu

# เพิ่ม Repository
sudo apt-get install -y lsb-release wget apt-transport-https
wget -O - 'https://repo.proxysql.com/ProxySQL/proxysql-2.6.x/repo_pub_key' | sudo apt-key add -
echo "deb https://repo.proxysql.com/ProxySQL/proxysql-2.6.x/$(lsb_release -sc)/" | sudo tee /etc/apt/sources.list.d/proxysql.list

# ติดตั้ง
sudo apt-get update
sudo apt-get install -y proxysql

# เริ่มบริการ
sudo systemctl start proxysql
sudo systemctl enable proxysql

ProxySQL มี Admin Interface ที่เข้าถึงได้ผ่าน MySQL Client บนพอร์ต 6032 และ Application เชื่อมต่อผ่านพอร์ต 6033

# เข้าสู่ Admin Interface (รหัสเริ่มต้น: admin/admin)
mysql -u admin -padmin -h 127.0.0.1 -P 6032 --prompt='ProxySQLAdmin> '

ตั้งค่า Backend Server

ขั้นตอนแรกคือเพิ่ม Backend Server ปลายทางที่ ProxySQL จะส่ง Query ไป โดยกำหนด Hostgroup เพื่อจัดกลุ่มเซิร์ฟเวอร์ เช่น กลุ่ม Writer (hostgroup 1) และกลุ่ม Reader (hostgroup 2)

-- เพิ่ม MySQL Server (Writer)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (1, '10.0.1.10', 3306, 1000);

-- เพิ่ม MySQL Server (Reader Replica)
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (2, '10.0.1.11', 3306, 1000);

INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES (2, '10.0.1.12', 3306, 1000);

-- บันทึกและนำไปใช้
LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

ตั้งค่า Pooling

ค่าที่สำคัญที่สุดสำหรับ Pooling คือ mysql-max_connections (จำนวนการเชื่อมต่อสูงสุดที่ ProxySQL จะเปิดไปยังแต่ละ Backend) และ mysql-connection_max_age_ms (อายุสูงสุดของการเชื่อมต่อก่อนถูกรีไซเคิล)

-- จำนวน Connection สูงสุดที่ ProxySQL รับจาก Client
SET mysql-max_connections = 2048;

-- จำนวน Connection สูงสุดต่อ Backend Server (ต่อ Hostgroup)
-- ตั้งค่าใน mysql_servers ผ่าน max_connections per server
UPDATE mysql_servers SET max_connections = 200
WHERE hostgroup_id = 1;

UPDATE mysql_servers SET max_connections = 300
WHERE hostgroup_id = 2;

-- Connection Multiplexing — เปิดการใช้ Connection ซ้ำ
SET mysql-multiplexing = true;

-- อายุสูงสุดของ Connection (ms) — รีไซเคิลทุก 1 ชั่วโมง
SET mysql-connection_max_age_ms = 3600000;

-- Free Connection หลังไม่ใช้งาน (ms)
SET mysql-free_connections_pct = 10;

LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

ด้วยการตั้งค่านี้ แม้ว่า Application จะเปิดการเชื่อมต่อมาถึง 2,048 ตัว ProxySQL จะใช้เพียง 200-300 การเชื่อมต่อจริง ๆ ไปยังแต่ละ Backend เท่านั้น ลดภาระของฐานข้อมูลได้อย่างมาก

ตั้งค่า User สำหรับ ProxySQL

Application จะเชื่อมต่อมาที่ ProxySQL ด้วย User ที่กำหนดไว้ ซึ่งต้องมีอยู่ทั้งใน ProxySQL และใน Backend

-- สร้าง User ใน MySQL Backend ก่อน
-- (บน MySQL Server)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'%';

-- เพิ่ม User ใน ProxySQL
INSERT INTO mysql_users (username, password, default_hostgroup, max_connections)
VALUES ('app_user', 'strong_password', 1, 500);

LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

ค่า default_hostgroup กำหนดว่า Query ที่ไม่มี Rule จะถูกส่งไป Hostgroup ไหน (ในที่นี้คือ 1 ซึ่งเป็น Writer) และ max_connections กำหนดจำนวนการเชื่อมต่อสูงสุดที่ User นี้เปิดได้

Read/Write Splitting

หนึ่งในความสามารถที่ทรงพลังของ ProxySQL คือการแยก Query อ่านไปยัง Replica และ Query เขียนไปยัง Primary โดยอัตโนมัติ ช่วยกระจาย Load ได้อย่างมีประสิทธิภาพ

-- Query ที่ขึ้นต้นด้วย SELECT ส่งไป Hostgroup 2 (Reader)
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (100, 1, '^SELECT.*FOR UPDATE$', 1, 1);

INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (200, 1, '^SELECT', 2, 1);

-- Query อื่น ๆ (INSERT, UPDATE, DELETE) ไปที่ Hostgroup 1 (Writer) ตาม default_hostgroup

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

Rule แรก (rule_id 100) จับ SELECT … FOR UPDATE ส่งไปที่ Writer เพราะเป็นการอ่านที่ต้อง Lock ข้อมูล ส่วน Rule ที่สอง (rule_id 200) จับ SELECT ทั่วไปส่งไปที่ Reader

ตรวจสอบสถานะ Pooling

-- ดูสถานะ Connection ทั้งหมด
SELECT * FROM stats_mysql_connection_pool;

-- ดูจำนวน Connection ที่ใช้งานอยู่
SELECT hostgroup, srv_host, srv_port,
       ConnUsed, ConnFree, ConnOK, ConnERR,
       MaxConnUsed, Queries
FROM stats.stats_mysql_connection_pool;

-- ดูสถิติ Query
SELECT hostgroup, digest_text, count_star, sum_time
FROM stats_mysql_query_digest
ORDER BY sum_time DESC
LIMIT 10;

ค่า ConnUsed แสดงการเชื่อมต่อที่กำลังใช้งาน, ConnFree แสดงการเชื่อมต่อว่างในชุดสำรอง และ MaxConnUsed แสดงจำนวนสูงสุดที่เคยใช้พร้อมกัน ข้อมูลเหล่านี้ช่วยวางแผนปรับขนาดชุดสำรองได้อย่างเหมาะสม

MySQL Router — เครื่องมือจาก Oracle

MySQL Router เป็น Lightweight Proxy ที่พัฒนาโดย Oracle เหมาะสำหรับใช้ร่วมกับ InnoDB Cluster หรือ Group Replication โดยเฉพาะ รองรับ Routing, Failover อัตโนมัติ และ Pooling พื้นฐาน

ติดตั้ง MySQL Router

# ติดตั้งบน Ubuntu
sudo apt-get install -y mysql-router

# Bootstrap กับ InnoDB Cluster
sudo mysqlrouter --bootstrap [email protected]:3306 --user=mysqlrouter --directory=/etc/mysqlrouter

# เริ่มบริการ
sudo systemctl start mysqlrouter
sudo systemctl enable mysqlrouter

หลัง Bootstrap แล้ว Router จะสร้าง Configuration อัตโนมัติ โดยปกติจะเปิด 2 พอร์ต คือพอร์ต 6446 สำหรับ Read-Write (ส่งไป Primary) และพอร์ต 6447 สำหรับ Read-Only (กระจายไป Secondary)

ตั้งค่า Pooling ใน Router

# /etc/mysqlrouter/mysqlrouter.conf

[routing:primary]
bind_address = 0.0.0.0
bind_port = 6446
destinations = metadata-cache://mycluster/?role=PRIMARY
routing_strategy = first-available
max_connections = 1024
max_connect_errors = 100
client_connect_timeout = 9

[routing:secondary]
bind_address = 0.0.0.0
bind_port = 6447
destinations = metadata-cache://mycluster/?role=SECONDARY
routing_strategy = round-robin-with-fallback
max_connections = 2048
max_connect_errors = 100
client_connect_timeout = 9

[connection_pool]
max_idle_server_connections = 64

ค่า max_idle_server_connections กำหนดจำนวนการเชื่อมต่อว่างที่ Router จะเก็บไว้สำหรับใช้ซ้ำ ส่วน routing_strategy กำหนดวิธีเลือก Backend โดย round-robin-with-fallback จะกระจายการเชื่อมต่อไปทุก Secondary อย่างเท่าเทียม และ Fallback ไปที่ Primary ถ้า Secondary ไม่พร้อม

เปรียบเทียบ ProxySQL กับ MySQL Router

ProxySQL มีความสามารถมากกว่า เช่น Query Caching, Query Rewriting, Regex-based Routing และ Multiplexing ที่ลดจำนวน Backend Sessions ได้อย่างมีประสิทธิภาพ เหมาะกับระบบที่ต้องการ Fine-tuning และมีหลาย Application เชื่อมต่อ ส่วน Router เหมาะกับผู้ที่ใช้ InnoDB Cluster อยู่แล้ว ต้องการ Proxy ที่ตั้งค่าง่ายและ Integrate กับ Ecosystem ได้ดี โดยไม่ต้องการ Feature ขั้นสูง

Client-Side Pooling ในฝั่ง Application

นอกจากการใช้ Proxy แล้ว การตั้งค่าชุดการเชื่อมต่อในฝั่ง Application ก็สำคัญไม่แพ้กัน ต่อไปนี้เป็นตัวอย่างการตั้งค่าในภาษาโปรแกรมที่นิยม

Python — SQLAlchemy

from sqlalchemy import create_engine

engine = create_engine(
    "mysql+pymysql://app_user:password@proxysql-host:6033/mydb",
    pool_size=20,          # จำนวน Connection ใน Pool
    max_overflow=10,       # Connection เพิ่มเติมเมื่อ Pool เต็ม
    pool_timeout=30,       # รอ Connection สูงสุด (วินาที)
    pool_recycle=3600,     # รีไซเคิล Connection ทุก 1 ชั่วโมง
    pool_pre_ping=True,    # ตรวจสอบ Connection ก่อนใช้งาน
)

# ใช้งาน
with engine.connect() as conn:
    result = conn.execute("SELECT * FROM orders LIMIT 10")
    for row in result:
        print(row)

ค่า pool_pre_ping=True จะตรวจสอบว่าการเชื่อมต่อยังใช้งานได้ก่อนส่งให้ Application ช่วยป้องกันปัญหา “MySQL server has gone away” ที่เกิดจากการเชื่อมต่อหมดอายุแต่ยังอยู่ใน Pool

Node.js — mysql2

const mysql = require('mysql2/promise');

const pool = mysql.createPool({
  host: 'proxysql-host',
  port: 6033,
  user: 'app_user',
  password: 'password',
  database: 'mydb',
  waitForConnections: true,   // รอเมื่อ Pool เต็ม
  connectionLimit: 20,        // จำนวน Connection สูงสุด
  queueLimit: 0,              // คิว Query ไม่จำกัด
  idleTimeout: 60000,         // ปิด Connection ที่ว่าง 60 วินาที
  enableKeepAlive: true,      // ส่ง Keep-Alive Packet
  keepAliveInitialDelay: 10000
});

// ใช้งาน
async function getOrders() {
  const [rows] = await pool.execute('SELECT * FROM orders LIMIT 10');
  return rows;
  // ไม่ต้อง release — pool.execute จัดการให้อัตโนมัติ
}

Java — HikariCP

// HikariCP — Connection Pool ที่เร็วที่สุดใน Java Ecosystem

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://proxysql-host:6033/mydb");
config.setUsername("app_user");
config.setPassword("password");

// Pool Settings
config.setMaximumPoolSize(20);       // Connection สูงสุด
config.setMinimumIdle(5);            // Connection ขั้นต่ำที่เก็บไว้
config.setIdleTimeout(300000);       // ปิด Idle Connection หลัง 5 นาที
config.setMaxLifetime(1800000);      // อายุสูงสุด 30 นาที
config.setConnectionTimeout(30000);  // รอ Connection สูงสุด 30 วินาที

// Validation
config.setConnectionTestQuery("SELECT 1");

HikariDataSource dataSource = new HikariDataSource(config);

การคำนวณขนาด Pool ที่เหมาะสม

การตั้งค่าขนาดชุดสำรองที่เหมาะสมเป็นเรื่องสำคัญ ถ้าใหญ่เกินไปจะกินทรัพยากรฐานข้อมูลโดยไม่จำเป็น ถ้าเล็กเกินไปจะทำให้ Request ต้องรอคิวนาน สูตรที่นิยมใช้เป็นจุดเริ่มต้นคือ

# สูตร Pool Size พื้นฐาน (ตาม HikariCP wiki)
pool_size = (core_count * 2) + effective_spindle_count

# ตัวอย่าง: เซิร์ฟเวอร์ 4 Core, SSD (spindle = 0)
pool_size = (4 * 2) + 1 = 9

# สำหรับระบบที่มีหลาย Application Server
total_connections = pool_size_per_app * number_of_app_instances
# ต้องไม่เกิน max_connections ของ MySQL

สูตรนี้เป็นจุดเริ่มต้นที่ดี แต่ขนาดที่เหมาะสมจริง ๆ ขึ้นอยู่กับลักษณะ Workload ควรทดสอบและปรับค่าตามผลลัพธ์จริง โดยมีหลักคิดว่า หาก Query ส่วนใหญ่เร็ว (ใช้เวลาน้อยกว่า 10 ms) ชุดสำรองขนาดเล็กก็เพียงพอ เพราะการเชื่อมต่อจะถูกใช้และคืนอย่างรวดเร็ว แต่หาก Query ช้า (มีการรอ I/O หรือ Lock) อาจต้องเพิ่มขนาดชุดสำรองเพื่อรองรับการเชื่อมต่อที่ถูกยึดไว้นาน

ตรวจสอบและ Monitor การเชื่อมต่อ

การ Monitor จำนวนและสถานะของการเชื่อมต่อเป็นสิ่งจำเป็นเพื่อตรวจหาปัญหาก่อนที่จะกระทบผู้ใช้ คำสั่งที่ใช้บ่อยมีดังนี้

-- ดูจำนวน Connection ปัจจุบัน
SHOW STATUS LIKE 'Threads_connected';

-- ดูจำนวน Connection สูงสุดที่เคยใช้พร้อมกัน
SHOW STATUS LIKE 'Max_used_connections';

-- ดูค่า max_connections ที่ตั้งไว้
SHOW VARIABLES LIKE 'max_connections';

-- ดูรายละเอียด Connection ทั้งหมด
SHOW PROCESSLIST;

-- ดู Connection ที่ค้างนานกว่า 60 วินาที
SELECT id, user, host, db, command, time, state
FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE command != 'Sleep' AND time > 60
ORDER BY time DESC;

-- ดู Connection ที่ Sleep นานผิดปกติ (อาจเป็น Connection Leak)
SELECT id, user, host, db, time
FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE command = 'Sleep' AND time > 300
ORDER BY time DESC;

ตรวจจับ Leak

Leak เกิดเมื่อ Application ดึงการเชื่อมต่อจากชุดสำรองแล้วไม่คืน เช่น ลืม close() หรือเกิด Exception ก่อนถึงจุดคืน ปัญหานี้ทำให้ชุดสำรองค่อย ๆ หมดจนไม่มีการเชื่อมต่อว่างให้ใช้ สัญญาณที่บ่งบอกว่ามี Leak ได้แก่ จำนวน Active Sessions เพิ่มขึ้นเรื่อย ๆ โดยไม่ลดลง, Application เริ่มแสดง Timeout Error ถี่ขึ้น และมี Thread แบบ Sleep จำนวนมากที่ค้างนาน

# HikariCP — เปิด Leak Detection (แจ้งเตือนถ้าใช้ Connection นานเกินกำหนด)
config.setLeakDetectionThreshold(60000);  # 60 วินาที

# SQLAlchemy — ใช้ pool_recycle เพื่อป้องกัน Stale Connection
engine = create_engine("mysql+pymysql://...", pool_recycle=3600)

MySQL Proxy — เครื่องมือรุ่นแรกจาก MySQL

MySQL Proxy เป็นเครื่องมือที่ MySQL AB (ปัจจุบันคือ Oracle) พัฒนาขึ้นเพื่อทำหน้าที่เป็นตัวกลางระหว่าง Application กับเซิร์ฟเวอร์ฐานข้อมูล รองรับ Pooling, Query Interception และ Load Balancing ผ่าน Lua Script อย่างไรก็ตาม โครงการนี้หยุดพัฒนาตั้งแต่ปี 2014 และไม่ได้ออกเวอร์ชันเสถียร (Stable Release) เลย

ปัจจุบัน Oracle แนะนำให้ใช้ Router แทน และชุมชนส่วนใหญ่หันไปใช้ ProxySQL ซึ่งมีความสามารถมากกว่า เสถียรกว่า และยังพัฒนาอย่างต่อเนื่อง หากคุณพบ Tutorial เก่า ๆ ที่สอนใช้เครื่องมือนี้ ควรเปลี่ยนมาใช้ ProxySQL หรือ Router แทน

Best Practices สำหรับ Pooling

เพื่อให้การจัดการ Pooling ทำงานได้อย่างมีประสิทธิภาพสูงสุด ควรปฏิบัติตามแนวทางต่อไปนี้

ใช้การเชื่อมต่อให้สั้นที่สุด — ดึงการเชื่อมต่อจากชุดสำรองเมื่อต้องใช้ ทำ Query ให้เสร็จ แล้วคืนทันที อย่ายึดไว้ระหว่างรอ Input จากผู้ใช้หรือเรียก API ภายนอก เพราะจะทำให้ชุดสำรองหมดโดยไม่จำเป็น

เปิด pool_pre_ping หรือ Validation Query — การเชื่อมต่อที่อยู่ในชุดสำรองนาน ๆ อาจถูกฐานข้อมูลตัดทิ้งเมื่อเกิน wait_timeout การตรวจสอบก่อนใช้งานจะป้องกัน Error ที่เกิดจาก Stale Connection

ตั้งค่า pool_recycle ให้น้อยกว่า wait_timeout — ค่า wait_timeout ของฐานข้อมูล (ค่าเริ่มต้น 28,800 วินาที หรือ 8 ชั่วโมง) คือเวลาที่เซิร์ฟเวอร์จะปิดการเชื่อมต่อที่ไม่มีการใช้งาน ควรตั้ง pool_recycle ให้สั้นกว่า เช่น 3,600 วินาที (1 ชั่วโมง) เพื่อรีไซเคิลก่อนที่ฝั่งเซิร์ฟเวอร์จะตัด

คำนวณจำนวนการเชื่อมต่อรวมของทั้งระบบ — หากมี 5 Application Server แต่ละตัวตั้งขนาดชุดสำรองไว้ที่ 20 ระบบจะเปิดการเชื่อมต่อไปยังฐานข้อมูลสูงสุด 100 ตัว ต้องแน่ใจว่าค่า max_connections (รวมส่วนที่ใช้สำหรับ Admin, Monitoring และ Replication ด้วย) เพียงพอรองรับ

ใช้ Proxy เมื่อ Scale ออกเป็นหลาย Instance — เมื่อมี Application หลายตัวเชื่อมต่อ การใช้ ProxySQL เป็นตัวกลางจะช่วย Multiplex การเชื่อมต่อ ลดภาระฐานข้อมูลได้ดีกว่าพึ่ง Client-Side เพียงอย่างเดียว

สรุป

การทำ Pooling เป็นเทคนิคพื้นฐานที่ทุกระบบที่ใช้ฐานข้อมูลควรนำไปใช้ ไม่ว่าจะเป็นระดับ Application (Client-Side) หรือระดับ Infrastructure (Proxy-Based) การนำช่องทางกลับมาใช้ซ้ำแทนการสร้างใหม่ทุกครั้งช่วยลดเวลา Response, ลดภาระ CPU และ Memory ของเซิร์ฟเวอร์ฐานข้อมูล และป้องกันปัญหา Too many connections

สำหรับระบบขนาดเล็กถึงกลาง การตั้งค่า Client-Side ใน Application (เช่น HikariCP, SQLAlchemy, mysql2) ก็เพียงพอ แต่เมื่อระบบเติบโตมีหลาย Application Server การวาง ProxySQL หรือ Router เป็นตัวกลางจะช่วย รวมการเชื่อมต่อ, แยก Read/Write และ Failover ได้อัตโนมัติ ทำให้ระบบรองรับ Traffic ได้สูงขึ้นโดยไม่ต้องเพิ่มทรัพยากรมากนัก

แนะนำบริการ DE

การตั้งค่า Pooling ด้วย ProxySQL หรือ Router ต้องการเซิร์ฟเวอร์ที่สามารถติดตั้งและปรับแต่งซอฟต์แวร์ได้อย่างอิสระ Cloud VPS ของ DE เป็นตัวเลือกที่เหมาะสม เพราะให้ root access เต็มรูปแบบ สามารถติดตั้ง ProxySQL, ตั้งค่า Multiplexing และจัดการ Read/Write Splitting ได้ตามต้องการ รองรับทั้งการรัน Proxy และ MySQL บนเครื่องเดียวกัน หรือแยกเครื่องเพื่อ Scale ในอนาคต

สำหรับผู้ที่ต้องการโฮสต์เว็บไซต์โดยไม่ต้องจัดการ Proxy เอง Cloud Hosting ของ DE มีระบบการจัดการฐานข้อมูลมาให้พร้อมใช้งาน เหมาะกับเว็บไซต์ที่ต้องการความสะดวกโดยไม่ต้องดูแล Infrastructure เอง