0

Apache Derby Bài 49: Kiến trúc High Availability (HA) và Cơ chế Replication (Nhân bản dữ liệu)

1. Điểm mù của hệ thống đơn lẻ (Single Point of Failure - SPOF)

Trong các bài trước, chúng ta đã tối ưu mã nguồn, đánh Index, và nén dữ liệu. Nhưng tất cả những nỗ lực đó đều xoay quanh một máy chủ vật lý duy nhất. Điều gì sẽ xảy ra nếu:

  • Máy chủ Derby bị mất điện đột ngột?

  • Cháy nổ tại trung tâm dữ liệu?

  • Ổ cứng bị hỏng hoàn toàn (Disk Crash) khiến tệp .dat không thể đọc được?

Dù bạn có file Backup (Bài 35), bạn vẫn mất hàng giờ để cài đặt lại hệ điều hành, cấu hình Java và phục hồi dữ liệu. Trong thời gian đó, hệ thống (như quản lý trạm vé Metro hay kho vận logistics) bị tê liệt hoàn toàn (Downtime).

Để hệ thống hoạt động 24/7 (High Availability - Sẵn sàng cao), bạn cần cơ chế Replication (Nhân bản dữ liệu): Dữ liệu được ghi vào máy chủ A sẽ lập tức được sao chép sang máy chủ B. Khi máy A chết, máy B sẽ ngay lập tức thay thế.

2. Cơ chế Replication của Apache Derby (Master - Slave)

Apache Derby hỗ trợ mô hình 1-to-1 Asynchronous Replication (Nhân bản bất đồng bộ 1-1). Mô hình này bao gồm hai máy chủ Network Server chạy song song:

  1. Master (Máy chủ chính - Active): Nhận kết nối từ ứng dụng Java, xử lý mọi thao tác SELECT, INSERT, UPDATE, DELETE.

  2. Slave (Máy chủ phụ - Standby): Chỉ kết nối nội bộ với Master. Không cho phép ứng dụng bên ngoài đọc/ghi. Nó đóng vai trò "người bắt chước".

Cách hoạt động (Log Shipping): Mỗi khi một giao dịch được COMMIT trên Master, Derby không gửi nguyên câu SQL sang Slave. Thay vào đó, nó gửi các Transaction Log (Nhật ký giao dịch vật lý) qua đường truyền mạng. Slave nhận Log này và tự động "phát lại" (replay) vào đĩa cứng của nó. Do tính chất "bất đồng bộ", Master không cần đợi Slave xác nhận ghi xong mới trả kết quả cho ứng dụng, giúp hiệu năng của Master không bị suy giảm.

3. Các bước thiết lập Replication trong Derby

Giả sử:

  • Máy Master: IP 192.168.1.10, đang có CSDL my_company_db.

  • Máy Slave: IP 192.168.1.20. Cổng giao tiếp Replication là 4851.

Bước 1: Chuẩn bị dữ liệu ban đầu (Baseline)

Bạn BẮT BUỘC phải sao chép vật lý CSDL (thư mục my_company_db) từ máy Master sang máy Slave. Hai máy phải có xuất phát điểm giống hệt nhau. (Sử dụng lệnh Online Backup ở Bài 35 để tạo bản sao này).

Bước 2: Bật chế độ Slave (Máy phụ chờ đợi)

Trên máy Slave, bạn mở kết nối JDBC (thông qua ij hoặc một script Java nhỏ) với thuộc tính startSlave=true.

Chuỗi kết nối trên Slave:

Plaintext

jdbc:derby:my_company_db;startSlave=true;slaveHost=192.168.1.20;slavePort=4851

Trạng thái: Lúc này Slave sẽ "đóng băng" CSDL, mở cổng mạng 4851 và kiên nhẫn chờ Master kết nối tới. Ứng dụng Java của bạn KHÔNG ĐƯỢC kết nối vào Slave lúc này.

Bước 3: Khởi động Master và bắt đầu đồng bộ

Trên máy Master, bạn mở kết nối JDBC với thuộc tính startMaster=true.

Chuỗi kết nối trên Master:

Plaintext

jdbc:derby:my_company_db;startMaster=true;slaveHost=192.168.1.20;slavePort=4851

Trạng thái: Master sẽ kết nối sang IP 192.168.1.20 cổng 4851. Khi bắt tay thành công, mọi luồng dữ liệu (I/O) mới từ giờ trở đi sẽ được âm thầm gửi sang Slave.

4. Kịch bản thảm họa và Failover (Chuyển đổi dự phòng)

Kịch bản 1: Chủ động dừng đồng bộ (Bảo trì Master)

Nếu bạn muốn nâng cấp RAM cho máy Master, bạn cần tắt Replication một cách an toàn. Trên máy Master, bạn chạy lệnh:

Plaintext

jdbc:derby:my_company_db;stopMaster=true

Lúc này, Master và Slave tách ra thành 2 CSDL độc lập.

Kịch bản 2: Master chết đột ngột (Failover)

Máy Master bị cháy nguồn. Ứng dụng Java của bạn (Spring Boot) báo lỗi kết nối. Bạn cần nhanh chóng "đưa" Slave lên làm Master để hệ thống tiếp tục chạy.

Trên máy Slave, bạn kích hoạt thuộc tính failover=true:

Plaintext

jdbc:derby:my_company_db;failover=true

Hành động: Slave sẽ áp dụng toàn bộ các Log còn sót lại trong bộ đệm, ngắt chế độ chờ, và chuyển mình thành Master.

Tại tầng Ứng dụng (Java): Lập trình viên cần cấu hình ứng dụng để khi kết nối IP .10 (Master cũ) thất bại, nó sẽ tự động thử kết nối sang IP .20 (Slave vừa lên ngôi).

Mã giả trong Spring Boot (Sử dụng nhiều cấu hình URL):

Java

String primaryUrl = "jdbc:derby://192.168.1.10:1527/my_company_db";
String failoverUrl = "jdbc:derby://192.168.1.20:1527/my_company_db";

try {
    // Thử kết nối Master
    return DriverManager.getConnection(primaryUrl);
} catch (SQLException e) {
    // Nếu Master sập, kích hoạt Failover trên Slave và kết nối vào nó
    triggerFailoverOnSlave(); 
    return DriverManager.getConnection(failoverUrl);
}

5. Những giới hạn thực tế của Derby Replication

Replication trong Derby rất nhẹ và dễ cấu hình, nhưng nó phù hợp cho các doanh nghiệp vừa và nhỏ vì mang một số hạn chế so với PostgreSQL hay Oracle:

  1. Chỉ có 1-to-1: Bạn không thể có 1 Master phân phát cho 5 Slaves.

  2. Slave không thể đọc (No Read-Replica): Trong nhiều DB khác, Slave có thể được dùng để chạy báo cáo (Report) nhằm giảm tải cho Master. Nhưng trong Derby, Slave bị khóa hoàn toàn (chỉ nhận log) cho đến khi Failover.

  3. Nguy cơ mất dữ liệu nhỏ (Data Loss): Do tính chất "Asynchronous", nếu Master chết đúng vào phần nghìn giây mà nó đã Commit xuống đĩa của nó nhưng chưa kịp gửi Log qua dây cáp mạng sang Slave, giao dịch đó sẽ bị mất khi Slave lên thay.

Hệ thống của chúng ta giờ đây đã có khả năng chống chịu thảm họa phần cứng. Để quản lý và theo dõi toàn bộ "sức khỏe" của cỗ máy đồ sộ này (CPU, RAM, số kết nối đang mở) từ xa, chúng ta sẽ bước vào công cụ giám sát chuyên nghiệp nhất của Java: Apache Derby Bài 50: Giám sát hiệu năng hệ thống qua JMX (Java Management Extensions).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí