
Vì sao cần connection pool?
Trong ứng dụng web hiện đại, mỗi request HTTP thường cần ít nhất một kết nối database để đọc/ghi dữ liệu. Nếu mỗi request tự mở một kết nối TCP mới tới PostgreSQL/MySQL, hệ thống sẽ nhanh chóng sử dụng hết cổng ephemeral trên client và đạt tới max_connections trên server — dẫn đến lỗi “too many connections”. Bên cạnh đó, TCP 3-way handshake + TLS handshake (nếu dùng SSL) thêm 150-300ms latency cho mỗi kết nối mới.
Connection pool giải quyết bằng cách duy trì một hồ sơ kết nối sẵn sàng (pool). Khi app cần kết nối, pool trả về một kết nối đã được xác thực; khi xong, app trả kết nối vào pool thay vì đóng nó. Kết quả: latency giảm xuống ~1ms, giảm 90%+ TCP handshake, và database chỉ chịu tải từ số kết nối tối đa được cấu hình trong pool (ví dụ: 20 thay vì 2000).
Kiến trúc chung của connection pool
Một connection pool thực hiện 3 nhiệm vụ chính:
- Quản lý lifecycle kết nối: tạo mới, kiểm tra sức khỏe (validation query), và hủy kết nối cũ.
- Thread-safe allocation: nhiều thread/app instance có thể đồng thời hỏi/mời kết nối mà không gây race condition.
- Monitoring & metrics: active/idle counts, wait times, leak detection, và histogram response time.
Các giải pháp phổ biến tuân theo chuẩn JDBC (Java) hoặc DB-API (Python), nhưng nguyên tắc cơ bản giống nhau: FIFO/LIFO allocation, idle connection eviction, và background validation.

HikariCP: Java’s High-Performance Pool
HikariCP là connection pool nhanh nhất trên JVM (theo benchmark TechEmpower), thường được tích hợp sẵn trong Spring Boot. Đặc trưng:
- Bytecode optimization: tối thiểu reflection, dùng proxies and inheritance thay vì reflection.
- Fail-fast validation: kiểm tra socket I/O thay vì chạy “SELECT 1” mỗi lần checkout (configurable).
- Lean locking: dùng ConcurrentLinkedQueue và phong cái đeo schrijf lock thay vì synchronized blocks.
- Zero configuration overload: 90% cases chỉ cần đặt
jdbcUrl,username,password— các thông số nhưmaximumPoolSize,connectionTimeout,idleTimeoutcó giá trị mặc định hợp lý.
Cấu hình tiêu chuẩn cho web app:
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.keepalive-time=0
spring.datasource.hikari.validation-timeout=5000
HikariCP cũng hỗ trợ leak detection qua leakDetectionThreshold — nếu connection không được trả lại sau X ms, log warning + stack trace giúp developer sửa bug.
PgBouncer: Lightweight PostgreSQL Connection Pooler
PgBouncer không phải là library mà là daemon standalone chạy trên cùng máy (hoặc dedicated box) làm proxy giữa app và PostgreSQL. Nó nói PostgreSQL protocol fluently và hỗ trợ 3 chế độ pooling:
- Session pooling (mặc định): mỗi connection từ app được ánh xạ 1:1 tới PostgreSQL connection — an toàn nhất, tương thích 100%.
- Transaction pooling: connection được trả về pool ngay sau khi transaction kết thúc (COMMIT/ROLLBACK). Lưu ý: không thể dùng prepared statements xuyên qua transactions.
- Statement pooling: connection được trả về sau mỗi statement — chỉ thích hợp cho autocommit-only workloads.
Ưu điểm nổi bật: memory footprint thấp (~2-5MB per 1000 connections), có thể chia sẻ pool giữa nhiều ứng dụng khác nhau, và hỗ trợ online reload cấu hình mà không ngắt kết nối hiện tại.
Cấu hình cơ bản trong pgbouncer.ini:
[databases]
mydb = host=localhost port=5432 dbname=mydb
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432
auth_type = md5
auth_file = userlist.txt
pool_mode = transaction
max_client_conn = 100
default_pool_size = 20

ProxySQL: MySQL/MariaDB Proxy with Intelligence
ProxySQL là lớp trung gian cao cấp cho MySQL/MariaDB, kết hợp connection pooling, query routing, và firewall rules. Nó hoạt động như một lớp trung gian L7 (application layer), cho phép bạn định nghĩa rules dựa trên username, schema, hoặc even nội dung query.
Ưu điểm chính:
- Query routing: gửi SELECT tới replica, INSERT/UPDATE/DELETE tới primary.
- Query caching: lưu lại result set của SELECT thường dùng (TTL-based).
- Query rewriting: tự động thay đổi query (ví dụ: thêm LIMIT, đổi tên bảng).
- Firewall: chặn các pattern nguy hiểm (DROP TABLE, DELETE không WHERE).
ProxySQL lưu cấu hình trong SQLite database (proxysql.db), cho phép thay đổi trên-the-fly qua ADMIN interface hoặc SQL commands.
Cấu hình cơ bản qua admin interface:
INSERT INTO mysql_users (username,password,default_hostgroup) VALUES ('app_user','secret_pass',10);
INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,comment) VALUES ('db_primary',10,3306,10,'Primary');
INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,comment) VALUES ('db_replica',20,3306,5,'Replica 1');
INSERT INTO mysql_query_rules (rule_id,active,match_pattern,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE',10,0);
LOAD MYSQL USERS TO RUNTIME; LOAD MYSQL SERVERS TO RUNTIME; LOAD MYSQL QUERY RULES TO RUNTIME;
Khi nào nên dùng cái nào?
Bảng sau giúp bạn quyết định:
| Tiêu chí | HikariCP | PgBouncer | ProxySQL |
|---|---|---|---|
| Ngôn ngữ | Java/JVM | PostgreSQL | MySQL/MariaDB |
| Deploy | Embedded trong app | Standalone proxy | Standalone proxy |
| Best for | Spring Boot, Quarkus, Micronaut | PostgreSQL-only workloads | MySQL needing routing/cache |
| Advanced features | Lean locking, bytecode opt | Low memory footprint | Query rewrite, caching, firewall |
| Setup complexity | Low (Spring Boot autoconfigure) | Low (ini file) | Medium (SQLite DB) |
