You are here

Active/active failover cluster with MySQL Replication

Electing a slave as new master and aligning the other slaves to the new master

In a simple MySQL Replication set-up you have high-availability (HA) on the read side (r). But for the master which covers all the writes (w) and the time critical read (rt) there is no HA implemented. For some situations this can be OK. For example if you have rarely writes or if you can wait until a new Master is set up.

But in other cases you need a fast failover to a new master.

In the following article it is shown how to implement the election of a new master and how to align the slaves to the new master.

We can have two possible scenarios:

  • This scenario assumes, that every slave can become the new master.
  • This scenario assumes, that only one dedicated slave will become master.

The advantages and disadvantages of both scenarios:

Scenario 1

+ You can choose the slave which is the most actual one.

- Higher possibility of errors if not automatized.

- You do not need an extra spare slave.

- More bin log writing on all Slaves.

Scenario 2

+ You do not have to choose which is the new master, you already have defined before.

- You have the possibility to not choose the Slave with the most recent data applied.

Important: All the slaves which can become master have to run with log-bin on and log-slave-updates.

Electing a Slave to become the new master

Szenario 1

Compare output of SHOW SLAVE STATUS and decide which one will become the new master.

Szenario 2

Not necessary because it is already done before.

Aligning the other slaves to the new master

The officially recommended way to set-up again a replication when the master fails is as follows:

  • Set-up the new master (is skipped in our case because a slave becomes master).
  • Do a consistent backup of the master (which takes time and, depending on the used storage engines, blocks writing).
  • Set-up all slaves one by one and point them to the new master (takes also time).

During these steps your production environment provides partially limited resources.

To avoid or at least reduce this problem we are looking for an abbreviation of the whole process:

Step 1: is obsolete in our scenario.

Step 2: Can be circumvented when we use a storage engine which allows us to make consistent backups (for example InnoDB) or when we use a very fast backup method (for example LVM snapshots).

Step 3: We can re-use all the slaves which have the same or older information than the new elected master. Slaves which have newer informations or in some other exceptional cases (see below) have to be set-up anyway as recommended.

How to do this?

IMHO the best is to show that in a little demo. For this I have set-up a environment like in scenario 1) and/or 2). There I have created my favorite table test as follows:

SQL> CREATE TABLE test (
  `id` int(11) NOT NULL AUTO_INCREMENT
, `data` varchar(32) DEFAULT NULL
, `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
, PRIMARY KEY (`id`)
);

As next step we simulate the application as follows:

SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);
SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);
SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);

To simulate a lag on one or more of the slaves we stop the replication on these:

SQL> STOP SLAVE;

Then we do some more application action on the master:

SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);
SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);

And then we crash the master!

From this point on we have the situation which could happen in the real world: Master is crashed and different slaves (can) have different positions relatively to the master:

Find the most actual slave

To find the slave which is the most actual one you have to gather some information on the slaves. This can be done as follows:

SQL> PAGER grep Master_Log;
SQL> SHOW SLAVE STATUS\G
SQL> PAGER ;

You also have to do this step in scenario b) because we want to know which slave can be taken and which one has to be set-up from scratch.

Then we get some output for example like this:

Slave 1:

      Master_Log_File: bin-3311.000006
  Read_Master_Log_Pos: 929
Relay_Master_Log_File: bin-3311.000006
  Exec_Master_Log_Pos: 929

Slave 2:

      Master_Log_File: bin-3311.000006
  Read_Master_Log_Pos: 635
Relay_Master_Log_File: bin-3311.000006
  Exec_Master_Log_Pos: 635

What we have to assure first is, that all the slave have caught up with writing the data from the relay log to slave. This is assured by comparing Master_Log_file / Read_Master_Log_Pos with Relay_Master_Log_file / Exec_Master_Log_Pos. If these values are the same then the slave has caught-up. Otherwise wait until they become the same.

When this is done we have to find, which slave is the most recent one. This is simple: Higher value is equal to newer information (also consider the log file not only the position!).

In scenario a) the one (or one of these) is elected as new master.

In our scenario this is Slave 1!

In scenario 2 all slaves which are newer than the pre-elected new master must be rebuild from the new master.

Slave 1 is newer than slave 2. If slave 2 was pre-elected as new master slave one must be rebuild from the new master.

From all the slaves which have a different position than the new master calculate the delta to the new master:

Calculate delta: 6.929 - 6.635 = 294

When the log file is different we cannot use these informations and we have to rebuild this slave from the new master.

Now we have defined, which one will become the new master and which slaves are in line, which are ahead and which are behind the new master.

Set-up the new environment

To avoid any troubles we to a STOP SLAVE on all slaves first.

Then we do a RESET SLAVE on the new master.

Now for every slave which is not rebuild from the master we have to calculate the position where to start the replication from. To do this we have to gather the actual position of the new master:

SQL> SHOW MASTER STATUS;
+-----------------+----------+--------------+------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-----------------+----------+--------------+------------------+
| bin-3312.000002 |     2857 |              |                  |
+-----------------+----------+--------------+------------------+

And for every slave we can calculate the delta:

==> 2857 - 294 = 2563

When the value becomes negative this means that we have to start in an older log-file than the actual one. I did not find any rule to calculate the exact position in this case. So unfortunately we also have to set-up these slaves from the backup.

As soon as we have these values calculated we can start the application running against the new master and we can also start now with the new consistent backup for all the slaves we have to set-up again from the backup.

SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);
SQL> INSERT INTO TEST VALUES (NULL, 'Insert on Master', NULL);

On the slaves which are OK for aligning with the new master we have to change the master and the new positions now:

SQL> CHANGE MASTER TO MASTER_HOST='laptop', MASTER_USER='replication'
       , MASTER_PORT=3312, MASTER_PASSWORD='replication';
SQL> CHANGE MASTER TO MASTER_LOG_FILE='bin-3312.000002', master_log_pos=2563;
SQL> START SLAVE;

That's it!

If you would like to here more about such stuff please let me know. We are glad to help you with some consulting...

I have also most of this stuff in some scripts so this could be easily automated...

Comments

[http://www.blogger.com/profile/13990877688502800403 Sheeri K. Cabral] said... You could probably very easily put this all into a lua script, slap MySQL Proxy in front of it, and have automated failover -- if it can't reach the 1st backend, pick among the other backends by doing a query, promote it, etc.
Sheeri K. Cabralcomment