Tổng quan về MHA (Master High Availability)
MHA (Master High Availability) là bộ công cụ mã nguồn mở mạnh mẽ được thiết kế để quản lý sự cố và chuyển đổi tự động trong môi trường sao chép (replication) của MySQL. Mục tiêu cốt lõi của MHA là giải quyết vấn đề "điểm lỗi đơn" (Single Point of Failure - SPOF) tại Master. Trong trường hợp Master gặp sự cố, MHA có thể thực hiện quy trình chuyển đổi (failover) trong khoảng 0 đến 30 giây, đồng thời tối đa hóa tính toàn vẹn của dữ liệu bằng cách cứu cứu nhật ký nhị phân (binary logs) từ Master bị lỗi.
Tại sao cần triển khai MHA?
Trong kiến trúc MySQL chuẩn, nếu máy chủ Master bị hỏng, quá trình khôi phục thủ công thường mất nhiều thời gian và có nguy cơ mất dữ liệu. MHA tự động hóa quy trình này, đảm bảo hệ thống database luôn sẵn sàng.
Kiến trúc thành phần của MHA
Hệ thống MHA bao gồm hai phần chính:
- MHA Manager (Node quản lý): Là thành phần giám sát, có thể được cài đặt trên một máy chủ độc lập hoặc chạy trên một trong các Slave. Nó chịu trách nhiệm kiểm tra trạng thái của Master định kỳ và điều phối quá trình chuyển đổi khi có sự cố.
- MHA Node (Node dữ liệu): Được cài đặt trên mỗi máy chủ MySQL (bao gồm cả Master và Slaves). Nó nhận các lệnh từ Manager để thực hiện các tác vụ như sao chép日志, áp dụng sự khác biệt relay logs, v.v.
Đặc điểm nổi bật
- Tự động phát hiện sự cố và chuyển đổi Slave có dữ liệu mới nhất lên làm Master.
- Hỗ trợ sao chép bán đồng bộ (semi-synchronous replication) để giảm thiểu mất mát dữ liệu.
- Cấu trúc tối thiểu là một Master và hai Slaves.
Thuật toán chọn Master mới
Khi cần chuyển đổi, MHA sử dụng thuật toán sau để chọn Slave phù hợp nhất:
- Dựa trên dữ liệu: Ưu tiên Slave có vị trí (Position/GTID) gần nhất với Master đã lỗi.
- Dựa trên cấu hình: Nếu dữ liệu tương đương, MHA sẽ chọn theo thứ tự được định nghĩa trong file cấu hình.
- Dựa trên权重: Nếu tham số
candidate_master=1được thiết lập, Slave đó sẽ được ưu tiên làm Master mới, bỏ qua độ trễ sao chép (nếucheck_repl_delay=0).
Cấu trúc hoạt động của MHA
MHA hoạt động dựa trên cơ chế giám sát liên tục. Khi Manager phát hiện Master không phản hồi (ping thất bại), quy trình sau sẽ được kích hoạt:
- Cấu hình được kiểm tra lại.
- Tentatively truy xuất các binary logs còn sót lại từ Master cũ (nếu có thể).
- Áp dụng các sự kiện relay log chênh lệch lên các Slave để đồng bộ hóa dữ liệu.
- Nâng cấp Slave có dữ liệu cập nhật nhất lên làm Master mới.
- Các Slave khác được cấu hình lại để sao chép từ Master mới.
- Địa chỉ IP ảo (VIP) được chuyển sang Master mới.
Triển khai kiến trúc Master-Slave
Trước khi cài MHA, ta cần thiết lập môi trường replication chuẩn. Dưới đây là ví dụ cấu hình với 1 Master và 2 Slaves.
Cấu hình trên Master Node (db-master)
# Dừng dịch vụ và làm sạch dữ liệu cũ
[root@db-master ~]# systemctl stop mysqld
[root@db-master ~]# rm -rf /var/lib/mysql/*
# Cấu hình file my.cnf
[root@db-master ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=101
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
log_slave_updates=ON
symbolic-links=0
# Khởi động lại và khởi tạo bảo mật
[root@db-master ~]# mysqld --user mysql --initialize
[root@db-master ~]# systemctl start mysqld
[root@db-master ~]# mysql_secure_installation
Tiếp tục, cấu hình tài khoản replication và bán đồng bộ trong MySQL:
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> CREATE USER 'rep_user'@'%' IDENTIFIED BY 'Passw0rd!';
mysql> GRANT REPLICATION SLAVE ON *.* TO rep_user@'%';
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Cấu hình trên Slave Nodes (db-slave1, db-slave2)
[root@db-slave1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=102 # Lưu ý: ID phải khác nhau, slave2 có thể là 103
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
log_slave_updates=ON
symbolic-links=0
[root@db-slave1 ~]# mysqld --user mysql --initialize
[root@db-slave1 ~]# systemctl start mysqld
Thiết lập kết nối replication trên Slaves:
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_USER='rep_user', MASTER_PASSWORD='Passw0rd!', MASTER_AUTO_POSITION=1;
mysql> START SLAVE;
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
mysql> STOP SLAVE IO_THREAD; START SLAVE IO_THREAD; # Khởi động lại luồng IO để plugin có hiệu lực
Cài đặt các gói phần mềm MHA
Cần cài đặt mha4mysql-node trên tất cả các máy chủ DB và mha4mysql-manager trên máy chủ quản lý.
# Trên MHA Manager
[root@mha-manager ~]# yum install mha4mysql-manager-0.58-0.el7.centos.noarch.rpm -y
# Trên tất cả DB Nodes (Master và Slaves)
[root@mha-manager ~]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@db-master:/tmp/
[root@mha-manager ~]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@db-slave1:/tmp/
[root@mha-manager ~]# scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@db-slave2:/tmp/
# Thực hiện cài đặt trên từng DB node
[root@db-master ~]# yum install /tmp/mha4mysql-node-0.58-0.el7.centos.noarch.rpm -y
Cấu hình môi trường MHA Manager
Tạo thư mục cấu hình và file cấu hình ứng dụng.
[root@mha-manager ~]# mkdir -p /etc/mha_app
[root@mha-manager ~]# vim /etc/mha_app/app1.cnf
Nội dung file cấu hình:
[server default]
user=admin
password=AdminP@ss
ssh_user=root
repl_user=rep_user
repl_password=Passw0rd!
master_binlog_dir=/var/lib/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 192.168.1.10 -s 192.168.1.11
ping_interval=2
manager_workdir=/etc/mha_app
manager_log=/var/log/mha_app/manager.log
[server1]
hostname=192.168.1.10
candidate_master=1
check_repl_delay=0
[server2]
hostname=192.168.1.11
candidate_master=1
check_repl_delay=0
[server3]
hostname=192.168.1.12
no_master=1
Kiểm tra kết nối và Replication
Trước khi chạy MHA, cần đảm bảo SSH trust và Replication hoạt động tốt.
[root@mha-manager ~]# masterha_check_ssh --conf=/etc/mha_app/app1.cnf
# Output mong đợi: All SSH connection tests passed successfully.
[root@mha-manager ~]# masterha_check_repl --conf=/etc/mha_app/app1.cnf
# Output mong đợi: MySQL Replication Health is OK.
Quy trình chuyển đổi lỗi (Failover)
1. Chuyển đổi thủ công (Online Master Switch)
Được sử dụng khi bảo trì máy chủ Master hiện tại mà không gây gián đoạn dịch vụ.
[root@mha-manager ~]# masterha_master_switch --conf=/etc/mha_app/app1.cnf --master_state=alive --new_master_host=192.168.1.11 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
2. Chuyển đổi khi có lỗi (Failover)
Khi Master chết, MHA có thể chuyển đổi tự động hoặc thủ công. Để chuyển đổi thủ công sau khi Master die:
# Giả lập lỗi Master
[root@db-master ~]# systemctl stop mysqld
# Thực hiện chuyển đổi trên Manager
[root@mha-manager ~]# masterha_master_switch --master_state=dead --conf=/etc/mha_app/app1.cnf --dead_master_host=192.168.1.10 --dead_master_port=3306 --new_master_host=192.168.1.11 --new_master_port=3306 --ignore_last_failover
3. Khôi phục Node bị lỗi
Sau khi chuyển đổi thành công, cần đưa Master cũ trở lại cluster với vai trò Slave.
# Trên node cũ (đã sửa lỗi)
[root@db-master ~]# systemctl start mysqld
mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.11', MASTER_USER='rep_user', MASTER_PASSWORD='Passw0rd!', MASTER_AUTO_POSITION=1;
mysql> START SLAVE;
Tích hợp Virtual IP (VIP)
Để ứng dụng kết nối vào DB mà không cần thay đổi cấu hình DNS/IP, ta dùng VIP. MHA sẽ di chuyển VIP này sang Master mới. Sử dụng script Perl để xử lý.
Tạo script /usr/local/bin/vip_manager:
#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use Getopt::Long;
my (
$cmd, $ssh_user, $old_master_host, $old_master_ip,
$old_master_port, $new_master_host, $new_master_ip, $new_master_port
);
my $virtual_ip = '192.168.1.200/24';
my $interface = 'eth0';
my $cmd_add = "/sbin/ip addr add $virtual_ip dev $interface";
my $cmd_del = "/sbin/ip addr del $virtual_ip dev $interface";
GetOptions(
'command=s' => \$cmd,
'ssh_user=s' => \$ssh_user,
'orig_master_host=s' => \$old_master_host,
'orig_master_ip=s' => \$old_master_ip,
'orig_master_port=i' => \$old_master_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
);
exit &main();
sub main {
if ( $cmd eq "stop" || $cmd eq "stopssh" ) {
my $exit_code = 1;
eval {
print "Gỡ bỏ VIP trên Master cũ: $old_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Lỗi: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $cmd eq "start" ) {
my $exit_code = 0;
eval {
print "Gán VIP $virtual_ip lên Master mới: $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
else {
&usage();
exit 1;
}
}
sub start_vip() {
`ssh $ssh_user\@$new_master_host \" $cmd_add \"`;
}
sub stop_vip() {
return 0 unless ($ssh_user);
`ssh $ssh_user\@$old_master_host \" $cmd_del \"`;
}
sub usage {
print
"Usage: vip_manager --command=start|stop|stopssh --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port\n";
}
Phân quyền và cấu hình trong file app1.cnf:
[root@mha-manager ~]# chmod +x /usr/local/bin/vip_manager
# Thêm dòng sau vào app1.cnf trong phần [server default]
master_ip_failover_script= /usr/local/bin/vip_manager
Bây giờ, khi MHA thực hiện failover, VIP sẽ tự động dịch chuyển sang Master mới, đảm bảo ứng dụng không bị gián đoạn kết nối.