How to Set Up MySQL Slave from Another Slave While Pointing to Master: Minimal Downtime Replication Strategy


3 views

When expanding MySQL replication topology, we often face a dilemma: creating new slaves from existing slaves while maintaining direct master connection. The standard approach using FLUSH TABLES WITH READ LOCK causes unacceptable downtime for busy systems.

For MySQL 5.6+ with GTID enabled, this becomes significantly easier:

# On slave B:
STOP SLAVE;
SHOW SLAVE STATUS\G
# Note Retrieved_Gtid_Set and Executed_Gtid_Set values

# Create backup without locking:
xtrabackup --backup --slave-info --target-dir=/path/to/backup
xtrabackup --prepare --target-dir=/path/to/backup

# On new slave C:
systemctl stop mysql
mv /var/lib/mysql /var/lib/mysql.old
xtrabackup --copy-back --target-dir=/path/to/backup
chown -R mysql:mysql /var/lib/mysql
systemctl start mysql

# Configure replication:
mysql> CHANGE MASTER TO
       MASTER_HOST='master_A',
       MASTER_USER='repl_user',
       MASTER_PASSWORD='password',
       MASTER_AUTO_POSITION=1;
mysql> START SLAVE;

For pre-5.6 versions or without GTID:

# On slave B:
FLUSH TABLES WITH READ LOCK;
SHOW SLAVE STATUS\G
# Note Master_Log_File and Read_Master_Log_Pos
# In another session:
xtrabackup --backup --slave-info --target-dir=/path/to/backup
UNLOCK TABLES;

# Prepare backup:
xtrabackup --prepare --target-dir=/path/to/backup

# On new slave C (same filesystem steps as above)

# Configure replication:
mysql> CHANGE MASTER TO
       MASTER_HOST='master_A',
       MASTER_USER='repl_user',
       MASTER_PASSWORD='password',
       MASTER_LOG_FILE='mysql-bin.000123',
       MASTER_LOG_POS=456789;
mysql> START SLAVE;

For automation in production environments, consider this bash script approach:

#!/bin/bash
# On slave B:
MYSQL_USER="backup_user"
MYSQL_PASS="secure_password"
BACKUP_DIR="/path/to/backup"

# Get replication info before lock
MASTER_INFO=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS\G" | grep -E "Master_Log_File|Read_Master_Log_Pos")
LOG_FILE=$(echo "$MASTER_INFO" | grep Master_Log_File | awk '{print $2}')
LOG_POS=$(echo "$MASTER_INFO" | grep Read_Master_Log_Pos | awk '{print $2}')

# Brief lock for consistency
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH TABLES WITH READ LOCK; SYSTEM /usr/bin/xtrabackup --backup --slave-info --target-dir=$BACKUP_DIR; UNLOCK TABLES;"

# Prepare backup (can be done on target server)
xtrabackup --prepare --target-dir=$BACKUP_DIR

echo "Replication coordinates for master setup:"
echo "MASTER_LOG_FILE='$LOG_FILE'"
echo "MASTER_LOG_POS=$LOG_POS"

After setup, verify replication status:

mysql> SHOW SLAVE STATUS\G
# Check for:
# Slave_IO_Running: Yes
# Slave_SQL_Running: Yes
# Seconds_Behind_Master: 0 or decreasing

When setting up MySQL replication in a multi-tier environment, a common scenario involves creating new slaves (replica C) from existing slaves (replica B) while maintaining direct master (server A) connections. The primary challenge arises when the master database is production-critical and cannot tolerate extended downtime for backup operations.

The most efficient approach combines XtraBackup with proper coordination of replication coordinates:


# On slave B (source slave):
1. Run XtraBackup without locking (use --safe-slave-backup):
   xtrabackup --backup --slave-info --safe-slave-backup --target-dir=/path/to/backup

2. Prepare the backup:
   xtrabackup --prepare --target-dir=/path/to/backup

# On new slave C:
1. Copy and restore the backup:
   rsync -avz /path/to/backup/ user@C:/var/lib/mysql/

2. Extract replication coordinates:
   cat /var/lib/mysql/xtrabackup_binlog_info
   # Output format: master-bin.000123 10785623

3. Configure replication to master A:
   CHANGE MASTER TO
     MASTER_HOST='A',
     MASTER_USER='repl_user',
     MASTER_PASSWORD='password',
     MASTER_LOG_FILE='master-bin.000123',
     MASTER_LOG_POS=10785623;

For environments where XtraBackup isn't available, consider these options:

MySQL Clone Plugin (5.7.17+)


# On slave C:
INSTALL PLUGIN clone SONAME 'mysql_clone.so';

# On slave B:
SET GLOBAL clone_valid_donor_list = 'B:3306';

# On slave C:
CLONE INSTANCE FROM 'repl_user'@'B':3306
IDENTIFIED BY 'password';

GTID-Based Replication

When using GTIDs, the process simplifies significantly:


# On slave C after restoring data:
CHANGE MASTER TO
  MASTER_HOST='A',
  MASTER_USER='repl_user',
  MASTER_PASSWORD='password',
  MASTER_AUTO_POSITION=1;
  • Use --compress with XtraBackup for large databases
  • Consider network bandwidth limitations when transferring backups
  • Monitor slave lag during initial sync
  • Adjust slave_parallel_workers for faster replication

For frequent slave creation, implement a script like:


#!/bin/bash
# Automated slave provisioning script
SOURCE_SLAVE="B"
MASTER="A"
BACKUP_DIR="/backups"
NEW_SLAVE="C"

# Create backup
ssh $SOURCE_SLAVE "xtrabackup --backup --slave-info --safe-slave-backup --stream=xbstream --target-dir=./" | \
  ssh $NEW_SLAVE "mkdir -p $BACKUP_DIR && xbstream -x -C $BACKUP_DIR"

# Prepare backup
ssh $NEW_SLAVE "xtrabackup --prepare --target-dir=$BACKUP_DIR"

# Get coordinates
COORDS=$(ssh $NEW_SLAVE "cat $BACKUP_DIR/xtrabackup_binlog_info")
BINLOG=$(echo $COORDS | awk '{print $1}')
POSITION=$(echo $COORDS | awk '{print $2}')

# Configure replication
mysql -h $NEW_SLAVE <