Skip to content

Multi-tenant ​

Hệ thống SaaS phục vụ nhiều khách hàng (tenant) trên cùng một hạ tầng. Câu hỏi chính: dữ liệu các tenant nằm chung tới mức nào.

Ba mô hình ​

Mô hìnhCách làmƯu điểmNhược điểm
Chung bảngCột tenant_id ở mọi bảngRẻ nhất, dễ vận hành, migration một lầnMột tenant lớn ảnh hưởng tất cả; quên lọc tenant_id là lộ dữ liệu
Schema riêng (PostgreSQL)Mỗi tenant một schema trong cùng databaseTách bạch hơn, backup/khôi phục từng tenantMigration nhân theo số tenant; hàng nghìn schema khó quản lý
Database riêngMỗi tenant một database hoặc cụmCô lập hoàn toàn, tuỳ chỉnh và đặt vùng theo tenantĐắt, vận hành nhân N

Thực tế hay dùng kết hợp: đa số tenant dùng chung bảng, khách rất lớn hoặc có yêu cầu pháp lý được tách database riêng.

Chung bảng: làm cho đúng ​

  • tenant_id ở mọi bảng, kể cả bảng con, để mọi query lọc được mà không phải join.
  • tenant_id đứng đầu khoá chính và mọi index, ví dụ PRIMARY KEY (tenant_id, id). Dữ liệu một tenant nằm gần nhau trong B+Tree, mọi query theo tenant seek gọn, và sau này shard theo tenant dễ dàng (MySQL chương 10).
  • UNIQUE theo nghiệp vụ cũng phải có tenant_id: UNIQUE (tenant_id, email), vì hai tenant khác nhau có thể có cùng email.
  • Chặn quên lọc ở tầng thấp nhất có thể:
    • PostgreSQL có Row-Level Security: CREATE POLICY … USING (tenant_id = current_setting('app.tenant_id')::bigint), database tự lọc.
    • MySQL không có RLS: lọc trong repository/ORM (global scope), kèm test tự động kiểm tra mọi query có điều kiện tenant.
  • Giới hạn tài nguyên theo tenant (rate limit, quota) để một tenant không làm chậm tất cả.

Ghi nhớ

  1. Chung bảng là mặc định; tách database cho khách lớn hoặc có yêu cầu riêng.
  2. tenant_id ở mọi bảng, đứng đầu khoá chính và index, có trong UNIQUE.
  3. Chặn quên lọc bằng RLS (PostgreSQL) hoặc lớp truy cập dữ liệu + test (MySQL).