USA - Toll Free: +1-866-221-0634
USA - From abroad: +1-408-701-9009
USA - Subscription Renewals: +1-866-830-4410
Latin America: +1 512 535 7751
UK: +44 845 399 1124
Ireland: +353 1 6919191
Germany: +49 89 420 95 98 95
France: +33 1 70 38 72 00
Sweden: +46 730 207 871
Benelux: +358 50 5710 528
Italy: +39 06-99268193
Israel: +358 50 5710 528
Spain & Portugal: + 34 933905461
Other EMEA countries: +353 1 6919191
Asia Pacific: +81 3 5918 7507
Learn about new MySQL releases, technical articles, events and more.
Guilhem Bichot
Here is an answer to question on how you can handle the failure of
a single master in a circular chain of N masters using MySQL database replication. For example, if the circular chain is A -> B -> C -> D -> A and then B fails, what you can do to manually reconnect C to A as a slave.
Let's say '->' means 'is replicated by'.
A -> B
^ |
| v
D <- C
(Prior note: to set up circular replication you need to start A, B, C and D all with --log-slave-updates.) Say server ids for A,B,C,D are 1,2,3,4, respectively.
Now circular replication is running. When B fails, C will get a read error on B. C will print something like "error, will reconnect to master in 60 sec" and try to reconnect every 60 sec. Now you want to bypass dead B, i.e. make C a slave of A.
In C's binlog you can see all updates issued by clients connected to A, B, C or D. For every update in C's binlog, you can know on which machine it was originally run, thanks to 'server id'.
Example : if a client sends an UPDATE query to B,
in B's binlog there is
# server id 2 log_pos=312
UPDATE ...,
in C's binlog there is
# server id 2 log_pos=312
UPDATE ...
Example : if a client sends an UPDATE query to C,
in C's binlog there is
# server id 3 log_pos=281
UPDATE ...
Example : if a client sends an UPDATE query to D,
in A's binlog there is
# server id 4 log_pos=3145
UPDATE ...,
in B's binlog there is
# server id 4 log_pos=3145
UPDATE ...,
and in C's binlog there is
# server id 4 log_pos=3145
UPDATE ...
In other words, server ids and binlog position (unfortunately, not
binlog name) are preserved in circular replication : they are those of the originating server, the one which performed the UPDATE first, the one which received the UPDATE query from the client.
To make C a slave of A, you need to inspect C's binlog and possibly A's. As stated above, binlog names are not logged in binlogs, hence it will be easier for you if your binlogs are not rotated too often (set max_binlog_size to its default of 1 GB for example). First read C's binlog and find the latest update (INSERT, UPDATE, DELETE etc) that came from D or A (can be determined by reading 'server id'). Write down its timestamp and log_pos.
* If this latest update is from A. Determine in which of A's binlog it was (easy with the timestamp read in C's binlog).
On C do
CHANGE MASTER TO MASTER_HOST='A', MASTER_PORT='A's port',
MASTER_USER=xx, MASTER_PASSWORD=yy,
MASTER_LOG_FILE='A's_binlog_you_determined',
MASTER_LOG_POS='the_position_you_read_in_C's_binlog';
* If this latest update is from D. Read A's binlogs and determine in which of A's binlogs it was (use timestamp, server id and log_pos), write down the coordinates of this update in A's binlog. Then go back to first *.
You can see all this is entirely manual. However, it could be automated: the script would need to read C's binlog (connect to C and do SHOW BINLOG EVENTS or mysqlbinlog), get the last line whose server id is 1 or 4, then read A's or D's disk (depending on 1 or 4), determine the binlog (do 'ls' and compare with the timestamp), etc etc. This way it can be entirely automated. If I had to do it, I'd probably do it in Perl.
