Cấu hình chuyển đổi Master-Slave MariaDB trên Windows Server
Bài viết này tập trung riêng vào quy trình chuyển đổi vai trò Slave lên Master cho MariaDB (GTID Replication), chia rõ 2 tình huống thực tế: (1) chủ động chuyển đổi khi Master vẫn còn sống — ưu tiên an toàn dữ liệu tuyệt đối; và (2) Master gặp sự cố mất kết nối/hỏng đột ngột (disaster) — ưu tiên khôi phục dịch vụ nhanh nhất có thể. Đi kèm checklist thao tác nhanh để tra cứu tại chỗ khi cần.
I. Server master còn hoạt động (chủ động chuyển đổi)
Áp dụng khi: cần bảo trì/patch Master, chuyển tải sang site khác theo kế hoạch, hoặc diễn tập định kỳ. Nguyên tắc: LUÔN đảm bảo Slave đã đồng bộ 100% (Seconds_Behind_Master = 0) trước khi cắt ghi trên Master cũ.
▶ Thực hiện trên: Master hiện tại
- Khoá ghi tạm thời trên Master để dừng phát sinh giao dịch mới:
SET GLOBAL read_only = ON;
-- Ứng dụng/HIS/EMR: tạm dừng hoặc chuyển sang chế độ bảo trì (maintenance mode)

Khoá ghi trên Master hiện tại (103.48.195.25) — SET GLOBAL read_only = ON
▶ Thực hiện trên: Slave sẽ lên Master
- Xác nhận Slave đã bắt kịp hoàn toàn (bắt buộc phải = 0 mới được đi tiếp):
SHOW SLAVE STATUS\G
-- Kiểm tra: Seconds_Behind_Master: 0
-- Kiểm tra: Slave_IO_Running: Yes | Slave_SQL_Running: Yes

Xác nhận Slave (45.119.85.253) đã đồng bộ đầy đủ — Seconds_Behind_Master: 0
- Dừng vai trò Slave, mở ghi, promote thành Master mới:
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;

Promote Slave (45.119.85.253) thành Master mới
▶ Thực hiện trên: Ứng dụng / HIS / EMR
- Trỏ connection string / VIP / proxy sang server vừa promote. Tắt chế độ bảo trì, tiếp tục ghi bình thường.
▶ Thực hiện trên: Master cũ → hạ cấp thành Slave
- Trỏ lại làm Slave, replicate từ Master mới:
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='<IP Master mới>',
MASTER_PORT=3307,
MASTER_USER='repl_user',
MASTER_PASSWORD='<mat_khau_manh>',
MASTER_USE_GTID=slave_pos,
MASTER_SSL=0;
SET GLOBAL read_only = ON;
START SLAVE;

Master cũ (103.48.195.25) hạ cấp thành Slave, trỏ về Master mới
- Xác nhận SHOW SLAVE STATUS\G sạch, Seconds_Behind_Master: 0 — hoàn tất switchover, không mất dữ liệu.

Trạng thái cuối cùng sau switchover — replicate đồng bộ sạch, Seconds_Behind_Master: 0
✓ Vì khoá ghi trước khi kiểm tra đồng bộ, và chỉ chuyển hướng ứng dụng sau khi Slave xác nhận Seconds_Behind_Master = 0, quy trình này đảm bảo RPO = 0 tuyệt đối.
II. Kịch bản — Failover khẩn cấp (Master down / disaster)
⚠ Chỉ thực hiện các bước dưới đây SAU KHI đã xác nhận chắc chắn Master không còn truy cập được (không chỉ là mạng chậm/gián đoạn tạm thời) — promote nhầm trong khi Master cũ vẫn đang chạy sẽ gây SPLIT-BRAIN (2 node cùng nhận ghi, dữ liệu phân kỳ, rất khó gộp lại).
1. Bước 0 — Xác nhận Master thực sự down
- Ping IP Master, kiểm tra port (
Test-NetConnection -ComputerName <IP Master> -Port 3307). - Thử RDP/console trực tiếp vào server nếu có thể — xác định do OS/server chết hẳn hay chỉ do mạng.
- Kiểm tra từ phía Slave:
SHOW SLAVE STATUS\Gđể xem lỗi kết nối cụ thể và thời điểm Master ngưng gửi dữ liệu (Last_IO_Error). - Nếu có thể, thử liên hệ team hạ tầng/ISP xác nhận sự cố mạng hay sự cố server thật sự trước khi quyết định promote.

Bằng chứng Master (45.119.85.253) mất kết nối hoàn toàn — Last_IO_Error 2003, ghi nhận từ phía Slave (103.48.195.25)
2. Promote Slave lên Master
▶ Thực hiện trên: Slave — sẽ được promote
- Ghi lại vị trí GTID cuối cùng đã nhận được trước khi promote (phục vụ đối chiếu dữ liệu sau này):
SHOW SLAVE STATUS\G
-- Ghi lại: Gtid_IO_Pos, Seconds_Behind_Master lúc mất kết nối
- Dừng vai trò Slave và promote thành Master độc lập:
STOP SLAVE;
SET GLOBAL read_only = OFF;
RESET SLAVE ALL;

Promote Slave (103.48.195.25) thành Master độc lập

Xác nhận read_only = OFF — Master mới đã sẵn sàng nhận ghi
▶ Thực hiện trên: Ứng dụng / HIS / EMR
- Chuyển hướng khẩn cấp connection string / VIP sang Slave vừa promote, đưa hệ thống hoạt động trở lại.
⚠ Nếu Seconds_Behind_Master tại thời điểm mất kết nối KHÔNG bằng 0, những giao dịch Master cũ đã ghi nhưng chưa kịp gửi cho Slave sẽ MẤT (RPO > 0). Cần ghi nhận lại khoảng thời gian này để đối chiếu nghiệp vụ (ví dụ: yêu cầu HIS/EMR kiểm tra lại các phiếu vừa tạo trong vài giây/phút cuối trước sự cố).
3. Xử lý Master cũ khi phục hồi trở lại
▶ Thực hiện trên: Master cũ
- TUYỆT ĐỐI KHÔNG để service MariaDB tự nhận ghi song song trong lúc kiểm tra — ngay khi server/service khởi động lại, khoá ghi lại lập tức:
SET GLOBAL read_only = ON;
- So sánh GTID hiện tại giữa Master cũ và Master mới để xác nhận có bị phân kỳ dữ liệu hay không:
SELECT @@gtid_current_pos;
-- Chạy trên cả 2 server, đối chiếu kết quả

GTID trên Master cũ (45.119.85.253) sau khi khoá ghi

GTID trên Master mới (103.48.195.25) — trùng khớp, không phân kỳ dữ liệu
- Trường hợp bình thường (GTID trùng khớp, không có giao dịch phân kỳ) — rejoin làm Slave, trỏ về Master mới, giống hệt thao tác failback ở Kịch bản A:
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='<IP Master mới>',
MASTER_PORT=3307,
MASTER_USER='repl_user',
MASTER_PASSWORD='<mat_khau_manh>',
MASTER_USE_GTID=slave_pos;
START SLAVE;

Master cũ (45.119.85.253) nhập lại làm Slave, trỏ về Master mới (103.48.195.25)
- Nếu GTID phân kỳ (server cũ có giao dịch mà Master mới không có) — KHÔNG dùng CHANGE MASTER TO trực tiếp: cần backup dữ liệu bị lệch riêng ra (mysqldump bảng liên quan để đối chiếu thủ công với nghiệp vụ), sau đó xoá dữ liệu cục bộ trên node cũ và rejoin bằng full resync (mysqldump từ Master mới hoặc xtrabackup) để tránh xung đột GTID/duplicate key.

Xác nhận replicate sạch sau khi Master cũ nhập lại làm Slave — Seconds_Behind_Master: 0
