Vấn đề: Ghép dữ liệu khi tách database
Khi tách nhỏ hệ thống sang Microservices, bài toán chia tách database thường kéo theo một phiền toái lớn: làm sao lấy thông tin user để hiển thị kèm đơn hàng khi users và orders nằm ở hai server vật lý khác nhau?
Nhiều team chọn giải pháp nhanh: query lấy danh sách user_id từ DB Order, nhồi vào mảng rồi bắn tiếp WHERE user_id IN (...) sang DB User. Với vài chục record, cách này chạy ổn. Nhưng khi danh sách chạm mốc 20.000 ID, backend ngốn sạch RAM, payload phình to và network latency tăng vọt từ 15ms lên hơn 1.200ms.
Ba hướng kết nối dữ liệu liên server phổ biến
Tùy theo bài toán, bạn có ba lựa chọn chính để xử lý liên kết dữ liệu:
- Join ở tầng ứng dụng (Application-level Join): Backend mở connection pool tới cả hai DB, kéo dữ liệu về bộ nhớ rồi map thủ công bằng code.
- Đồng bộ qua CDC / ETL: Dùng Debezium, Kafka hoặc MySQL Replication đẩy dữ liệu từ bảng nguồn sang server đích.
- Dùng FEDERATED Storage Engine: Tạo một bảng đại diện (proxy table) ngay trên Local Server, trỏ thẳng tới bảng thật ở Remote Server. Bản thân MySQL Local sẽ tự đóng vai trò client để gửi query qua mạng.
So sánh chi phí kỹ thuật giữa các giải pháp
Không có giải pháp vạn năng. Mỗi hướng đi đều buộc bạn phải đánh đổi:
1. Application-level Join
- Ưu điểm: Triển khai nhanh. Hoàn toàn không can thiệp cấu hình database.
- Nhược điểm: Rất tốn RAM backend. Dễ dính lỗi Out-of-Memory (OOM) khi kích thước mảng
IN (...)vượt quá giới hạn bộ nhớ của tiến trình.
2. Đồng bộ CDC / ETL
- Ưu điểm: Tốc độ đọc cực nhanh vì dữ liệu đã nằm sẵn trên đĩa cục bộ.
- Nhược điểm: Tốn gấp đôi dung lượng đĩa. Dữ liệu luôn có độ trễ (replication lag từ vài trăm ms đến vài giây). Chỉ cần remote server đổi tên một cột, pipeline đồng bộ rất dễ gãy.
3. FEDERATED Storage Engine
- Ưu điểm:
- Dữ liệu luôn chuẩn xác theo thời gian thực, không có độ trễ đồng bộ.
- Local Server không tốn dung lượng ổ cứng cho data và index. Máy chỉ lưu thông tin metadata cấu trúc bảng.
- Viết query tự nhiên: bạn thoải mái dùng
JOINgiữa bảng FEDERATED và bảng InnoDB nội bộ.
- Nhược điểm: Tốc độ phụ thuộc trực tiếp vào độ trễ mạng (RTT). Engine này không hỗ trợ transaction phân tán (XA), không hỗ trợ câu lệnh
ALTER TABLEtrực tiếp và không tối ưu tốt cho các query phức tạp.
Khi nào nên dùng FEDERATED?
FEDERATED không sinh ra để gánh tải cho hệ thống Core OLTP có lưu lượng lớn. Bạn chỉ nên cân nhắc engine này trong các tình huống:
- Trang quản trị (Admin Dashboard) hoặc tool nội bộ cần tra cứu nhanh dữ liệu người dùng mà không đáng để dựng pipeline ETL tốn kém.
- Tham chiếu các bảng danh mục ít thay đổi (tỉnh thành, mã bưu chính, danh mục sản phẩm) đặt tập trung ở database master.
- Chạy script chuyển đổi (migration) hoặc đối soát số liệu giữa hệ thống cũ và mới.
Hướng dẫn từng bước cấu hình FEDERATED
Mô hình thử nghiệm gồm hai máy chủ nội bộ:
- Remote Server: IP
192.168.1.100, port3306, giữ DBauth_dbvà bảng gốcusers. - Local Server: IP
192.168.1.50, giữ DBorder_db, cần đọc trực tiếp bảnguserstừ xa.
Bước 1: Bật engine FEDERATED trên Local Server
Đa phần các bản cài MySQL đều tắt sẵn engine này. Đầu tiên, hãy kiểm tra trạng thái trên Local Server:
SHOW ENGINES;
Nếu cột Support hiển thị NO hoặc DISABLED, bạn mở file cấu hình MySQL (thường nằm ở /etc/mysql/mysql.conf.d/mysqld.cnf) và thêm dòng sau vào khối [mysqld]:
[mysqld]
federated
Khởi động lại MySQL daemon để nhận cấu hình:
sudo systemctl restart mysql
Chạy lại lệnh SHOW ENGINES;. Khi thấy giá trị chuyển sang YES, engine đã sẵn sàng.
Bước 2: Chuẩn bị tài khoản và bảng trên Remote Server
Di chuyển sang Remote Server (192.168.1.100). Khởi tạo schema và cấp quyền đọc tối thiểu cho IP của Local Server:
-- Chạy trên Remote Server
CREATE DATABASE IF NOT EXISTS auth_db;
USE auth_db;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- Chỉ cấp quyền SELECT từ đúng IP của Local Server
CREATE USER 'fed_reader'@'192.168.1.50' IDENTIFIED BY 'StrongPass#2026';
GRANT SELECT ON auth_db.users TO 'fed_reader'@'192.168.1.50';
FLUSH PRIVILEGES;
Bước 3: Tạo bảng liên kết trên Local Server
Cách trực diện nhất là khai báo connection string ngay trong tham số CONNECTION:
-- Chạy trên Local Server
USE order_db;
CREATE TABLE federated_users (
id INT NOT NULL,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP
)
ENGINE=FEDERATED
CONNECTION='mysql://fed_reader:StrongPass#[email protected]:3306/auth_db/users';
Cú pháp URL tuân theo quy tắc: mysql://user:password@host:port/database/table.
Bước 4: Tách credential bảo mật bằng `CREATE SERVER`
Khai báo mật khẩu trần trong câu lệnh CREATE TABLE rất nguy hiểm vì ai gõ SHOW CREATE TABLE cũng đọc được. Bạn nên che giấu thông tin kết nối bằng CREATE SERVER:
-- Tạo đối tượng server connection
CREATE SERVER remote_auth_srv
FOREIGN DATA WRAPPER mysql
OPTIONS (
HOST '192.168.1.100',
DATABASE 'auth_db',
USER 'fed_reader',
PASSWORD 'StrongPass#2026',
PORT 3306
);
-- Tạo bảng sử dụng tên server vừa định nghĩa
CREATE TABLE federated_users_secure (
id INT NOT NULL,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP
)
ENGINE=FEDERATED
CONNECTION='remote_auth_srv/users';
Bước 5: Kiểm tra hiệu năng câu lệnh JOIN
Lúc này bảng federated_users_secure hoạt động hệt như một bảng nội bộ trong order_db:
-- Đọc một bản ghi theo khóa chính
SELECT id, username, email FROM federated_users_secure WHERE id = 10;
-- Ghép bảng InnoDB cục bộ với bảng FEDERATED từ xa
SELECT
o.id AS order_id,
o.total_amount,
u.username,
u.email
FROM orders o
JOIN federated_users_secure u ON o.user_id = u.id
WHERE o.status = 'PAID'
LIMIT 20;
Bẫy hiệu năng và kinh nghiệm thực chiến
Khi dùng FEDERATED trên môi trường production, hãy cẩn thận với ba vấn đề sống còn:
- Cạm bẫy Full Table Scan: FEDERATED chỉ đẩy được các mệnh đề
WHEREđơn giản có index xuống remote server. Nếu bạn viết điều kiện không dùng index (chẳng hạnLIKE '%keyword%'), Local Server sẽ âm thầm tải toàn bộ hàng trăm ngàn dòng từ Remote về máy mình rồi mới lọc. Đường truyền LAN 1Gbps có thể bị nghẽn tức thì. - Lệch Schema gây crash query: Định nghĩa cột giữa Local và Remote phải khớp nhau. Nếu bên Remote sửa
VARCHAR(50)thànhVARCHAR(150)hoặc đổi tên cột mà Local chưa sửa theo, mọi truy vấn liên quan sẽ trả về lỗi ngay. - Kiểm soát độ trễ mạng: Chỉ nên đặt bảng FEDERATED giữa các máy chủ cùng dải mạng nội bộ (LAN / VPC với ping dưới 1-2ms). Tuyệt đối tránh trỏ FEDERATED qua Internet công cộng giữa hai data center cách xa nhau vì network jitter sẽ làm ứng dụng treo hàng loạt kết nối.

