Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Scale database: chứng minh nút thắt trước khi thêm thành phần

Câu hỏi: query, connection, replica, partition hay shard giải quyết đúng phần nào đang nghẽn?

Cần biết trước: EXPLAIN, composite index, replication lag và quan sát database. Bài là khung ra quyết định cho PostgreSQL 18; phần pooling đối chiếu tài liệu PgBouncer hiện tại ngày 2026-10-03 (website hiển thị 1.26.0). Chưa chạy benchmark PgBouncer, sharding hoặc failover. Ba profile dưới là tình huống giả định, không phải số đo production.

Đặt ngân sách trước giải pháp

Ghi request cần phục vụ, p95/p99 và deadline, tỷ lệ lỗi chấp nhận, ngân sách đọc stale, cửa sổ đo, workload và mức tăng tải. Phân rã latency thành chờ pool, thực thi/lock DB, và xử lý ứng dụng/mạng; không cộng percentile riêng thành p99 tổng. Đo trong cùng cửa sổ: throughput hoàn tất, queue depth/age, số connection active/idle, wait event, CPU/I/O, plan/buffers và WAL/replica. Khi metric mất, sửa đường quan sát trước; up=0 không chứng minh DB đang chậm hay khỏe.

Không dùng CCU để chọn số connection hoặc shard. Người đang online có thể không gửi request; một request có thể gọi nhiều SQL hoặc giữ transaction lâu. Ví dụ giả định, hệ thống ổn định hoàn tất 100 DB transaction/s, mỗi transaction giữ connection trung bình 0,02s: occupancy trung bình khoảng 2 connection. Đây chỉ là phép tính trung bình với cùng boundary và steady state, không phải cấu hình pool=2; burst, tail, transaction chờ khóa và deadline cần phép thử riêng. Queue không ổn định thì phép suy này không đủ.

Ba profile và phép thử tiếp theo

Profile giả địnhTín hiệu cần xác nhậnƯu tiên thửDấu hiệu đã chọn sai
Đọc nhiềuMột nhóm query đọc chiếm thời gian/buffers, latency DB cao dù pool ít chờSửa query/index và lượng dữ liệu trả; sau đó route phần đọc chấp nhận stale sang replicaQuery vẫn quét quá nhiều, hoặc replica replay không theo kịp; thêm node chỉ nhân công việc
Ghi nhiềuWAL/I/O/lock hoặc index maintenance chiếm chi phí, không chỉ tổng R/W ratioGiữ transaction ngắn, cùng thứ tự khóa, batch đúng atomicity; đo index/durability trước partition/shardCùng hot key vẫn tranh khóa, hoặc commit chậm ở primary; replica không chia tải ghi này
Quá nhiều connectionNhiều connection idle/churn, pool wait và số backend/CPU tăng cùng burstBound/reuse pool, admission/deadline; kiểm session contract trước chọn pool modeSQL/lock vẫn chậm, active backend vẫn nghẽn; tăng max connection chỉ tăng cạnh tranh

Một hệ thống có thể gặp cả ba. Ưu tiên phần đang làm vỡ ngân sách của request quan trọng; không có thứ tự bắt buộc “query→pool→replica” cho mọi hệ thống. Đổi một nhóm biến, giữ workload và durability/consistency cần thiết, chạy lại và đối chiếu lỗi lẫn latency.

Pooling giữ connection, không sửa SQL

Pool ứng dụng tái dùng connection và giới hạn số request vào DB. Pool ở ngoài như PgBouncer thêm một hàng đợi và điểm vận hành riêng; đo thời gian chờ ở từng pool để tránh che queue này bằng queue khác. max_client_conn là client; default_pool_size là số server connection tối đa cho mỗi cặp user/database, còn giới hạn DB/user khác cũng ảnh hưởng tổng backend. Không đặt một số nhỏ cho một pool rồi coi đó là trần mọi connection. Pool configuration.

Session mode giữ server connection đến khi client ngắt; transaction mode trả về sau transaction. Statement mode cấm transaction nhiều statement, nên không dùng cho BEGIN→ghi request ID→hai UPDATE→COMMIT của lab deadlock. Session state, LISTEN, temp table và prepared statement cần đối chiếu driver/protocol/config; hỗ trợ protocol-level prepared plan không đồng nghĩa SQL PREPARE dùng được ở transaction mode. Không dựa vào một generic “pool reset” để chứng minh tenant state được xóa. Feature map.

Nếu CPU thấp mà request chờ row lock, thêm backend không nhả khóa. Nếu app giữ connection trong lúc gọi API chậm, trước tiên giảm phạm vi giữ transaction/connection. Giới hạn queue và deadline theo caller; overload có kết quả quan sát được thay vì cho mọi request treo vô hạn.

Replica và partition có ranh giới khác nhau

Read replica có thể nhận những query đọc mà hợp đồng cho phép dữ liệu cũ. Đọc-sau-ghi cần route primary hoặc barrier/timeout đã kiểm; synchronous commit cũng phụ thuộc ack mode và replica được chọn, không bảo đảm mọi SELECT trên mọi replica luôn mới. Replica thêm chi phí apply WAL, vận hành và failover; không tự là backup/restore. Standby behavior.

Partition chia một bảng theo key/range và có thể pruning khi query phù hợp; không tự thêm máy hoặc chia tải ghi primary. Nó hữu ích cho pruning/retention/lifecycle khi predicate và partition key khớp. Query không pruning, quá nhiều partition hoặc hot partition vẫn có thể chậm. Constraint unique/PRIMARY của bảng partitioned PostgreSQL phải bao gồm mọi cột partition key; không bỏ constraint toàn cục cho tiện thiết kế. Đánh giá lock và vận hành attach/detach theo version. Partitioning limitations.

Giá phải trả và phép kiểm bác bỏ

Lựa chọnVận hành thêmConsistency/failure cần giữBằng chứng khiến dừng hoặc đổi hướng
Query/indexStatistics, index build/maintenance và theo dõi planKết quả query/constraint không đổi; index thêm chi phí ghiPlan/buffers không giảm ở workload mục tiêu, write budget xấu đi
Bounded poolQueue, timeout, reset/session và tổng backendKhông trả connection đang transaction lỗi; tenant state đúngQueue age vượt deadline dù DB chưa bận: kiểm hold time/lỗi lease
ReplicaRouting, WAL retention/apply, health, failover rehearsalStale read/read-after-write/RPO theo hợp đồngApply tụt xa hoặc query yêu cầu dữ liệu mới; route đó trở lại primary
PartitionKey/range, retention, pruning, DDL/constraintUnique/FK/query semantics được giữQuery không pruning hoặc hot partition vẫn chiếm tải
ShardingRouter/key, rebalancing, backup/restore nhiều shard, migrationCross-shard transaction/JOIN, hotspot, partial failureHot key tập trung một shard hoặc business transaction phải đi qua nhiều shard

Chỉ xét sharding khi đã chứng minh giới hạn của một node phù hợp workload, và có key phân bố được công việc/dữ liệu. Không chỉ đợi hết ổ đĩa, cũng không chia shard vì bảng “nhiều hàng”. Liệt kê các query/transaction bắt buộc cross-shard, kế hoạch đổi key và cách thử recovery trước khi chốt. Tách OLTP/analytics cũng cần freshness và quyền truy cập ở nơi nhận, không chỉ thêm pipeline.

Dùng bằng chứng có sẵn đúng phạm vi

  • Bulk import đo cùng CSV/constraint/transaction trên local PG18.6: đây là cách kiểm batch/COPY, không dự báo write capacity production hay 10M hàng.
  • Replication lab chứng minh pause/replay barrier và stale read, chưa chứng nhận RPO hoặc failover tự động.
  • Observability lab đối chiếu metric/query và phát hiện exporter mất; chưa đo overhead production hoặc chọn ngưỡng SLO.
  • VACUUM giữ cơ chế snapshot và reclaim; không tắt autovacuum như bước scale mặc định. Deadlock giữ order/retry semantics.

Record quyết định gồm vấn đề/ngân sách, baseline, phương án nhỏ nhất sẽ thử, điều kiện bác bỏ, kết quả cùng môi trường và rủi ro chưa kiểm. Chỉ thêm thành phần khi evidence cho thấy nó phục vụ một yêu cầu cụ thể; lưu lý do bằng ADR.