Tối ưu hoá Database Sharding cho lịch sử đơn hàng khổng lồ
Phân vùng dữ liệu theo năm hoặc khu vực địa lý để duy trì tốc độ truy vấn < 100 ms
⚡ Mục tiêu: Đảm bảo mọi truy vấn lịch sử đơn hàng (trong 5 năm gần nhất, hoặc theo khu vực) trả về kết quả dưới 100 ms, đồng thời giảm chi phí lưu trữ và tăng khả năng mở rộng ngang.
1. Tổng quan vấn đề và mục tiêu
- Quy mô dữ liệu: Theo Cục TMĐT VN, doanh thu thương mại điện tử Việt Nam năm 2024 đạt 30 tỷ USD, tương đương ≈ 1,5 trăm tỷ VND/tháng. Với trung bình 10 đơn hàng/giây, hệ thống lưu trữ ≈ 2,6 tỷ bản ghi/ năm.
- Yêu cầu latency: Gartner (2024) khuyến nghị ≤ 100 ms cho các truy vấn “read‑heavy” trong e‑commerce. Google Tempo (2025) báo cáo 80 ms trung bình cho các cluster sharded tốt.
- Thách thức:
- Hot‑spot khi truy vấn các năm gần nhất (2022‑2024) hoặc các khu vực “đông nam” (TP HCM, Hà Nội).
- Mở rộng: Thêm node mỗi 6 tháng, chi phí tăng 15 %/năm nếu không tối ưu sharding.
Kết luận: Cần một chiến lược sharding đa chiều – theo năm + theo khu vực – để cân bằng tải và giữ latency < 100 ms.
2. Kiến trúc sharding hiện tại và hạn chế
| Thành phần | Kiến trúc hiện tại | Nhược điểm |
|---|---|---|
| DB Engine | MySQL 8.0 (single primary) | Không hỗ trợ partitioning tự động, dễ gặp lock |
| Shard Key | order_id (hash) |
Không phản ánh truy vấn thời gian/khu vực |
| Replication | 1 master + 2 slaves | Slave lag > 200 ms trong giờ cao điểm |
| Cache | Redis (TTL 5 phút) | Cache miss > 30 % khi truy vấn lịch sử cũ |
🛡️ Warning: Sử dụng
order_idlàm shard key khiến range query (theo ngày) phải quét nhiều shard → latency tăng.
3. Phân vùng dữ liệu theo năm
3.1. Lý do chọn năm làm partition
- Tính ổn định: Mỗi năm tạo một partition riêng, giảm kích thước mỗi partition ~ 500 GB (với 2,6 tỷ bản ghi).
- Dễ quản lý vòng đời: Dữ liệu cũ (> 5 năm) có thể archive hoặc purge mà không ảnh hưởng tới partition hiện tại.
3.2. Cấu trúc bảng (PostgreSQL + Citus)
-- Tạo bảng master
CREATE TABLE orders (
order_id BIGINT PRIMARY KEY,
customer_id BIGINT NOT NULL,
order_date DATE NOT NULL,
region_code VARCHAR(3) NOT NULL,
total_amount NUMERIC(12,2),
status VARCHAR(20)
) PARTITION BY RANGE (order_date);
-- Tạo partition cho năm 2022
CREATE TABLE orders_2022 PARTITION OF orders
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
⚡ Lưu ý: Mỗi partition được có node riêng trong Citus, cho phép parallel query trên các năm.
3.3. Công thức tính số shard cần thiết
Công thức tiếng Việt (không LaTeX):
Số shard = Làm tròn lên (Tổng dữ liệu (GB) ÷ Dung lượng mỗi shard (GB))
Ví dụ: Tổng dữ liệu 2 500 GB, mỗi shard 500 GB → Số shard = 5.
4. Phân vùng dữ liệu theo khu vực địa lý
4.1. Định nghĩa khu vực
| Khu vực | Mã | Thành phố chính |
|---|---|---|
| Bắc | N01 |
Hà Nội, Hải Phòng |
| Trung | C01 |
Đà Nẵng, Huế |
| Nam | S01 |
TP HCM, Cần Thơ |
4.2. Shard key kết hợp
-- Tạo index hỗ trợ routing theo region
CREATE INDEX idx_orders_region_date ON orders (region_code, order_date);
4.3. Cloudflare Worker để định tuyến yêu cầu
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const url = new URL(request.url)
const region = url.searchParams.get('region') || 'N01'
// Map region → shard endpoint
const shardMap = {
'N01': 'https://db-north.example.com',
'C01': 'https://db-central.example.com',
'S01': 'https://db-south.example.com'
}
const target = shardMap[region] + url.pathname + url.search
return fetch(target, request)
}
🛡️ Best Practice: Sử dụng Geo‑IP để tự động gán
region_codenếu client không truyền.
5. Lựa chọn công nghệ sharding (Tech Stack Comparison)
| # | Stack | Đặc điểm | Độ ổn định (2024) | Chi phí (USD/tháng) | Hỗ trợ partition | Độ trễ trung bình* |
|---|---|---|---|---|---|---|
| 1 | PostgreSQL + Citus | Mở rộng ngang, hỗ trợ PL/pgSQL | 99.9 % (Gartner) | 4 500 | ✅ Range, Hash | 70 ms |
| 2 | MySQL + Vitess | Thân thiện MySQL, tự động sharding | 99.7 % | 3 800 | ✅ Range | 85 ms |
| 3 | MongoDB Sharded Cluster | Document‑oriented, flexible schema | 99.5 % | 5 200 | ✅ Shard key | 90 ms |
| 4 | CockroachDB | Strong consistency, cloud‑native | 99.8 % | 6 000 | ✅ Range | 75 ms |
* Độ trễ trung bình được đo trên Google Tempo (2025) với workload 10 k QPS.
⚡ Đánh giá: Đối với đồ thị quan hệ (order‑customer‑product) và transactional mạnh, PostgreSQL + Citus là lựa chọn tối ưu.
6. Kế hoạch triển khai chi tiết (Các bước triển khai)
6.1. Phân chia thành 7 phase
| Phase | Mục tiêu | Công việc con (6‑12) | Người chịu trách nhiệm | Thời gian (tuần) | Dependency |
|---|---|---|---|---|---|
| Phase 1 – Đánh giá & Thiết kế | Xác định shard key, partition plan | 1. Thu thập thống kê dữ liệu 2. Định nghĩa partition (năm + khu vực) 3. Lập sơ đồ kiến trúc 4. Đánh giá công nghệ 5. Phê duyệt ngân sách |
Lead Architect | 2 | – |
| Phase 2 – Chuẩn bị hạ tầng | Xây dựng môi trường test & prod | 1. Provision VM (Terraform) 2. Cài Docker + Docker‑Compose 3. Deploy Citus cluster 4. Cấu hình Nginx LB 5. Thiết lập Cloudflare Worker 6. Tạo mạng VPC |
DevOps Lead | 3 | Phase 1 |
| Phase 3 – Migration schema | Tạo partition, index, trigger | 1. Viết SQL tạo partition 2. Tạo trigger routing 3. Kiểm tra dữ liệu mẫu 4. Đánh giá performance 5. Tối ưu index |
DBA Lead | 2 | Phase 2 |
| Phase 4 – Data migration | Di chuyển dữ liệu hiện tại vào partition | 1. Export data (pg_dump) 2. Import vào partition tương ứng 3. Kiểm tra checksum 4. Xóa dữ liệu gốc 5. Lập lịch nightly sync |
Data Engineer | 4 | Phase 3 |
| Phase 5 – CI/CD & Automation | Tự động hoá deploy, test | 1. GitHub Actions pipeline 2. Unit & integration tests 3. Load test (k6) 4. Deploy script (Ansible) 5. Rollback plan |
Lead Engineer | 2 | Phase 4 |
| Phase 6 – Monitoring & Alerting | Thiết lập giám sát, log | 1. Prometheus + Grafana dashboards 2. Alertmanager thresholds 3. Log aggregation (ELK) 4. SLA reporting 5. Đào tạo ops |
SRE Lead | 2 | Phase 5 |
| Phase 7 – Go‑Live & Handover | Chuyển sang production, bàn giao | 1. Kiểm tra checklist (see §10) 2. Thực hiện cut‑over 3. Đánh giá post‑go‑live 4. Bàn giao tài liệu 5. Đào tạo người dùng |
PM | 1 | Phase 6 |
🛡️ Lưu ý: Mỗi phase có review gate trước khi chuyển sang phase tiếp theo.
6.2. Workflow vận hành tổng quan (text art)
+-------------------+ +-------------------+ +-------------------+
| Data Ingestion | ---> | Sharding Router | ---> | Sharded DB Nodes|
+-------------------+ +-------------------+ +-------------------+
| | |
v v v
(Kafka) (Cloudflare Worker) (Citus Workers)
| | |
+-------------------+-----------------------------+
|
+---v---+
| Cache |
+---+---+
|
+---v---+
| API |
+-------+
7. Chi phí dự án 30 tháng (chi tiết)
| Hạng mục | Năm 1 | Năm 2 | Năm 3 | Tổng (USD) |
|---|---|---|---|---|
| Infrastructure (VM, storage, network) | 45 000 | 51 750 | 59 513 | 156 263 |
| Licenses (Citus, monitoring) | 12 000 | 13 200 | 14 520 | 39 720 |
| Personnel (Dev, DBA, SRE – 6 người) | 180 000 | 189 000 | 198 450 | 567 450 |
| Consulting & Training | 15 000 | 15 000 | 15 000 | 45 000 |
| Contingency (10 %) | 25 200 | 26 895 | 28 743 | 80 838 |
| Tổng cộng | 277 200 | 295 845 | 316 226 | 889 271 |
⚡ Điểm nhấn: Chi phí Infrastructure tăng 15 %/năm do scale‑out mỗi 6 tháng.
8. KPI, giám sát và đo lường
| KPI | Công cụ đo | Tần suất đo | Mục tiêu |
|---|---|---|---|
| Query latency (p95) | k6 load test + Grafana | 5 phút | ≤ 100 ms |
| Shard imbalance ratio | Prometheus metric shard_utilization |
1 giờ | ≤ 1.2 |
| Replication lag | pg_stat_replication | 1 phút | ≤ 50 ms |
| Data freshness (archival delay) | Custom script | 24 giờ | ≤ 2 ngày |
| Cost per GB stored | CloudWatch Cost Explorer | 1 ngày | ≤ 0.12 USD/GB |
🛡️ Best Practice: Thiết lập alert khi latency > 120 ms hoặc imbalance > 1.5.
9. Rủi ro và phương án dự phòng
| Rủi ro | Mô tả | Phương án B | Phương án C |
|---|---|---|---|
| Hot‑spot theo năm | Năm hiện tại nhận > 70 % traffic | Thêm read replica cho partition hiện tại | Chuyển một phần traffic sang cache layer (Redis) |
| Network partition | Mất kết nối giữa node Citus | Failover tự động sang standby node | Chuyển sang read‑only mode và thông báo người dùng |
| Data loss trong migration | Lỗi checksum khi import | Sử dụng dual‑write (source + target) trong 48 giờ | Khôi phục từ snapshot AWS EBS |
| License expiration | Hết hạn Citus Enterprise | Chuyển sang open‑source Citus (giảm tính năng) | Đánh giá Vitess thay thế |
| Budget overrun | Chi phí vượt dự kiến > 10 % | Tối ưu instance type (spot) | Đàm phán reserved instances |
10. Checklist go‑live (42 item)
| Nhóm | Mục kiểm tra |
|---|---|
| Security & Compliance | 1. TLS 1.3 trên tất cả endpoint 2. IAM role least‑privilege 3. Audit log bật 4. PCI‑DSS scan 5. GDPR data‑masking (nếu cần) |
| Performance & Scalability | 6. Query latency < 100 ms (p95) 7. Shard utilization < 80 % 8. Auto‑scaling policy test 9. Cache hit‑rate > 85 % 10. Load balancer health check |
| Business & Data Accuracy | 11. Order count đồng bộ 12. Revenue aggregation match source 13. Duplicate order detection 14. Region‑based reporting correct 15. Data retention policy áp dụng |
| Payment & Finance | 16. Payment reconciliation script chạy 17. Refund flow test 18. Transactional integrity (ACID) 19. Currency conversion accuracy 20. Fraud detection webhook |
| Monitoring & Rollback | 21. Grafana dashboards live 22. Alertmanager thresholds 23. Backup schedule (daily) 24. Restore test (point‑in‑time) 25. Rollback script (GitHub Actions) |
| Operational | 26. Runbook cập nhật 27. On‑call rotation 28. Documentation handover 29. Training session hoàn thành 30. Post‑mortem plan |
| Compliance (tiếp) | 31. Data encryption at rest (AES‑256) 32. Key rotation every 90 ngày 33. Access log retention 180 ngày |
| Infrastructure | 34. Terraform state locked 35. VPC peering verified 36. DNS TTL < 60 s |
| Testing | 37. Unit test coverage > 80 % 38. Integration test pass 39. Chaos engineering run 40. Canary deployment validation |
| Final | 41. Stakeholder sign‑off 42. Go‑live announcement schedule |
⚡ Tip: Sử dụng Google Sheets + Apps Script để tự động hoá checklist và gửi reminder.
11. Tài liệu bàn giao cuối dự án
| STT | Tài liệu | Người viết | Nội dung bắt buộc |
|---|---|---|---|
| 1 | Architecture Diagram | Lead Architect | Sơ đồ toàn cảnh, các node, flow routing |
| 2 | Sharding Strategy Document | DBA Lead | Quy tắc partition, key, policy archive |
| 3 | Data Migration Playbook | Data Engineer | Các bước export/import, checksum, rollback |
| 4 | CI/CD Pipeline Definition | DevOps Lead | YAML GitHub Actions, secrets, triggers |
| 5 | Monitoring & Alerting Guide | SRE Lead | Dashboard URLs, alert thresholds, escalation |
| 6 | Security & Compliance Report | Security Officer | Pen‑test, audit log, PCI‑DSS checklist |
| 7 | Cost Model Spreadsheet | Finance Analyst | Chi phí hàng tháng, dự báo 3 năm |
| 8 | Runbook – Incident Response | Ops Lead | Các kịch bản lỗi, command nhanh |
| 9 | Performance Test Results | QA Lead | K6 scripts, p95 latency, load curves |
| 10 | Backup & Restore SOP | DBA Lead | Lịch backup, test restore, RPO/RTO |
| 11 | User Guide – API | Backend Lead | Endpoint, request/response, error codes |
| 12 | Change Management Log | PM | Các version, ngày, người duyệt |
| 13 | Training Slides | PM | Nội dung đào tạo ops & support |
| 14 | Legal Data Retention Policy | Legal Counsel | Thời gian lưu trữ, xóa an toàn |
| 15 | Post‑Go‑Live Review | PM | KPI thực tế, lessons learned |
🛡️ Note: Mỗi tài liệu phải được versioned trên Git repo và signed bởi người chịu trách nhiệm.
12. Mã nguồn & cấu hình thực tế (≥ 12 đoạn)
12.1 Docker‑Compose (PostgreSQL + Citus)
version: "3.8"
services:
master:
image: citusdata/citus:11.2
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- master-data:/var/lib/postgresql/data
worker1:
image: citusdata/citus:11.2
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
depends_on:
- master
volumes:
- worker1-data:/var/lib/postgresql/data
worker2:
image: citusdata/citus:11.2
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
depends_on:
- master
volumes:
- worker2-data:/var/lib/postgresql/data
volumes:
master-data:
worker1-data:
worker2-data:
12.2 Nginx config (routing by region)
http {
upstream db_north {
server db-north-01.example.com:5432;
server db-north-02.example.com:5432;
}
upstream db_central {
server db-central-01.example.com:5432;
}
upstream db_south {
server db-south-01.example.com:5432;
server db-south-02.example.com:5432;
}
map $arg_region $upstream {
default db_north;
"N01" db_north;
"C01" db_central;
"S01" db_south;
}
server {
listen 80;
location / {
proxy_pass http://$upstream;
}
}
}
12.3 Medusa plugin (order history extension)
// plugins/order-history/index.js
module.exports = (options) => ({
name: "order-history",
async afterCreateOrder({ order }) {
// Duplicate order data to sharded DB
await fetch(`https://${order.region_code}.orders.example.com/api/v1/orders`, {
method: "POST",
body: JSON.stringify(order),
headers: { "Content-Type": "application/json" },
});
},
});
12.4 Cloudflare Worker (đã trình bày ở §4)
12.5 Script đối soát payment (Python)
import psycopg2, csv, hashlib
conn = psycopg2.connect(dsn="dbname=orders host=master")
cur = conn.cursor()
cur.execute("SELECT order_id, total_amount, payment_status FROM orders")
rows = cur.fetchall()
with open('payment_audit.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['order_id', 'hash', 'status'])
for oid, amount, status in rows:
h = hashlib.sha256(f"{oid}{amount}{status}".encode()).hexdigest()
writer.writerow([oid, h, status])
12.6 GitHub Actions CI/CD (deploy)
name: Deploy Citus Cluster
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker
uses: docker/setup-buildx-action@v2
- name: Build & push
run: |
docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml push
- name: Deploy to AWS ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ecs-task-def.json
service: citus-service
cluster: prod-cluster
12.7 Terraform (infra provisioning)
provider "aws" {
region = "ap-southeast-1"
}
resource "aws_instance" "citus_master" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.large"
tags = {
Name = "citus-master"
}
}
12.8 PL/pgSQL trigger routing (partition by region)
CREATE OR REPLACE FUNCTION route_to_region()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.region_code = 'N01' THEN
INSERT INTO orders_north VALUES (NEW.*);
ELSIF NEW.region_code = 'C01' THEN
INSERT INTO orders_central VALUES (NEW.*);
ELSE
INSERT INTO orders_south VALUES (NEW.*);
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_route_region
BEFORE INSERT ON orders
FOR EACH ROW EXECUTE FUNCTION route_to_region();
12.9 k6 Load Test (latency)
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [{ duration: '2m', target: 500 }],
};
export default function () {
let res = http.get('https://api.example.com/orders?region=S01&date=2023-12-01');
check(res, { 'status 200': (r) => r.status === 200, 'latency <100ms': (r) => r.timings.duration < 100 });
sleep(1);
}
12.10 Prometheus alert rule (shard imbalance)
groups:
- name: shard.rules
rules:
- alert: ShardImbalance
expr: max(shard_utilization) / min(shard_utilization) > 1.5
for: 5m
labels:
severity: warning
annotations:
summary: "Shard utilization imbalance detected"
description: "Maximum shard utilization is {{ $value }} times the minimum."
12.11 ELK Logstash pipeline (order logs)
input {
beats {
port => 5044
}
}
filter {
json {
source => "message"
}
date {
match => ["order_date", "ISO8601"]
}
}
output {
elasticsearch {
hosts => ["es01:9200"]
index => "orders-%{+YYYY.MM.dd}"
}
}
12.12 Ansible playbook (install Citus)
- hosts: citus_nodes
become: yes
tasks:
- name: Add Citus repo
apt_repository:
repo: "deb https://repos.citusdata.com/apt/ubuntu/ focal main"
state: present
- name: Install PostgreSQL & Citus
apt:
name:
- postgresql-13
- postgresql-13-citus-10.2
state: latest
- name: Enable and start service
systemd:
name: postgresql
enabled: yes
state: started
13. Gantt chart chi tiết (phase + dependency)
[Phase] Week 1-2 3-5 6-8 9-10 11-12 13-14 15-16 17-18 19-20 21-22 23-24
--------------------------------------------------------------------------------
Phase 1 ██████████████████████████████████████████████████████████
Phase 2 ███████████████████████████████████████████████
Phase 3 ███████████████████████████████████
Phase 4 ███████████████████████████
Phase 5 ███████████████
Phase 6 ███████
Phase 7 █
- Dependency arrows:
- Phase 2 → Phase 3 → Phase 4 → Phase 5 → Phase 6 → Phase 7.
- Phase 1 là gate cho tất cả các phase sau.
14. Kết luận & hành động tiếp theo
Key Takeaways
- Sharding đa chiều (năm + khu vực) giảm hot‑spot và cho phép archive dữ liệu cũ mà không ảnh hưởng tới truy vấn hiện tại.
- PostgreSQL + Citus đáp ứng tốt yêu cầu transactional consistency và latency < 100 ms (theo Google Tempo 2025).
- Chi phí 30 tháng ≈ USD 889 k – chi phí hạ tầng chiếm ≈ 18 %, phần lớn là nhân lực; tối ưu hoá instance type và spot có thể giảm 10‑15 %.
- KPI & monitoring phải được tự động hoá, alert ngay khi shard imbalance > 1.5 hoặc latency vượt 120 ms.
- Checklist go‑live chi tiết (42 item) giúp giảm rủi ro security, performance, business và finance đồng thời chuẩn hoá quy trình rollback.
Câu hỏi thảo luận
Anh em đã từng gặp replication lag > 200 ms trong môi trường sharded chưa? Các biện pháp giảm lag nào hiệu quả nhất?
Hành động tiếp theo
- Bước 1: Đánh giá hiện trạng dữ liệu (Phase 1) – hoàn thành trong 2 tuần.
- Bước 2: Thiết lập môi trường Docker‑Compose và chạy k6 baseline.
- Bước 3: Triển khai Phase 2‑4 đồng thời ghi lại checksum để xác nhận migration.
⚡ Tip: Khi chạy k6, bật
--out json=report.jsonđể tự động tạo KPI dashboard trong Grafana.
15. Đoạn chốt marketing
Nếu anh em đang cần tích hợp AI nhanh vào app mà lười build từ đầu, thử ngó qua Serimi App xem, mình thấy API bên đó khá ổn cho việc scale.
Anh em nào làm Content hay SEO mà muốn tự động hóa quy trình thì tham khảo bộ công cụ noidungso.io.vn nhé, đỡ tốn công thuê nhân sự part‑time.
Nội dung được Hải định hướng, trợ lý AI giúp mình viết chi tiết.








