Bối cảnh & Lý do: Phá vỡ giới hạn hiệu năng của MySQL đơn node
Khi đẩy một cơ sở dữ liệu MySQL nguyên khối (monolithic) vượt ngưỡng 80.000 truy vấn mỗi giây (QPS), việc mở rộng theo chiều dọc (vertical scaling) sẽ chạm trần giới hạn. Trong cụm production của chúng tôi, bảng orders dung lượng 4.2 TB đã làm tê liệt một instance AWS r6i.16xlarge (64 vCPU, 512 GB RAM). Ngay cả khi nâng provisioned IOPS lên đến 40.000, độ dài hàng đợi đĩa (disk queue depth) vẫn tăng vọt trong những đợt traffic đột biến. Độ trễ sao chép ghi (write replication lag) thường xuyên vượt quá 15 giây, gây nguy cơ đọc dữ liệu cũ (stale read) trên các secondary replica.
Sharding ở tầng ứng dụng là giải pháp tình thế thường thấy. Tuy nhiên, việc nhúng logic shard key vào mã nguồn ứng dụng là một cái bẫy bảo trì. Các backend service sẽ nhanh chóng biến thành mớ hỗn độn của connection pool tùy biến, distributed transaction lỏng lẻo và các bảng ánh xạ shard bị gắn cứng (hardcode). Vitess mang đến một cách tiếp cận gọn gàng hơn nhiều.
Ban đầu được phát triển tại YouTube để xử lý hàng chục tỷ lượt xem video mỗi ngày trên hàng nghìn node, Vitess đóng vai trò như một proxy trừu tượng hóa. Các microservice kết nối đến Vitess thông qua driver giao thức MySQL tiêu chuẩn như thể đang kết nối với một database nguyên khối duy nhất. Bên dưới hệ thống, Vitess phân chia trách nhiệm vận hành thành các tầng chuyên biệt:
- VTGate: Các proxy phi trạng thái (stateless) đóng vai trò làm frontend tiếp nhận kết nối. Chúng phân tích cú pháp SQL gửi đến, tra cứu phân vùng đích trong metadata của cụm và định tuyến các truy vấn đồng thời đến đúng shard database tương ứng.
- VTTablet: Một tiến trình sidecar chạy song song cùng mỗi tiến trình
mysqld. Nó quản lý connection pool cục bộ, ngắt các truy vấn treo vượt quá giới hạn thực thi (chẳng hạn như truy vấn giữ lock quá 10 giây) và theo dõi trạng thái replication. - Topology Service: Cụm đồng thuận consensus (thường là etcd hoặc Consul) lưu trữ địa chỉ tablet, phạm vi shard và trạng thái failover.
- VSchema: Cấu hình định tuyến ánh xạ cấu trúc bảng, primary VIndex (khóa hash hoặc lookup) và ranh giới phân vùng.
Cài đặt: Triển khai cụm Vitess trên Kubernetes
PlanetScale Vitess Operator tự động hóa các tác vụ vòng đời của cụm trên Kubernetes, bao gồm tự động failover, sao lưu dự phòng và rolling rollout cấu hình.
Bắt đầu bằng việc thêm Helm repository và triển khai operator controller:
helm repo add vitess https://vitess.io/helm-charts/
helm repo update
kubectl create namespace vitess
helm install vitess-operator vitess/vitess-operator --namespace vitess
Tiếp theo, định nghĩa cấu hình cụm trong file cluster.yaml. Manifest này khởi tạo backend topology etcd, một cell có tên zone1, hai VTGate proxy và một keyspace ban đầu chưa sharded có tên commerce:
apiVersion: planetscale.com/v2
kind: VitessCluster
metadata:
name: production-db
namespace: vitess
spec:
cells:
- name: zone1
gateway:
replicas: 2
resources:
limits:
cpu: "2"
memory: 4Gi
requests:
cpu: "500m"
memory: 1Gi
topology:
etcd:
replicas: 3
keyspaces:
- name: commerce
turndownStrategy: Immediate
partitionings:
- equal:
parts: 1
shardTemplate:
tabletControl:
- tabletType: replica
cells: [zone1]
tablets:
- type: replica
replicas: 2
resources:
limits:
cpu: "4"
memory: 8Gi
Áp dụng manifest và chờ các pod vượt qua bài kiểm tra trạng thái hoạt động (health check):
kubectl apply -f cluster.yaml
kubectl wait --for=condition=Ready vitesscluster/production-db -n vitess --timeout=300s
Cấu hình: Thiết kế VSchema và chia tách Shard
Sau khi cụm đã hoạt động, bước quan trọng tiếp theo là định nghĩa một sharded keyspace và phân vùng các bảng có lưu lượng truy cập cao trên các MySQL instance độc lập.
1. Định nghĩa VSchema
Vitess sử dụng keyspace ID 64-bit để phân phối các hàng dữ liệu trên các tablet vật lý. Lưu cấu hình schema này thành vschema_orders.json. Nó sử dụng VIndex hash tích hợp sẵn để phân bổ đều các bản ghi trên các ranh giới shard dựa trên customer_id:
{
"sharded": true,
"vindexes": {
"hash_index": {
"type": "hash"
}
},
"tables": {
"customers": {
"column_vindexes": [
{
"column": "customer_id",
"name": "hash_index"
}
]
},
"orders": {
"column_vindexes": [
{
"column": "customer_id",
"name": "hash_index"
}
]
}
}
}
Cập nhật VSchema lên keyspace mục tiêu (customer_db) bằng vtctlclient:
vtctlclient --server vtctld.vitess:15999 ApplyVSchema \
--vschema-file vschema_orders.json customer_db
2. Chia tách Keyspace thành các Shard
Vitess biểu diễn khoảng shard bằng các dải giá trị thập lục phân (hexadecimal). Cấu hình 2-shard sẽ chia đôi dải hash từ 00 đến ff của keyspace thành hai nửa: -80 (0x00 đến 0x7f) và 80- (0x80 đến 0xff):
# Khởi tạo các tablet primary và replica cho Shard 1 (-80)
vtctlclient --server vtctld.vitess:15999 CreateShard customer_db/-80
# Khởi tạo các tablet primary và replica cho Shard 2 (80-)
vtctlclient --server vtctld.vitess:15999 CreateShard customer_db/80-
3. Di chuyển bảng và chuyển đổi định tuyến
Quá trình chia tách dữ liệu online được thực hiện qua workflow MoveTables mà không gây gián đoạn hệ thống (zero downtime). VTGate quản lý việc ghi kép (dual-write), đồng bộ dữ liệu lịch sử và đệm các transaction đang xử lý trong quá trình chuyển đổi cuối cùng:
# Bắt đầu sao chép dữ liệu ngầm trực tuyến
vtctlclient --server vtctld.vitess:15999 MoveTables \
--workflow=order_migration customer_db/-80,customer_db/80- Create
# Kiểm tra replication lag giữa shard nguồn và đích
vtctlclient --server vtctld.vitess:15999 MoveTables \
--workflow=order_migration Status
# Chuyển đổi lưu lượng đọc và ghi mà không làm rớt kết nối
vtctlclient --server vtctld.vitess:15999 MoveTables \
--workflow=order_migration SwitchTraffic
Trong đợt migration 120 triệu bản ghi, replication lag luôn được duy trì ổn định dưới 150ms. Bước chuyển đổi ghi cuối cùng chỉ đệm các request từ client trong vòng 85ms trước khi hoàn tất.
Kiểm thử & Giám sát: Đánh giá định tuyến truy vấn và độ ổn định
Sau khi chuyển đổi lưu lượng truy cập, bạn cần kiểm tra lại để đảm bảo VTGate định tuyến truy vấn từ client đến chính xác các shard và hạn chế tối đa chi phí scatter-gather khi có thể.
1. Kiểm thử định tuyến VTGate qua MySQL CLI
VTGate mở port MySQL chuẩn 15306. Kết nối trực tiếp bằng các công cụ client database thông thường:
mysql -h vtgate.vitess.svc.cluster.local -P 15306 -u vtgate_user
Thêm tiền tố EXPLAIN FORMAT = VITESS vào các câu truy vấn SQL mục tiêu để kiểm tra execution plan:
USE customer_db;
-- Định tuyến trực tiếp đến một shard đơn lẻ dựa trên customer_id đã hash
EXPLAIN FORMAT = VITESS
SELECT * FROM orders WHERE customer_id = 1045;
-- Truy vấn scatter-gather trên toàn bộ các shard
EXPLAIN FORMAT = VITESS
SELECT COUNT(*) FROM orders WHERE created_at > '2026-01-01';
Truy vấn đầu tiên tính toán mã băm MD5 của customer_id = 1045. Giá trị hash rơi vào dải -80, nên VTGate định tuyến trực tiếp câu truy vấn đến tablet customer_db/-80 với độ trễ dưới 3ms. Truy vấn thứ hai không có shard key, buộc VTGate phải phát tán (broadcast) câu lệnh tới tất cả các shard, thu thập kết quả từng phần rồi tổng hợp lại, làm tăng thêm một chút chi phí độ trễ (khoảng 11ms).
2. Các chỉ số Prometheus cốt lõi cho Vitess
Tất cả các tiến trình Vitess đều xuất metric cho Prometheus trên port 15000. Hãy theo dõi chặt chẽ bốn chỉ số production quan trọng sau:
vtgate_queries_total{keyspace="customer_db"}: Theo dõi tốc độ truy vấn theo keyspace và loại plan. Các cảnh báo tăng vọt ở đây giúp phát hiện các đợt bùng phát truy vấn scatter-gather ngoài dự kiến.vttablet_query_latency_seconds_bucket: Giám sát thời gian thực thi trên từng node shard riêng lẻ. Nên thiết lập cảnh báo P99 nếu độ trễ vượt quá 25ms.vttablet_pool_wait_count: Báo hiệu tình trạng bão hòa kết nối. Tỉ lệ lớn hơn 5 lượt chờ/giây đồng nghĩa với việc cần mở rộng connection pool của VTTablet.vitess_replication_lag_seconds: Đo lường độ trễ của read replica. Giữ ngưỡng cảnh báo ở mức 5 giây để tránh tình trạng đọc dữ liệu cũ trên các read-only replica.
Sự kết hợp giữa cơ chế định tuyến proxy của VTGate và tự động hóa của Kubernetes giúp loại bỏ hoàn toàn nút thắt cổ chai đơn node. Cụm MySQL của bạn sẽ đạt khả năng mở rộng ghi tuyến tính và dễ dàng xử lý mượt mà hơn 200.000 QPS mà không làm phức tạp hóa tầng ứng dụng.

