📃 API Gateway - Data Model¶
1. Giới thiệu¶
Tài liệu này mô tả mô hình dữ liệu của API Gateway, một core service trong hệ sinh thái DX-VAS đóng vai trò như một điểm vào tập trung cho tất cả các frontend apps. Gateway thực hiện proxy định tuyến đến backend service tương ứng, đồng thời enforce RBAC, xác thực JWT, ghi log và thu thập metrics phục vụ observability.
🎯 Mục tiêu của mô hình dữ liệu¶
Khác với các service nghiệp vụ khác, API Gateway không duy trì cơ sở dữ liệu quan hệ phức tạp.
Thay vào đó, kiến trúc của Gateway phụ thuộc gần như hoàn toàn vào các lớp cache thông minh, với thời gian truy xuất siêu nhanh và khả năng invalidate động. Mô hình dữ liệu của Gateway được thiết kế để:
- Định tuyến chính xác request đến backend phù hợp qua
route_config - Thực thi phân quyền tốc độ cao qua
rbacrule được cache - Ngăn chặn token bị thu hồi thông qua
revokedtoken cache - Xác thực JWT hiệu quả bằng cách cache JWKS key từ
token-service - Tự động làm mới thông tin khi có thay đổi cấu hình nhờ vào TTL hoặc Pub/Sub
📦 Phân loại state chính¶
| Loại dữ liệu | Lưu ở đâu? | Mục đích chính |
|---|---|---|
| Route config | Redis (routes:) |
Tra cứu định tuyến → backend tương ứng |
| Permission RBAC | Redis (rbac:) |
Kiểm tra phân quyền theo user_id + tenant_id |
| Token revoked | Redis (revoked:) |
Xác minh token đã bị thu hồi chưa (JTI) |
| JWKS Key | Redis (jwks:) |
Cache public key verify JWT, giảm gọi token-service |
| Processed Events | PostgreSQL | Ghi nhận các event đã xử lý để đảm bảo idempotency |
🔍 Gateway có thể hoạt động gần như toàn bộ trên RAM nếu Redis cache đủ hit-rate, giúp đạt hiệu năng tuyến đầu ~10.000 RPS.
2. Phạm vi Dữ liệu Quản lý (Scope)¶
Dữ liệu mà API Gateway quản lý được chia thành hai loại chính:
- Stateful ngắn hạn (ephemeral cache): lưu trữ trong Redis, chủ yếu phục vụ hiệu năng thời gian thực, có TTL ngắn và có thể tái tạo từ hệ thống gốc (stateless sync).
- Stateful dài hạn (persistence): lưu trữ trong PostgreSQL, chủ yếu phục vụ mục đích đảm bảo tính đúng đắn (idempotency, log) cho các kịch bản async hoặc Pub/Sub.
2.1. 🔁 Redis Cache – phục vụ hiệu năng thời gian thực¶
| Key Pattern | Mục đích | TTL mặc định |
|---|---|---|
routes:{path}:{method} |
Tra cứu định tuyến: route → backend service, timeout, retry | 300 giây |
rbac:{user_id}:{tenant} |
Danh sách permission đã resolved của user trong tenant | 300 giây |
revoked:{jti} |
Kiểm tra token đã bị thu hồi | 180 giây |
jwks:public_key |
Cache public JWKS key từ token-service để xác thực JWT |
600 giây |
- Mọi cache đều có thể bị invalidated bởi TTL, hoặc chủ động qua Pub/Sub (ví dụ:
rbac.updated). - Gateway sẽ fallback tự động nếu cache miss (gọi
user-sub,token-service...).
📌 Một số field được trích xuất từ JWT (như
sub,tenant_id,login_method) sẽ được forward qua header cho các backend service, nhưng không được cache riêng trong Redis tại Gateway.
Chúng là kết quả của quá trình decode JWT (offline introspection) và chỉ được giữ tạm trong memory per-request.
2.2. 🗃️ PostgreSQL – phục vụ tính đúng đắn & log kỹ thuật¶
| Bảng dữ liệu | Mục đích |
|---|---|
route_config |
Quản lý route rule, timeout, retry, RBAC yêu cầu cho mỗi endpoint |
processed_events |
Lưu dấu vết event đã xử lý để chống xử lý lại (idempotency) |
📌 Các cấu trúc dữ liệu trong cache luôn được đồng bộ hoặc tái tạo từ các hệ thống gốc (User Service, Token Service, Config Center…).
Gateway không sở hữu quyền quyết định cuối cùng với dữ liệu nghiệp vụ – nó chỉ là cơ chế điều phối tốc độ cao và đáng tin cậy.
2.3. Bảng Tổng Hợp Redis Cache – Cấu Trúc & Ví Dụ¶
Redis là nơi lưu trữ toàn bộ state ngắn hạn để tăng hiệu năng xử lý tuyến đầu của API Gateway. Dưới đây là mô tả chi tiết từng key pattern, cấu trúc dữ liệu và ví dụ minh họa.
🔑 Key: routes:{path}:{method}¶
Mục đích:
Tra cứu cấu hình định tuyến của route (timeout, retry, backend, permission…)
Cấu trúc JSON:
{
"backend": "user-service.master",
"x-required-permission": "user.read",
"x-condition": {
"user_id": "{{X-User-ID}}"
},
"timeout": 3000,
"retry": 2
}
TTL mặc định: 300 giây
Cơ chế cập nhật: Polling file route_config.json hoặc lắng nghe Pub/Sub route_config.updated
🔑 Key: rbac:{user_id}:{tenant_id}¶
Mục đích:
Lưu danh sách permission của user theo tenant – được resolve từ user-sub.
Cấu trúc JSON:
{
"user_id": "u123",
"tenant_id": "t456",
"permissions": [
"user.read",
"user.update.self",
"report.view_summary"
],
"resolved_at": "2025-06-10T11:33:00Z"
}
TTL mặc định: 300 giây
Cơ chế invalidate: TTL hoặc lắng nghe sự kiện rbac.updated (Pub/Sub)
🔍 Trường
login_methodkhông nằm trong cache RBAC mà được lấy từ JWT payload và forward quaX-Login-Method.
Backend có thể dùng field này để phân nhánh logic, nhưng Gateway không quản lý cache riêng cho nó.
🔑 Key: revoked:{jti}¶
Mục đích:
Kiểm tra xem token đã bị thu hồi chưa. Được set sau khi gọi token/introspect hoặc khi người dùng logout.
Giá trị: "true" hoặc "false"
Ví dụ:
TTL mặc định: 180 giây Cơ chế ghi: Ghi khi revoke hoặc sau khi introspect token
🔑 Key: jwks:public_key¶
Mục đích:
Cache JWKS từ token-service để xác thực chữ ký JWT offline.
Cấu trúc JSON (rút gọn):
{
"keys": [
{
"kty": "RSA",
"kid": "key-001",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
],
"fetched_at": "2025-06-10T11:40:00Z"
}
TTL mặc định: 600 giây
Cơ chế refresh: TTL hết hạn hoặc trigger từ jwt.jwks.rotated
✅ Tất cả các cache Redis đều có thể bị flush thủ công bằng CLI, hoặc tự động hóa bằng cron/task theo config TTL. ✅ Mọi Redis key nên được monitor qua metrics: hit/miss ratio, TTL remaining, size.
3. Ngoài Phạm Vi (Out of Scope)¶
API Gateway không sở hữu dữ liệu nghiệp vụ, không quyết định quyền truy cập cuối cùng, cũng không giữ bất kỳ thông tin người dùng hay session nào.
Dưới đây là các loại dữ liệu hoặc logic không nằm trong phạm vi quản lý của mô hình dữ liệu Gateway:
-
✖️ Dữ liệu người dùng, xác thực danh tính
- Không lưu thông tin user (profile, role, trạng thái...)
- Không xử lý đăng nhập, cấp token, xác thực danh tính (do
auth-servicevàtoken-serviceđảm nhiệm)
-
✖️ Cơ sở dữ liệu nghiệp vụ
- Không lưu danh sách lớp, bài học, báo cáo, hợp đồng, học sinh...
- Gateway chỉ proxy request đến service có DB riêng
-
✖️ Session, trạng thái người dùng
- Gateway không quản lý phiên làm việc (session) hay token store
- Không có bảng lưu session hoặc login state
-
✖️ Event log chi tiết
- Gateway không lưu lại chi tiết log request/response vào DB
- Việc audit log và phân tích hành vi người dùng được chuyển giao cho
audit-logging-service
-
✖️ Logic phân quyền tùy ngữ cảnh nghiệp vụ
- Gateway chỉ enforce permission +
x-conditionđã định nghĩa trongroute_config - Các điều kiện nghiệp vụ nâng cao (ví dụ: “chỉ admin của tổ chức X mới được duyệt báo cáo Y”) sẽ do backend xử lý
- Gateway chỉ enforce permission +
✅ Điều này đảm bảo Gateway giữ được tính chất stateless và hiệu năng cao, không bị lệ thuộc vào state nghiệp vụ hoặc bị phình to không kiểm soát.
4. Mục tiêu của Tài liệu Mô hình Dữ liệu¶
Tài liệu này được biên soạn nhằm mô tả đầy đủ, chính xác và dễ hiểu các cấu trúc dữ liệu được sử dụng bởi API Gateway — bao gồm cả phần được lưu trong Redis (cache ngắn hạn) và PostgreSQL (lưu trữ dài hạn, phục vụ idempotency).
🎯 Mục đích chính¶
- Chuẩn hoá kiến thức kỹ thuật cho toàn bộ đội ngũ (backend, SRE, QA) về cách Gateway sử dụng và tổ chức dữ liệu.
- Định nghĩa rõ cấu trúc các Redis key và TTL tương ứng để phục vụ tuning hiệu năng, observability, và scaling.
- Đảm bảo đồng bộ với thiết kế hệ thống (
design.md,interface-contract.md,openapi.yaml) và các quyết định kiến trúc (ADR-007,ADR-011,ADR-023). - Làm tài liệu tham khảo chính thức cho việc xây dựng các script monitor, alerting, flush CLI, cũng như hướng dẫn SRE khi troubleshooting.
📚 Mục tiêu phụ trợ¶
- Là nền tảng để:
- Viết các test kiểm tra consistency của Redis cache
- Xây dựng dashboard Prometheus về cache hit/miss theo loại key
- Thiết kế hệ thống autoscaling dựa trên số lượng key active
📌 Đây không phải là tài liệu thiết kế schema DB truyền thống, mà là "Sơ đồ bộ nhớ phân tán" của một service tuyến đầu — nơi mà cache chính là trung tâm xử lý tốc độ cao.
5. ERD (Entity Relationship Diagram)¶
erDiagram
ROUTE_CONFIG {
string id PK
string method
string path
string backend_service
string required_permission
int timeout_ms
int retry_count
}
PROCESSED_EVENTS {
UUID event_id PK
TEXT consumer_group_name
TIMESTAMPTZ processed_at
}
📎 Ghi chú
-
ROUTE_CONFIGmô phỏng một bảng cấu hình định tuyến nội bộ. Trên thực tế, cấu hình route được load từ file JSON (route_config.json) hoặc external source (GCS, Firestore…), sau đó được Gateway parse, cache vào Redis (keyroutes:{path}:{method}) và sử dụng tại runtime. -
PROCESSED_EVENTSlà bảng vật lý trong PostgreSQL. Dùng để đảm bảo idempotency khi xử lý các sự kiện từ Pub/Sub, đặc biệt với các action bất đồng bộ (async). Việc lưu lạievent_idtheo từngconsumer_groupgiúp tránh xử lý trùng khi retry. -
Gateway không có bảng dữ liệu nghiệp vụ, cũng không chứa foreign key hoặc relationship phức tạp — mục tiêu là truy cập nhanh, định tuyến đúng, không state dài hạn.
6. Chi tiết Bảng¶
Phần này mô tả chi tiết cấu trúc và mục đích của hai bảng dữ liệu chính mà API Gateway sử dụng trong PostgreSQL: route_config và processed_events.
6.1. 📌 Bảng: route_config¶
📏 Mục đích¶
Lưu trữ cấu hình định tuyến được Gateway tải về từ external config (JSON, GCS, Firestore…).
Phục vụ cho Routing Engine, RBAC Policy, Timeout Handler, và Retry Logic.
🧾 Định nghĩa bảng¶
CREATE TABLE route_config (
id TEXT PRIMARY KEY,
method TEXT NOT NULL,
path TEXT NOT NULL,
backend_service TEXT NOT NULL,
required_permission TEXT,
timeout_ms INTEGER DEFAULT 3000,
retry_count INTEGER DEFAULT 2,
created_at TIMESTAMPTZ DEFAULT now() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT now() NOT NULL
);
CREATE INDEX idx_route_path_method ON route_config(path, method);
🧰 Giải thích cột¶
| Cột | Kiểu DL | Ràng buộc | Mô tả |
|---|---|---|---|
id |
TEXT | PK | Mã định danh duy nhất cho route (có thể dùng hash path+method) |
method |
TEXT | NOT NULL | HTTP method áp dụng: GET, POST, PUT... |
path |
TEXT | NOT NULL | Pattern URL, ví dụ: /users/** hoặc /auth/login |
backend_service |
TEXT | NOT NULL | Tên định danh backend service (theo định danh nội bộ) |
required_permission |
TEXT | optional | Mã permission yêu cầu (áp dụng RBAC) |
timeout_ms |
INTEGER | DEFAULT | Timeout (milliseconds) khi proxy đến backend |
retry_count |
INTEGER | DEFAULT | Số lần retry nếu backend không phản hồi |
created_at |
TIMESTAMPTZ | DEFAULT NOW() | Timestamp tạo bản ghi |
updated_at |
TIMESTAMPTZ | DEFAULT NOW() | Timestamp cập nhật cuối cùng |
6.2. 🔄 Bảng: processed_events¶
📏 Mục đích¶
Ghi nhận các sự kiện Pub/Sub đã được xử lý để đảm bảo idempotency – tránh xử lý lặp trong trường hợp message bị gửi lại (retry).
🧾 Định nghĩa bảng¶
CREATE TABLE processed_events (
event_id UUID PRIMARY KEY,
consumer_group_name TEXT NOT NULL,
processed_at TIMESTAMPTZ DEFAULT now() NOT NULL
);
🧹 Chính sách TTL & Dọn dẹp¶
- Dữ liệu trong bảng
processed_eventsđược lưu tối đa 30 ngày. - Batch job (cron, Airflow, pg_cron...) sẽ xóa các bản ghi quá hạn để giữ bảng nhẹ, truy vấn nhanh.
🧰 Giải thích cột¶
| Cột | Kiểu DL | Ràng buộc | Mô tả |
|---|---|---|---|
event_id |
UUID | PK | Mã duy nhất của sự kiện từ Pub/Sub hoặc queue |
consumer_group_name |
TEXT | NOT NULL | Tên định danh consumer (theo tenant hoặc chức năng) |
processed_at |
TIMESTAMPTZ | DEFAULT NOW() | Thời điểm Gateway đánh dấu sự kiện đã xử lý |
✅ Cả hai bảng đều được thiết kế để phục vụ mục tiêu tốc độ, đơn giản hóa kiểm soát và hỗ trợ các batch job vận hành (xóa TTL, reload config…).
7. Phụ lục¶
Phần phụ lục này tổng hợp lại toàn bộ chiến lược cache, TTL, và liên kết đến các tài liệu kiến trúc có liên quan, giúp đội ngũ phát triển và vận hành dễ dàng tra cứu, đồng bộ và debug hệ thống Gateway.
7.1. 🔄 Chiến lược Cache¶
API Gateway hoạt động theo nguyên tắc cache ưu tiên – fallback khi cần thiết để đảm bảo hiệu năng tuyến đầu. Dưới đây là chiến lược cụ thể cho từng loại dữ liệu:
| Cache Key Pattern | TTL | Nguồn fallback | Cơ chế invalidate |
|---|---|---|---|
routes:{path}:{method} |
300s | File route_config.json / GCS |
Reload định kỳ / PubSub route.updated |
rbac:{uid}:{tid} |
300s | user-sub service |
PubSub rbac.updated |
revoked:{jti} |
180s | token-service/introspect |
Khi logout hoặc introspect fail |
jwks:public_key |
600s | JWKS endpoint từ token-service |
PubSub jwt.jwks.rotated |
7.2. 🧩 Cấu hình Redis đề xuất¶
- Mode: Redis cluster hoặc Sentinel
- Eviction Policy:
volatile-lru(ưu tiên xóa key gần hết TTL) - Monitoring: Prometheus Redis Exporter:
cache_hit_rate,key_expired_total,memory_usage - Alert: TTL xuống thấp bất thường hoặc miss rate > 5%
7.3. 🔗 Tài liệu liên kết¶
| Chủ đề | File |
|---|---|
| Thiết kế tổng thể hệ thống | docs/README.md |
| Thiết kế chi tiết Gateway | docs/services/api-gateway/design.md |
| Giao diện hợp đồng Gateway | docs/services/api-gateway/interface-contract.md |
| Chuẩn hóa lỗi & phản hồi | docs/ADR/adr-011-api-error-format.md, adr-012-response-structure.md |
| Phân quyền động RBAC | docs/architecture/rbac-deep-dive.md |
| Chiến lược JWT & revoked tokens | docs/services/token-service/design.md |
| Quản lý TTL & event cache | docs/ADR/adr-023-schema-migration-strategy.md |
7.4. 📝 Ghi chú mở rộng¶
- Redis cache KHÔNG được xem là nguồn dữ liệu chính. Mọi dữ liệu có thể bị mất cache và sẽ được tự động tái tạo từ hệ thống gốc.
- TTL ngắn + kiểm soát thông minh giúp Gateway cân bằng giữa hiệu năng và tính đúng đắn.
- Mọi access tới Redis nên được wrap qua RedisClient có trace + metric Prometheus.
📌 Tài liệu này sẽ được cập nhật tự động khi có thay đổi từ các ADR hoặc service phụ thuộc.