System Design

Connection pool: 45ms mở kết nối mới vs. 0,2ms mượn lại

Tóm tắt

Mỗi kết nối mới tới database phải qua bắt tay TCP, TLS và xác thực — khoảng 45ms trong video. Connection pool giữ sẵn một nhóm kết nối để mượn lại trong ~0,2ms. Khi lưu lượng vượt số kết nối trong pool, request phải chờ đến lượt.

Xem trên Facebook

Mỗi lần ứng dụng mở một kết nối mới tới database, nó phải bắt tay TCP, thương lượng TLS và xác thực — trong video là khoảng 45ms trước khi chạy được một câu truy vấn. Với một truy vấn chỉ mất 2ms, bạn trả phí kết nối gấp hơn 20 lần thời gian làm việc thật. Connection pool giữ sẵn một nhóm kết nối để mượn lại trong khoảng 0,2ms. Khi lưu lượng vượt số kết nối trong pool, request phải chờ đến lượt.

Ba tình huống

Tình huốngThời gian lấy kết nốiGhi chú
Không có pool~45ms mỗi requestTCP → TLS → AUTH lặp lại mỗi lần
Có pool, tải nhẹ~0,2msMượn lại kết nối có sẵn, không bắt tay lại
Burst 14 request, pool 4 kết nối10ms, 20ms, 30ms…10 request xếp hàng chờ kết nối rảnh

Hết burst, các kết nối rảnh bị đóng theo idle timeout.

Các tham số quan trọng

Tham sốÝ nghĩa
Kích thước tối đaSố kết nối đồng thời tối đa tới database
Kích thước tối thiểuSố kết nối giữ sẵn kể cả khi rảnh
Thời gian chờ lấy kết nốiChờ bao lâu trước khi báo lỗi nếu pool cạn
Idle timeoutSau bao lâu kết nối rảnh bị đóng
Max lifetimeTuổi thọ tối đa của một kết nối để tránh kết nối cũ bị lỗi

Pool to hơn chưa chắc nhanh hơn

Database có giới hạn số kết nối và tài nguyên (CPU, bộ nhớ, khóa). Quá nhiều kết nối hoạt động cùng lúc khiến chúng tranh chấp nhau và làm tất cả chậm đi. Thường pool nhỏ hơn mà đủ dùng cho kết quả tốt hơn. Cách chọn hợp lý là bắt đầu nhỏ, đo, rồi tăng khi có bằng chứng.

Các lỗi thường gặp

  • Rò rỉ kết nối: không trả kết nối về pool sau khi dùng; pool cạn dần và ứng dụng treo.
  • Giữ kết nối quá lâu: mở transaction rồi làm việc khác (gọi API ngoài) trước khi commit.
  • Kết nối chết: sau khi database restart hoặc timeout phía mạng; cần kiểm tra/validate kết nối khi mượn.
  • Mỗi instance một pool: nhiều instance nhân số kết nối và có thể vượt giới hạn database.

Áp dụng thế nào?

  • Luôn dùng pool cho ứng dụng có lưu lượng ổn định (HikariCP cho Java, pgBouncer cho PostgreSQL, pool có sẵn trong hầu hết ORM).
  • Đo “thời gian chờ lấy kết nối” như một chỉ số riêng — nó tăng là dấu hiệu pool quá nhỏ hoặc query giữ kết nối quá lâu.
  • Serverless: mỗi instance có pool riêng dễ làm cạn kết nối DB — dùng proxy như RDS Proxy hoặc pgBouncer.
  • Giữ transaction ngắn để kết nối sớm được trả lại.

Nguồn & tham khảo

  1. About Pool Sizing — HikariCP