Ba mô hình quen thuộc, thường được gọi là silo / bridge / pool.
Database riêng mỗi tenant (silo): cách ly mạnh nhất — sai sót ở tầng ứng dụng không thể làm lộ dữ liệu chéo, khôi phục hay di chuyển riêng một khách rất gọn, và tenant lớn không ảnh hưởng tenant nhỏ. Đổi lại chi phí hạ tầng theo số tenant, migration phải chạy N lần, và không thể query tổng hợp toàn hệ thống bằng một câu SQL.
Schema riêng mỗi tenant (bridge): một database, mỗi tenant một namespace bảng. Cách ly khá tốt, backup theo schema được, nhưng migration vẫn là N lần và hàng nghìn schema làm catalog của PostgreSQL trở nên nặng.
Bảng chung + tenant_id (pool): rẻ và vận hành đơn giản nhất — một schema, một lần migration.
create table invoices (
id bigserial primary key,
tenant_id bigint not null,
...
);
-- tenant_id must be the leading column of every index
create index on invoices (tenant_id, created_at desc);Rủi ro lớn nhất là quên where tenant_id = ? một lần là rò dữ liệu chéo.
Vì vậy đừng phó mặc cho lập trình viên nhớ: bật row-level security để database tự lọc theo biến session, hoặc bắt buộc mọi truy vấn đi qua một lớp repository duy nhất.
alter table invoices enable row level security;
create policy tenant_isolation on invoices
using (tenant_id = current_setting('app.tenant_id')::bigint);Chọn thế nào: đa số SaaS bắt đầu ở mô hình pool vì chi phí thấp và số tenant lớn.
- Khi có khách hàng doanh nghiệp đòi cách ly theo hợp đồng, hoặc một tenant lớn đến mức làm nghẽn tenant khác, thì tách riêng những tenant đó ra silo — mô hình lai này rất phổ biến.
- Ràng buộc pháp lý về nơi lưu trữ dữ liệu cũng có thể ép silo ngay từ đầu.