MySQL 5.7 comes with a new set of features and multi-source replication is one of them. In few words this means that one slave can replicate from different masters simultaneously.
During the last couple of months I’ve been playing a lot with this trying to analyze its potential in a real case that I’ve been facing while working with a customer.
This was motivated because my customer is already using multi-sourced slaves with Tungsten Replicator and I wanted to do a side-by-side comparison between Tungsten Replicator and Multi-source Replication in MySQL 5.7

DB1 is our main master attending mostly writes from several applications, it also needs to serve read traffic which is putting it’s capacity close to the limit. It has attached 6 replication slaves using regular replication.
A1, A2, A3, B1, B2 and DB7 are reporting slaves used to offload some reads from master and also woking on some offline ETL processes.
Since they had some idle capacity customer decided to go further and set a different architecture:
A1 and B1 became also masters of other slaves using Tungsten Replicator, in this case group A is a set of servers for a statistics application and B is attending a finance application, so A2, A3 and B2 became multi sourced slaves.
New applications writes directly to A1 and B1 without impacting write capacity of main master.
Pros
Cons
With all this in mind we moved a step forward and started to test if we can move this architecture to use legacy replication only.

We added some storage capacity to DB7 for our testing purposes and the goal here is to replace all Tungsten replicated slaves by a single server where all databases are consolidated.
For some data dependency we weren’t able to completely separate A1 and B1 servers to become master-only so they are currently acting as masters of DB7 and slaves of DB1 By data dependency I mean DB1 replicates it’s schemas to all of it’s direct slaves, including DB7. DB7 also gets replication of the finance DB running locally to B1 and stats DB running locally to A1.
master_info_repository andrelay_log_info_repository variables needs to be set to TABLE
log_slave_updates needs to be disabled in A1 and B2 to avoid having duplicate data in DB7 due replication flow.Pros
Cons
sql_slave_skip_counter is a global command still which means you can’t easily skip a statement in a particular channel.It was easier than you think. First of all we needed to start from a backup of data coming from our masters. Due to versions used in production (main master is 5.5, A1 and B1 are 5.6) we started from a logical dump so we avoided to deal with mysql_upgrade issues.
Disclaimer: this does not pretend to be a guide on how to setup multi-source replication
For the matter of our case we did the backup/restore using mydumper/myloader as follow:
|
1 |
[root@db1]$ mydumper -l 600 -v 3 -t 8 --outputdir /mnt/backup_db1/20150708 --less-locking --regex="^(database1.|database2.|database3.)" <br><br>[root@a1]$ mydumper -l 600 -v 3 -t 8 --outputdir /mnt/backup_a1/20150708 --less-locking --regex="^(tungsten_stats.|stats.)" <br><br>[root@b1]$ mydumper -l 600 -v 3 -t 8 --outputdir /mnt/backup_b1/20150708 --less-locking --regex="^(tungsten_finance.|finance.)"<br> |
Notice each command was run in each master server, now the restore part:
|
1 |
[root@db7]$ myloader -d /mnt/backup_db1/20150708 -o -t 8 -q 10000 -h localhost<br><br>[root@db7]$ myloader -d /mnt/backup_a1/20150708 -o -t 8 -q 10000 -h localhost<br><br>[root@db7]$ myloader -d /mnt/backup_b1/20150708 -o -t 8 -q 10000 -h localhost<br> |
So at this point we have a new slave with a copy of databases from 3 different masters, just for context we need to dump/restore tungsten* databases because they are constantly updated by Replicator (which at this point is still in use). Pretty easy right?
Now the most important part of this whole process, setting up replication. The procedure is very similar than regular replication but now we need to consider which binlog position is necessary for each replication channel, this is very easy to get from each backup by reading in this case the metadata file created by mydumper. In known backup methods (either logical or physical) you have a way to get binlog coordinates, for example –master-data=2 in mysqldump or xtrabackup_binlog_info file in xtrabackup.
Once we get the replication info (and created a replication user in master) then we only need to run the known CHANGE MASTER TO and START SLAVE commands, but here we have our new way to do it:
|
1 |
db7:information_schema> change master to master_host='db1', master_user='rep', master_password='rep', master_log_file='db1-bin.091487', master_log_pos=74910596 FOR CHANNEL 'main_master';<br> Query OK, 0 rows affected (0.02 sec)<br>db7:information_schema> change master to master_host='a1', master_user='rep', master_password='rep', master_log_file='a1-bin.394460', master_log_pos=56004 FOR CHANNEL 'a1_slave';<br> Query OK, 0 rows affected (0.02 sec)<br>db7:information_schema> change master to master_host='b1', master_user='rep', master_password='rep', master_log_file='b1-bin.1653245', master_log_pos=2563356 FOR CHANNEL 'b1_slave';<br> Query OK, 0 rows affected (0.02 sec) |
Replication is set and now we are good to go:
|
1 |
db10:information_schema> START SLAVE FOR CHANNEL 'main_master';<br> Query OK, 0 rows affected (0.00 sec)<br>db10:information_schema> START SLAVE FOR CHANNEL 'a1_slave';<br> Query OK, 0 rows affected (0.00 sec)<br>db10:information_schema> START SLAVE FOR CHANNEL 'b1_slave';<br> Query OK, 0 rows affected (0.00 sec) |
New commands includes the FOR CHANNEL 'channel_name' option to handle replication channels independently
At this point we have a slave running 3 replication channels from different sources, we can check the status of replication with our known command SHOW SLAVE STATUS (TL;DR)
|
1 |
db10:information_schema> show slave statusG<br>*************************** 1. row ***************************<br> Slave_IO_State: Waiting for master to send event<br> Master_Host: db1<br> Master_User: rep<br> Master_Port: 3306<br> Connect_Retry: 60<br> Master_Log_File: db1-bin.077011<br> Read_Master_Log_Pos: 15688468<br> Relay_Log_File: db7-relay-main_master.000500<br> Relay_Log_Pos: 18896705<br> Relay_Master_Log_File: db1-bin.076977<br> Slave_IO_Running: Yes<br> Slave_SQL_Running: Yes<br> Replicate_Do_DB:<br> Replicate_Ignore_DB:<br> Replicate_Do_Table:<br> Replicate_Ignore_Table:<br> Replicate_Wild_Do_Table:<br> Replicate_Wild_Ignore_Table: mysql.%,temp.%<br> Last_Errno: 0<br> Last_Error:<br> Skip_Counter: 0<br> Exec_Master_Log_Pos: 18896506<br> Relay_Log_Space: 2260203264<br> Until_Condition: None<br> Until_Log_File:<br> Until_Log_Pos: 0<br> Master_SSL_Allowed: No<br> Master_SSL_CA_File:<br> Master_SSL_CA_Path:<br> Master_SSL_Cert:<br> Master_SSL_Cipher:<br> Master_SSL_Key:<br> Seconds_Behind_Master: 31047<br>Master_SSL_Verify_Server_Cert: No<br> Last_IO_Errno: 0<br> Last_IO_Error:<br> Last_SQL_Errno: 0<br> Last_SQL_Error:<br> Replicate_Ignore_Server_Ids:<br> Master_Server_Id: 1004<br> Master_UUID: 65107c0c-7ab5-11e4-a85a-bc305bf01f00<br> Master_Info_File: mysql.slave_master_info<br> SQL_Delay: 0<br> SQL_Remaining_Delay: NULL<br> Slave_SQL_Running_State: System lock<br> Master_Retry_Count: 86400<br> Master_Bind:<br> Last_IO_Error_Timestamp:<br> Last_SQL_Error_Timestamp:<br> Master_SSL_Crl:<br> Master_SSL_Crlpath:<br> Retrieved_Gtid_Set:<br> Executed_Gtid_Set:<br> Auto_Position: 0<br> Replicate_Rewrite_DB:<br> Channel_Name: main_master<br>*************************** 2. row ***************************<br> Slave_IO_State: Waiting for master to send event<br> Master_Host: a1<br> Master_User: slave<br> Master_Port: 3306<br> Connect_Retry: 60<br> Master_Log_File: a1-bin.072336<br> Read_Master_Log_Pos: 10329256<br> Relay_Log_File: db7-relay-db3_slave.000025<br> Relay_Log_Pos: 10329447<br> Relay_Master_Log_File: a1-bin.072336<br> Slave_IO_Running: Yes<br> Slave_SQL_Running: Yes<br> Replicate_Do_DB:<br> Replicate_Ignore_DB:<br> Replicate_Do_Table:<br> Replicate_Ignore_Table:<br> Replicate_Wild_Do_Table:<br> Replicate_Wild_Ignore_Table: mysql.%,temp.%<br> Last_Errno: 0<br> Last_Error:<br> Skip_Counter: 0<br> Exec_Master_Log_Pos: 10329256<br> Relay_Log_Space: 10329697<br> Until_Condition: None<br> Until_Log_File:<br> Until_Log_Pos: 0<br> Master_SSL_Allowed: No<br> Master_SSL_CA_File:<br> Master_SSL_CA_Path:<br> Master_SSL_Cert:<br> Master_SSL_Cipher:<br> Master_SSL_Key:<br> Seconds_Behind_Master: 0<br>Master_SSL_Verify_Server_Cert: No<br> Last_IO_Errno: 0<br> Last_IO_Error:<br> Last_SQL_Errno: 0<br> Last_SQL_Error:<br> Replicate_Ignore_Server_Ids:<br> Master_Server_Id: 4000<br> Master_UUID: 0f061ec4-6fad-11e4-a069-a0d3c10545b0<br> Master_Info_File: mysql.slave_master_info<br> SQL_Delay: 0<br> SQL_Remaining_Delay: NULL<br> Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates<br> Master_Retry_Count: 86400<br> Master_Bind:<br> Last_IO_Error_Timestamp:<br> Last_SQL_Error_Timestamp:<br> Master_SSL_Crl:<br> Master_SSL_Crlpath:<br> Retrieved_Gtid_Set:<br> Executed_Gtid_Set:<br> Auto_Position: 0<br> Replicate_Rewrite_DB:<br> Channel_Name: a1_slave<br>*************************** 3. row ***************************<br> Slave_IO_State: Waiting for master to send event<br> Master_Host: b1.las1.fanops.net<br> Master_User: slave<br> Master_Port: 3306<br> Connect_Retry: 60<br> Master_Log_File: b1-bin.093214<br> Read_Master_Log_Pos: 176544432<br> Relay_Log_File: db7-relay-db8_slave.000991<br> Relay_Log_Pos: 176544623<br> Relay_Master_Log_File: b1-bin.093214<br> Slave_IO_Running: Yes<br> Slave_SQL_Running: Yes<br> Replicate_Do_DB:<br> Replicate_Ignore_DB:<br> Replicate_Do_Table:<br> Replicate_Ignore_Table:<br> Replicate_Wild_Do_Table:<br> Replicate_Wild_Ignore_Table: mysql.%,temp.%<br> Last_Errno: 0<br> Last_Error:<br> Skip_Counter: 0<br> Exec_Master_Log_Pos: 176544432<br> Relay_Log_Space: 176544870<br> Until_Condition: None<br> Until_Log_File:<br> Until_Log_Pos: 0<br> Master_SSL_Allowed: No<br> Master_SSL_CA_File:<br> Master_SSL_CA_Path:<br> Master_SSL_Cert:<br> Master_SSL_Cipher:<br> Master_SSL_Key:<br> Seconds_Behind_Master: 0<br>Master_SSL_Verify_Server_Cert: No<br> Last_IO_Errno: 0<br> Last_IO_Error:<br> Last_SQL_Errno: 0<br> Last_SQL_Error:<br> Replicate_Ignore_Server_Ids:<br> Master_Server_Id: 1001<br> Master_UUID:<br> Master_Info_File: mysql.slave_master_info<br> SQL_Delay: 0<br> SQL_Remaining_Delay: NULL<br> Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates<br> Master_Retry_Count: 86400<br> Master_Bind:<br> Last_IO_Error_Timestamp:<br> Last_SQL_Error_Timestamp:<br> Master_SSL_Crl:<br> Master_SSL_Crlpath:<br> Retrieved_Gtid_Set:<br> Executed_Gtid_Set:<br> Auto_Position: 0<br> Replicate_Rewrite_DB:<br> Channel_Name: b1_slave<br>3 rows in set (0.00 sec) |
Yeah I know, output is too large and the Oracle guys noticed it, too, so they have created a set of new tables in performance_schema DB to help us retrieving this information in a friendly manner, check this link for more information. We could also run SHOW SLAVE STATUS FOR CHANNEL 'b1_slave' for instance
Conclusions
So far this new feature looks very nice and provides some extra flexibility to slaves which helps to reduce architecture complexity when we want to consolidate databases from different sources into a single server. After some time testing it I’d say that I prefer this type of replication over Tungsten Replicator in this kind of scenarios due it’s simplicity for administration, i.e. pt-table-checksum and pt-table-sync will work without proper limitations of Tungsten.
With the exception of some limitations that need to be addressed, I believe this new feature is game changing and will definitely make DBA’s life easier. I still have a lot to test still but that is material for a future post.
Resources
RELATED POSTS