MySQL Replication Setup
by Mark Nielsen
Copyright Dec 2021
This is going to be a different setup. We are manually going to start MySQL multiple times.
We are not going to use start files, but do everything manual --- because I am lazy
and don't want to write service files and because Docker doesn't run service unless
you set it up right.
This will be an advanced setup. This document assume you already have the versions
below installed on your laptop, a vm, or docker instance. An explanation will be added
later, but for now these are tested commands. All the commands can be executed in
the bash prompt and not the mysql prompt.
This is for Ubuntu 20.04 and MariaDB 10.6
- Links
- Files to use
- Setup MariaDB
- Start MySQL
- Check Replication
Links
- https://sqlconjuror.com/mariadb-enabling-semisynchronous-replication/
- https://dev.mysql.com/doc/mysql-replication-excerpt/8.0/en/replication-semisync.html
- https://dev.mysql.com/doc/refman/5.6/en/replication-delayed.html
- https://www.tutorialspoint.com/mysql/mysql-create-tables.htm
- https://www.gnupg.org/documentation/manuals/gnupg-devel/Unattended-GPG-key-generation.html
Files to Use
Copy these
files and directories or
use this tar file
and then set the files permissions.
|
# uncomment to run the tar file.
# tar -xcvf mysql_rep_files.tgz /
mkdir -p /var/log/mysql
cd /var/log/mysql
mkdir -p mysql1/relay mysql2/relay mysql3/relay mysql4/relay mysql5/relay mysql6/relay
mkdir -p mysql1/binlogs mysql2/binlogs mysql3/binlogs mysql4/binlogs mysql5/binlogs mysql6/binlogs
mkdir -p /data/mysql
cd /data/mysql
mkdir -p mysql1/data mysql2/data mysql3/data mysql4/data mysql5/data mysql6/data
export web=http://odendata.com/docs/database/mysql/rep1/data/mysql
for i in 1 2 3 4 5 6; do
dest=/data/mysql/mysql$i/my.cnf
webcnf=$web/mysql$i/my.cnf
echo " wget -vo $dest $webcnf"
wget -O $dest $webcnf
done
mkdir -p /opt/odendata/mysql
for f in Initialize.sh Make_cnf.sh Replication.sh my_template.cnf ; do
dest=/opt/odendata/mysql/$f
web=http://odendata.com/docs/database/mysql/rep1/opt/odendata/mysql/$f
wget -O $dest $web
done
chown -R mysql.mysql /var/log/mysql
chown -R mysql.mysql /data/mysql
| |
We are setting up two severs if Master - Master setup. Each master will have a slave
with delayed replication. Each master will have a normal slave.
Both masters will require the transaction to be committed
before there is a return to the application. All writes should go to one master so that
the other responds quickly.
Start MySQL
For the first time only:
|
chown -R mysql.mysql /var/log/mysql
chown -R mysql.mysql /data/mysql
mysql_install_db --user=mysql --datadir=/data/mysql/mysql1/data \
--defaults-file=/data/mysql/mysql1/my.cnf
mysql_install_db --user=mysql --datadir=/data/mysql/mysql2/data \
--defaults-file=/data/mysql/mysql2/my.cnf
mysql_install_db --user=mysql --datadir=/data/mysql/mysql3/data \
--defaults-file=/data/mysql/mysql3/my.cnf
mysql_install_db --user=mysql --datadir=/data/mysql/mysql4/data \
--defaults-file=/data/mysql/mysql4/my.cnf
mysql_install_db --user=mysql --datadir=/data/mysql/mysql5/data \
--defaults-file=/data/mysql/mysql5/my.cnf
mysql_install_db --user=mysql --datadir=/data/mysql/mysql6/data \
--defaults-file=/data/mysql/mysql6/my.cnf
| |
After each time you start Docker or the server. Its amazing
all the articles about starting MySQL manually is not manually.
A service script is not manually
|
#rm -f /var/log/mysql/mysql*/*.log
#export web=http://odendata.com/docs/database/mysql/rep1/data/mysql
#for i in 1 2 3 4 5 6; do
# dest=/data/mysql/mysql$i/my.cnf
# webcnf=$web/mysql$i/my.cnf
# echo " wget -vo $dest $webcnf"
# wget -O $dest $webcnf
#done
for i in 1 2 3 4 5 6; do
echo "starting mysql $i"
echo "mysqld --defaults-file=/data/mysql/mysql$i/my.cnf &"
mysqld --defaults-file=/data/mysql/mysql$i/my.cnf &
sleep 5
done
#cat /var/log/mysql/mysql1/error.log
ps auxww | grep mysqld
#ls -al /var/lib/mysql/
| |
Setup Mariadb
Setup accounts on all servers.
|
sql=" CREATE USER 'rep'@'localhost' IDENTIFIED BY 'rep'; FLUSH PRIVILEGES;"
sql2="GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.*
TO 'rep'@'localhost'"
# We assume root's password is set in ~/.mysql.my.cnf or its blank.
# If not do it.
for i in 1 2 3 4 5 6; do
echo "Setting up rep in mysql $i"
mysql -v -u root -e "$sql" -S /tmp/mysql$i.sock
mysql -vv -u root -e "$sql2" -S /tmp/mysql$i.sock
mysql -v -u root -e "show grants for rep@localhost" -S /tmp/mysql$i.sock
done
| |
Setup test database and tables.
|
sql="create database if not exists test_od;"
sql2="
use test_od;
drop table if exists hosts;
create table if not exists hosts (
host varchar(64),
date_insert timestamp,
index ( host, date_insert )
);
"
for i in 1 2 3 4 5 6; do
echo "setup schema in mysql $i"
mysql -v -u root -e "$sql" -S /tmp/mysql$i.sock
mysql -vv -u root -e "$sql2" -S /tmp/mysql$i.sock
done
| |
Setup Replication
Setup replication on each server.
NOTE: MariaDB 10.3.3 has semi-synchronous replication built-in if you want it.
|
killall mysqld
sleep 5
echo "removing binlogs"
rm -vf /var/log/mysql/mysql*/binlogs/*
rm -vf /var/log/mysql/mysql*/relay/*
rm -vf /data/mysql/mysql*/data/mysql-bin*
rm -vf /data/mysql/mysql*/data/*relay*
for i in 1 2 3 4 5 6; do
echo "starting mysql $i"
echo "mysqld --defaults-file=/data/mysql/mysql$i/my.cnf &"
mysqld --defaults-file=/data/mysql/mysql$i/my.cnf &
sleep 5
done
for i in 1 2 3 4 5 6; do
echo "flushing logs mysql $i"
mysql -v -u root -e "flush logs" -S /tmp/mysql$i.sock
mysql -v -u root -e "show master logs" -S /tmp/mysql$i.sock
done
for i in 1 2 3 4 5 6; do
echo "start slave mysql $i"
mysql -v -u root -e "stop slave\G" -S /tmp/mysql$i.sock
done
sql_slave1="
change master to MASTER_HOST='127.0.0.1',
MASTER_USER='rep',
MASTER_PASSWORD='rep',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=375,
master_port=3301;
"
sql_slave2="
change master to MASTER_HOST='127.0.0.1',
MASTER_USER='rep',
MASTER_PASSWORD='rep',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=375,
master_port=3302;
"
sql_delay="CHANGE MASTER TO MASTER_DELAY = 10;"
#SHOW VARIABLES LIKE 'rpl_semi_sync%';
# m-m
mysql -v -u root -e "$sql_slave2" -S /tmp/mysql1.sock
mysql -v -u root -e "$sql_slave1" -S /tmp/mysql2.sock
# slaves off first master
mysql -v -u root -e "$sql_slave1" -S /tmp/mysql3.sock
mysql -v -u root -e "$sql_slave1" -S /tmp/mysql5.sock
# slave off 2nd master
mysql -v -u root -e "$sql_slave2" -S /tmp/mysql4.sock
mysql -v -u root -e "$sql_slave2" -S /tmp/mysql6.sock
# 10 second dlay slaves
mysql -v -u root -e "$sql_delay" -S /tmp/mysql5.sock
mysql -v -u root -e "$sql_delay" -S /tmp/mysql6.sock
for i in 1 2 3 4 5 6; do
echo "show slave mysql $i"
mysql -v -u root -e "show slave status\G" -S /tmp/mysql$i.sock \
| egrep -i 'running|master_host|master_port';
done
for i in 1 2 3 4 5 6; do
echo "start slave mysql $i"
mysql -v -u root -e "start slave\G" -S /tmp/mysql$i.sock
sleep 1
done
sleep 10
for i in 1 2 3 4 5 6; do
echo "show slave mysql $i"
mysql -v -u root -e "show slave status\G" -S /tmp/mysql$i.sock \
| egrep -i 'running|master_host|master_port';
done
# mysql -v -u root -e "show slave status\G" -S /tmp/mysql1.sock
| |
Check replication
Check the replication
|
# This checks the data is on each server.
# Also test the delayed reaction.
sql="insert into test_od.hosts values ('1',now())"
mysql -v -u root -e "$sql" -S /tmp/mysql1.sock
sql="select @@server_id, host, date_insert from test_od.hosts where host = '1'
order by date_insert desc limit 1"
for i in 1 2 3 4; do
echo "server $j", `mysql -u root -e "$sql" -S /tmp/mysql$i.sock`
done
echo "The above lines should all be the same."
echo ""
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
sleep 1
for j in 1 5 6; do
echo "second $i, server $j'", `mysql -u root -e "$sql" -S /tmp/mysql$j.sock`
done
echo ""
done
echo "You should have seen a time change after 10 seconds on server 5 and 6."
| |
Other Stuff
Take backup of delayed Slave with "show master status" of the slave
and "show slave status". The backup will be compressed. There will be another
article on encryption of backups.
Now do a mysqldump backup.
mkdir -p /backups/mysql/mysql1
d=`date +%y%m%d_%H%M%S`
f=/backups/mysql/mysql1/mysql1_$d
mysqldump -u root --all-databases -S /tmp/mysql1.sock | gzip > $f.gz
Now do a Xtrabackup compressed encrypted backup.
# This is mariabdb, so we have to use mariadb-backup
apt-get install mariadb-backup
# We can use xtrrabackup or innobackupex
# If xtrabackup, you should also backup the mysql database.
mkdir -p /backups/mysql/mysql1
d=`date +%y%m%d_%H%M%S`
mariabackup --defaults-file=/data/mysql/mysql1/my.cnf \
--datadir=/data/mysql/mysql1/data \
--user=root --compress --backup \
--slave-info \
--target-dir=/backups/mysql/mysql1/mysql1_$d \
--socket=/tmp/mysql1.sock \
--compress
exclude="--exclude=gtid*,innodb*,transaction*"
S=/data/mysql/mysql1/data/mysql
D=/backups/mysql/mysql1/mysql1_$d/MYSQL_copy
mkdir -p /backups/mysql/mysql1/mysql1_$d/MYSQL_copy
rsync -av $exlude $S $D