한번의 failover 수행만 가능 ( mha daemon 은 한번의 failover 만 수행 가능 / failover 후 재구성 필요 )
candidate master 중 1번째로 지정된 slave 가 master 로 전환되며 기존 master 에 붙어있던 slave 는 new slave 로 전환
MHA로 failover가 되면, 모든 slave Node에 down되기 직전의 master Node 데이터 변경 내용을 모두 적용 함.
모든 Node에 최신 데이터 변경 내용을 적용 후 시작 되기 때문에, master - slave 간 데이터 동기화 지연이 클수록 복구 시간이 오래 걸림.
vip 를 이동하는 형태로 failover 되므로 서버에서 새로운 마스터 장비의 ip 변경이 불필요함 ( old master 장비에 셋팅되어 있던 VIP를 new master 장비에 셋팅하는 방식 .. Application은 서버 정상 일때나 failover가 된 이후 모두 VIP로 DB에 접속함 )
MHA를 통해 DB가 스위칭 될때 일시적으로 기존 연결이 끊어지므로, application 서버는 connection 재구성 예외 처리 로직이 필요
MHA 구성 조건
MySQL 서버 최소 2대 이상 필요
MySQL Master - Slave Replication 구성 필요
Manager Server 1대 필요(Slave 장비에서 구성 가능)
VIP 1개
test 환경 master : 10.10.10.10 slave : 10.10.10.20 vip : 10.10.10.30
Can't locate inc/Module/Install.pm in @INC (you may need to install the inc::Module::Install module) (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5) at Makefile.PL line 1.
BEGIN failed--compilation aborted at Makefile.PL line 1.
perl-Log-Dispatch 오류
powertools 관련 rpm 설치
해결 : dnf config-manager --set-enabled powertools
perl-PAR-Packer-Tk conflicting 오류 yum install perl* 실행 시 아래 에러는 무시 가능
Error:
Problem 1: conflicting requests
- nothing provides perl(Tk::ColoredButton) needed by perl-PAR-Packer-Tk-1.052-2.el8.noarch
- nothing provides perl(Tk::EntryCheck) needed by perl-PAR-Packer-Tk-1.052-2.el8.noarch
- nothing provides perl(Tk::Getopt) needed by perl-PAR-Packer-Tk-1.052-2.el8.noarch
- nothing provides perl(Tk::Pod) needed by perl-PAR-Packer-Tk-1.052-2.el8.noarch
Problem 2: conflicting requests
- nothing provides perl-HTML-Strip needed by perl-sword-1.8.1-18.el8.x86_64
(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)
GRANT ALL PRIVILEGES ON *.* TO 'mhauser'@'%' IDENTIFIED BY 'mhauser비밀번호';
GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'%' IDENTIFIED BY 'repluser비밀번호';
아래 부분 주석해제 후 저장
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
-- visudo 명령어로 암호없이 ssh계정 사용하기위해 아래 부분 변경
(ssh 통신 시 암호없이 통신을하기 위한 방법이며, 보안을 위해 VIP 알리아스를 만든 후
ohnew 계정은 VIP 알리아스만 실행하고자 변경)
~]# visudo
23라인 부근의 아래 커멘트 부근에 아래 명령어 추가
## Command Aliases
## These are groups of related commands...
Cmnd_Alias VIP = /sbin/ifconfig, /sbin/arping
57라인 부근에 이부분 주석 처리
# Defaults requiretty
105 라인 부근에 아래 부분 추가
## Allow root to run any commands anywhere
mhauser ALL=(ALL) NOPASSWD: VIP
mha user ssh 설정
su - mhauser ( 반드시 mhauser 계정으로 실행 )
ssh-keygen -t rsa ( 암호없이 생성을 위해 enter 연타 )
# source 서버에서 target 서버로 전달
ssh-copy-id mhauser@10.10.10.10
ssh-copy-id mhauser@10.10.10.20
================================================================================================================
~]$ ssh-copy-id mhauser@10.10.10.10
The authenticity of host '10.10.10.10 (10.10.10.10)' can't be established.
ECDSA key fingerprint is 38:58:d9:71:8a:ed:89:af:1d:c8:d1:69:e0:e1:b8:dd.
Are you sure you want to continue connecting (yes/no)? yes
/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
mhauser@10.10.10.10's password:
/etc/profile.d/logging.sh: line 7: ifconfig: command not found
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'mhauser@10.10.10.10'"
and check to make sure that only the key(s) you wanted were added.
================================================================================================================
# 접속 테스트 ( 모든 장비 Node, Manager 간 비밀번호 없이 접속 가능 )
ssh mhauser@10.10.10.10
ssh mhauser@10.10.10.20
VIP 설정
master node 장비에서만 실행
-- IP 확인
~]# ifconfig
bond0: flags=5187<UP,BROADCAST,RUNNING,MASTER,MULTICAST> mtu 1500
inet 10.10.10.10 netmask 255.255.255.0 broadcast 10.10.10.255
.....
-- VIP 설정
~]# ifconfig bond0:0 10.10.10.30 up netmask 255.255.255.128 up
-- VIP 적용
~]# arping -c3 -D -I bond0 -s 10.10.10.30 -U 10.10.10.1
ARPING 10.10.10.1 from 10.10.10.10 bond0
Unicast reply from 10.162.131.10 [00:00:5E:00:01:15] 0.770ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
[root@Nmsprofdb01 ~]#
-- VIP 확인
[root@Nmsprofdb01 ~]# ifconfig
bond0: flags=5187<UP,BROADCAST,RUNNING,MASTER,MULTICAST> mtu 1500
inet 10.10.10.10 netmask 255.255.255.0 broadcast 10.10.10.255
.....
bond0:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.10.10.30 netmask 255.0.0.0 broadcast 10.255.255.255
master_ip_failover 파일 생성
manager 장비 /mha/script/master_ip_failover 파일 생성 후 추가
#!/usr/bin/env perl
# use strict;
# use warnings FATAL => 'all';
use Getopt::Long;
my (
$command, $ssh_user, $orig_master_host, $orig_master_ip, $orig_master_ssh_port,
$orig_master_port, $new_master_host, $new_master_ip, $new_master_port, $new_master_user,
$new_master_password, $new_master_ssh_port
);
my $vip = '10.10.10.30'; # Virtual IP
my $key = "0";
my $devicenm = "bond0";
my $ssh_start_vip = "sudo /sbin/ifconfig $devicenm:$key $vip netmask 255.255.255.128 up";
my $ssh_stop_vip = "sudo /sbin/ifconfig $devicenm:$key down";
my $ssh_mac_refresh = "sudo /sbin/arping -c3 -D -I $devicenm -s 10.10.10.30 10.10.10.1";
GetOptions(
'command=s' => \$command,
'ssh_user=s' => \$ssh_user,
'orig_master_host=s' => \$orig_master_host,
'orig_master_ip=s' => \$orig_master_ip,
'orig_master_port=i' => \$orig_master_port,
'orig_master_ssh_port=i' => \$orig_master_ssh_port,
'new_master_host=s' => \$new_master_host,
'new_master_ip=s' => \$new_master_ip,
'new_master_port=i' => \$new_master_port,
'new_master_user=s' => \$new_master_user,
'new_master_password=s' => \$new_master_password,
'new_master_ssh_port=i' => \$new_master_ssh_port,
);
exit &main();
sub main {
print "\n\nIN SCRIPT TEST====$ssh_stop_vip==$ssh_start_vip===\n\n";
if ( $command eq "stop" || $command eq "stopssh" ) {
# $orig_master_host, $orig_master_ip, $orig_master_port are passed.
# If you manage master ip address at global catalog database,
# invalidate orig_master_ip here.
my $exit_code = 1;
eval {
print "Disabling the VIP on old master: $orig_master_host \n";
&stop_vip();
$exit_code = 0;
};
if ($@) {
warn "Got Error: $@\n";
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "start" ) {
# all arguments are passed.
# If you manage master ip address at global catalog database,
# activate new_master_ip here.
# You can also grant write access (create user, set read_only=0, etc) here.
my $exit_code = 10;
eval {
print "Enabling the VIP - $vip on the new master - $new_master_host \n";
&start_vip();
$exit_code = 0;
};
if ($@) {
warn $@;
exit $exit_code;
}
exit $exit_code;
}
elsif ( $command eq "status" ) {
print "Checking the Status of the script.. OK \n";
`ssh -p $orig_master_ssh_port $ssh_user\@$orig_master_host \" $ssh_start_vip \"`;
exit 0;
}
else {
&usage();
exit 1;
}
}
# A simple system call that enable the VIP on the new master
sub start_vip() {
`ssh -p $new_master_ssh_port $ssh_user\@$new_master_host \" $ssh_start_vip \"`;
`ssh -p $new_master_ssh_port $ssh_user\@$new_master_host \" $ssh_mac_refresh\"`;
}
# A simple system call that disable the VIP on the old_master
sub stop_vip() {
`ssh -p $orig_master_ssh_port $ssh_user\@$orig_master_host \" $ssh_stop_vip \"`;
}
sub usage {
print
"Usage: master_ip_failover --command=start|stop|stopssh|status --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";
}
scripts/master_ip_failover 실행 권한 추가
chmod +x /mha/scripts/master_ip_failover
conf 파일 추가
/mha/conf/mhatest.conf 파일 생성 후 작성
[server default]
# mysql user and password
user=mhauser
password=mhauserDB비밀번호
ssh_user=mhauser
repl_user=repluser
repl_password=repluserDB비밀번호
# manager log file
manager_log=/mha/log/mhatest.log
# working directory on the manager
manager_workdir=/mha/work/mhatest/
# working directory on MySQL servers
remote_workdir=/mha/remote/mhatest/
master_binlog_dir=/log/
master_ip_failover_script=/mha/scripts/master_ip_failover --orig_master_ssh_port=22 --new_master_ssh_port=22
[server1]
hostname=10.10.10.10
port=59306
candidate_master=1
[server2]
hostname=10.10.10.20
port=59306
candidate_master=1
#no_master=1
#ignore_fail=1
relay log 삭제 스크립트 추가
relay log purge 스크립트 등록 vi /mha/scripts/relay_log_purge.sh chmod 755 /mha/scripts/relay_log_purge.sh
#!/bin/sh
source ~/.bash_profile
USER=mhauser
PORT=$1
PASSWORD='mhauser패스워드'
# Slave Check
v_mysql=`which mysql`
SLAVE_STATUS=`$v_mysql -u root -p XXXX -P 3306 -e 'show slave status\G;' | grep Running | grep Yes | wc -l`
if [ $SLAVE_STATUS -lt 2 ]
then
echo 'The master does not execute purge...' >> /mha/log/purge_relay.log
exit;
fi
/usr/local/bin/purge_relay_logs --user=$USER --port=$PORT --password=$PASSWORD --disable_relay_log_purge >> /mha/log/purge_relay.log 2>&1
ll /usr/bin/perl
su - mhauser
masterha_check_ssh --conf=/mha/conf/mhatest.conf
~]$ masterha_check_ssh --conf /mha/conf/mhatest.conf
Thu Jun 1 18:52:28 2017 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Thu Jun 1 18:52:28 2017 - [info] Reading application default configurations from /mha/conf/mhatest.conf..
Thu Jun 1 18:52:28 2017 - [info] Reading server configurations from /mha/conf/mhatest.conf..
Thu Jun 1 18:52:28 2017 - [info] Starting SSH connection tests..
Thu Jun 1 18:52:28 2017 - [debug]
Thu Jun 1 18:52:28 2017 - [debug] Connecting via SSH from mhauser@10.10.10.20(10.10.10.20:22) to mhauser@10.10.10.10(10.10.10.10:22)..
Thu Jun 1 18:52:28 2017 - [debug] ok.
Thu Jun 1 18:52:29 2017 - [debug]
Thu Jun 1 18:52:28 2017 - [debug] Connecting via SSH from mhauser@10.10.10.20(10.10.10.20:22) to mhauser@10.10.10.10(10.10.10.10:22)..
Thu Jun 1 18:52:29 2017 - [debug] ok.
Thu Jun 1 18:52:29 2017 - [info] All SSH connection tests passed successfully.
===============================================================================================================
masterha_check_repl
ll /usr/bin/perl
su - mhauser
masterha_check_repl --conf=/mha/conf/mhatest.conf
~]$ masterha_check_repl --conf=/mha/conf/mhatest.conf
Mon Jun 5 14:15:35 2017 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Mon Jun 5 14:15:35 2017 - [debug] MHA::MasterMonitor version 0.56.
Mon Jun 5 14:15:35 2017 - [debug] Connecting to servers..
Mon Jun 5 14:15:36 2017 - [debug] Connected to: 10.10.10.10(10.10.10.10:59306), user=mhauser
Mon Jun 5 14:15:36 2017 - [debug] Connected to: 10.10.10.20(10.10.10.20:59306), user=mhauser
Mon Jun 5 14:15:36 2017 - [debug] Comparing MySQL versions..
Mon Jun 5 14:15:36 2017 - [debug] Comparing MySQL versions done.
Mon Jun 5 14:15:36 2017 - [debug] Connecting to servers done.
.....
Checking the Status of the script.. OK
Bad port 'mhauser@10.10.10.20'
Mon Jun 5 14:15:38 2017 - [debug] OK.
Mon Jun 5 14:15:38 2017 - [warning] shutdown_script is not defined.
Mon Jun 5 14:15:38 2017 - [debug] Disconnected from 10.10.10.10(10.10.10.10:59306)
Mon Jun 5 14:15:38 2017 - [debug] Disconnected from 10.10.10.20(10.10.10.20:59306)
Mon Jun 5 14:15:38 2017 - [debug] Got exit code 0 (Not master dead).
MySQL Replication Health is OK.
Mysql 버전 확인 부분 오류 수정
~]$ masterha_check_repl --conf=/mha/conf/mhatest.conf
## 에러 내용
Fri Nov 4 11:30:59 2022 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Fri Nov 4 11:30:59 2022 - [info] Reading application default configuration from /mha/conf/mhatest.conf..
Fri Nov 4 11:30:59 2022 - [info] Reading server configuration from /mha/conf/mhatest.conf..
Fri Nov 4 11:30:59 2022 - [info] MHA::MasterMonitor version 0.57.
Fri Nov 4 11:31:00 2022 - [error][/usr/local/share/perl5/MHA/MasterMonitor.pm, ln427] Error happened on checking configurations. Redundant argument in sprintf at /usr/local/share/perl5/MHA/NodeUtil.pm line 190.
Fri Nov 4 11:31:00 2022 - [error][/usr/local/share/perl5/MHA/MasterMonitor.pm, ln525] Error happened on monitoring servers.
Fri Nov 4 11:31:00 2022 - [info] Got exit code 1 (Not master dead).
## 수정 방법
/usr/local/share/perl5/MHA/NodeUtil.pm 파일의 190번 라인을 아래 형태로 수정
~]# vi /usr/local/share/perl5/MHA/NodeUtil.pm
182 sub parse_mysql_version($) {
183 my $str = shift;
184 my $result = sprintf( '%03d%03d%03d', $str =~ m/(\d+)/g );
185 return $result;
186 }
187
188 sub parse_mysql_major_version($) {
189 my $str = shift;
190 my $result = sprintf( '%03d%03d%03d', $str =~ m/(\d+)/g );
191 return $result;
192 }
mha 실행
su - mhauser
nohup masterha_manager --conf=/mha/conf/mhatest.conf > /mha/log/mhatest.log 2>&1 &
MongoDB 서버는 UPDATE나 REMOVE 명령에 $isolated 옵션을 사용하면, 데이터 변경 작업이 완료될 때까지 다른 컨넥션이 변경 중인 데이터를 조회할 수 없다.
즉 UPDATE나 REMOVE 명령이 10건의 도큐먼트를 변경해야 하는데, 작업 도중 에러가 발생하면 MongoDB 서버가 이미 처리된 도큐먼트에 대해서 롤백을 수행하거나 하지는 않는다.
$isolated 옵션은 정상적으로 처리될 때에만 필요한 격리 수준을 보장해 준다.
※ 주의
MongoDB의 $isolated 옵션은 꼭 필요한 경우에만 제한적으로 사용할 것을 권장한다. MongoDB 서버는 $isolated 옵션을 사용한 업데이트 명령의 격리 수준을 보장하기 위해서 업데이트 대상 컬렉션에 대해서 쓰기 잠금( Exclusive Lock )을 걸고 처리를 한다. 이는 MongoDB 엔진이 컬렉션 레벨의 잠금을 걸기 때문에 MMAPv1 스토리지 엔진뿐만 아니라 도큐먼트 레벨의 잠금을 지원하는 WiredTiger 스토리지 엔진에서도 동일하게 작동한다. 즉 $isolated 옵션을 설정한 UPDATE나 REMOVE 명령이 수행되는 동안에는 다른 컨넥션에서 어떤 쿼리나 데이터 변경 명령을 실행하지 못한다. 만약 읽고 쓰기가 빈번하게 실행되는 컬렉션에 대해서 $isolated 옵션을 설정한 UPDATE나 DELETE 명령이 실행되면 다른 컨넥션의 수많은 쿼리나 업데이트 명령들이 일시적으로 처리를 멈추게 되고, 응용 프로그램은 데이터베이스의 응답을 받지 못해서 더 많은 쓰레드나 컨넥션을 생성하면서 처리 불가 상태로 빠지게 될 가능성이 높다.