Dual-master MySQL replication setup

Stephen Balukoff's picture

Greetings!

Yesterday I got the opportunity to meet Eric Sandall and have a brief conversation as we walked to and from the LUG room to reconnect the server(s) there (which I had dropped off the network a couple days ago. Heh. Heh.) Anyway, we got to geeking pretty quickly, and among other things, the subject of high-availability clustering and MySQL replication under Linux came up. I mentioned that I was using keepalived in a two-node cluster that among other things was running MySQL in a dual-master set-up. He said he didn't know how to set up MySQL this way, so I offered to make an addition to the LUG site with the procedure I followed to set it up.

I keep notes on everything I do with regard to systems administration in my job here as the Information Systems Coordinator for the College of Engineering and Architecture here at WSU. (And as a side note to all you sysadmin types-- if you aren't writing down everything you do when setting up or configuring a system, why aren't you? Having worked many sysadmin jobs, I can tell you the thing that most drives me nuts about a new environment is discovering a bunch of machines nobody knows what to do with because my predecessor couldn't be bothered to write anything down. If you want to keep your job for a long time and add more value to the company you're working for, write everything down. Yes, it takes a little more time when doing installs or maintenance, but you'll save yourself days of work when you are either forced to troubleshoot a nasty problem with your network, or required to do a 'fresh install' of some component of your network. I currently use a Subversion repository to document my systems, and am slowly moving a lot of the "higher level documentation" over to a wiki.)

Anyway, rant aside, here are the notes I took last year when setting up the MySQL dual-master relationship I use right now. Of course, you'll want to change your usernames / hostnames / passwords / etc. when setting this up for your own environment.

My environment is two machines running Fedora Core 5, one of which is a Pentium IV box, the other is an Athlon-64.

# $Id: mysql-replication 335 2005-10-13 19:46:20Z sbalukoff $
# To set up bi-directional mysql replication:

# For the purposes of this document, we have two servers which will in the
# end be filling a co-master type relationship.  However, since when you set up
# this replication there will probably be one machine with all the data on it
# that needs to be brought into sync with the other machine, the machine
# with all the data will be considered the 'master', and the one being brought
# into the relationship will be considered the 'slave'.  Again, don't let
# the names fool you:  We're only using 'master' and 'slave' here to
# differentiate the machines.  In the end they will be in a true co-master
# relationship.


# Before you begin:
#
# Make sure that /etc/my.cnf is set to have binary and relay logging turned on
# on both the slave and the master.  (Verify the log files actually exist if
# they weren't set up with this, you will need to restart the server process once
# the config file has been changed.)  Pertinent config lines should look like:
#
# # This stuff is needed for replication purposes
#   server-id=2
#   log-bin=/var/lib/mysql/master-bin.log
#   log-bin-index = /var/lib/mysql/master-log-bin.index
#   log-error = /var/lib/mysql/master-error.log
#
#   relay-log = /var/lib/mysql/slave-relay.log
#   relay-log-info-file = /var/lib/mysql/slave-relay-log.info
#   relay-log-index = /var/lib/mysql/slave-relay-log.index
#
# In the above, the master and slave must have different server-id's.

# Make sure these machines' firewalls are set up to allow them talk to each
# other on tcp port 3306, or wherever your mysql daemon is listening.

# Set up the replication user on the master:
#
sudo mysql -u root -p
mysql> GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%.cea.wsu.edu' IDENTIFIED BY 'replication_password';
mysql> GRANT REPLICATION CLIENT ON *.* TO 'replicator'@'%.cea.wsu.edu';
mysql> GRANT SUPER ON *.* TO 'replicator'@'%.cea.wsu.edu';
mysql> GRANT RELOAD ON *.* TO 'replicator'@'%.cea.wsu.edu';
mysql> GRANT SELECT ON *.* TO 'replicator'@'%.cea.wsu.edu';

# Get a clean snapshot of the master's data:
mysql> FLUSH TABLES WITH READ LOCK;
# On the shell:
sudo tar cvf /tmp/mysql.bak /var/lib/mysql
# on my mysql prompt:
mysql> SHOW MASTER STATUS;
# Take note of what is said!  You'll need to enter the log file name and position later on.
mysql> UNLOCK TABLES;


# Copy the snapshot to the slave, and slurp it into the database:
scp /tmp/mysql.bak user@slave-server:/tmp
# on the slave
sudo /etc/init.d/mysqld stop
cd /
sudo tar xvf /tmp/mysql.bak
sudo /etc/init.d/mysqld start


# Start replication from master to slave:
# on the slave's mysql command line as root:
mysql> CHANGE MASTER TO MASTER_HOST='master_host_name',
->     MASTER_USER='replicator',
->     MASTER_PASSWORD='replication_password',
->     MASTER_LOG_FILE='recorded_log_file_name',
->     MASTER_LOG_POS=recorded_log_position;

mysql> START SLAVE;


# Test the replication by creating a dummy table on the master...  it should be
# created on the slave

# On the master:
mysql> USE test;
mysql> CREATE TABLE foo (id INT);

# On the slave;
mysql> USE test;
mysql> SHOW TABLES;
# you should see the 'foo' table, eh.


# Start replication from slave to master:
# First, ensure that no updates are being made to the slave, by ensuring
# that no clients are connected to it, eh.  Do this however you see fit.
# Shutting down any local clients and adding firewall rules to prevent anyone but
# the master from connecting should do it.  Updates to the master can continue while
# you do this.

# Get the 'master' status from the slave:
# on the slave's mysql console:
mysql> SHOW MASTER STATUS;
# Make note of what you see!  Again, gonna need that logfile and position in the next step...

# Add the replication configuration to the master.
# On the master's mysql command line as root:
mysql> CHANGE MASTER TO MASTER_HOST='slave_host_name',
->     MASTER_USER='replicator',
->     MASTER_PASSWORD='replication_password',
->     MASTER_LOG_FILE='recorded_log_file_name',
->     MASTER_LOG_POS=recorded_log_position;

# Start replication on the master:
# on the master:
mysql> START SLAVE;

# Test bi-directional data flow by creating something on one server, and
# deleting it on the other, eh.  (Or just delete that 'foo' table we made
# earlier.)

# Slave:
mysql> use test;
mysql> drop table foo;

# Master:
mysql> use test;
mysql> SHOW TABLES;

# Test restarting each server individually, and then together
# to ensure there are no errors that show up in the logs when you do this.

# Be sure the check out the output of the following, on both master and slave:
mysql> SHOW SLAVE STATUS \G
# If you don't see the following in the list on both systems, you've got problems:
#   Slave_IO_Running: Yes
#   Slave_SQL_Running: Yes

# Enjoy the glow!

Other things to note:

  • As far as I've been able to tell, this relationship works across architectures: One of my masters is a 32-bit Intel Pentium IV box, the other is an Athlon-64. (I don't know, though, if say, a PPC could dual-master with an Intel chip. LSB/MSB architectural differences might break things.)
  • When upgrading your MySQL server version, be sure to read any release notes and be very careful especially when doing major version upgrades. This spring I managed to kill replication when I upgraded my machines from MySQL 4.x to MySQL 5.x. (This upgrade requires certain changes to the mysql meta-database-- which the replication system kind of choked on.) Always do a backup before you do this kind of thing. ;)
  • Be sure to periodically check out the content of the SHOW SLAVE STATUS \G command to ensure that the machines keep in synch. Reboots and long outages of one machine or the other shouldn't screw things up, but it's good to monitor this, just in case.

And... that's it. If y'all found this helpful, please let me know; I'd be happy to share some of my other notes from stuff I've done in my position here at WSU or at my former jobs. Some of the things I could talk about include:

  • Systems Administration documentation best practices
  • Linux high-availability using keepalived
  • L2TP/IPSec and PPTP VPN server set up with authentication against M$ Active Directory using open-source tools.
  • Network-to-network VPN using Linux "2.6" IPSec.
  • Network trend monitoring using Cacti (including advanced features like aggregate graphs, showing 10+ data sources on a single graph, and custom polls)
  • E-mail spam and virus filtering using amavisd-new, spamassassin and clamav (which will, sadly enough, often beat the quality of filtering WSU's getting from the Barracuda systems central IT uses.)
  • Configuring DNS, DHCP, Apache, Radius and other Linux "server" services and applications.

Anyway, feedback is appreciated, guys and gals!

Comments

lw's picture

Re: Dual-master MySQL replication setup

http://www.onlamp.com/pub/a/onlamp/2006/04/20/advanced-mysql-replication...

Talks in detail about the issues mentioned here. 

area code lookup's picture

Re: Dual-master MySQL replication setup

This is extremely interesting. My programmers and I were just discussing this for a client's site. They referred me to read this post. I'm impressed.

James

Lee Y's picture

I don't think this

I don't think this configuration is reliable in production environment. You cannot guarantee an updating operation issued on 'master' would be successfully re-executed while a conflicting one is submitted almost simutaneously on 'slave'

Stephen Balukoff's picture

You're right!

Today I got an interesting message in my inbox from Keith Freedman which made suggestions about the above tutorial which would make the set-up a lot more robust in a dual-master relationship where both masters are receiving updates from clients.

To be honest, I'd totally forgotten that I'd made this tutorial and was surprised people were still reading it and drawing on it as a source of information for doing dual-master mysql replication set-ups. (And then I noticed google currently has it as the top-listed page for those search terms. Thank you google! ;o.o )

Anyway, one thing I know I didn't make very clear in the above instructions was that for the environment I was working with at the time, I knew I would be connecting clients to a virtual IP (controlled by keepalived), and therefore there would only ever be one server in this set up receiving updates from the clients at any given time. The point of the dual-master in my case was for availability, not for performance.

Having said that, I do want to say there are couple major problems with the above tutorial if you do intend to have an environment where both masters might be receiving updates from the clients simultaneously. Kieth put it well in his e-mail so I'll just quote that here:

Stephen,

your tutorial on dual-master mysql replication is quite helpful.

you may want to also include the recommendation that people update their my.sql files and add:
auto_increment_increment=(number of servers)
auto_increment_offset=(this server number)

to address updating auto-increment problems.

also, it may be worth noting that people should write code that lets the database do the math wherever possible.
for example... a 'counter' field should do things like this:
UPDATE counter SET count=count+1 WHERE id=...;
instead of computing the new count and setting the value. this way, if it's updated on both servers simultaneously,
the count will increment correctly.
same goes for transactions that might increase/decrease a financial balance...

Also, http://day32.com/MySQL/ has a couple scripts I find invaluable.
specifucally, the 'check mysql replication status' script.
it's definitely necessary in a production environment.

Keith

In summary, if you want to avoid problems with a dual-master set up you need to:

1. Avoid creating a ticking-time bomb with autoincrement. If you don't add lines like auto_increment_increment=(number of servers) and auto_increment_offset=(this server number) eventually you'll get both servers trying to insert a row into a table with the same unique, auto_incremented field, replication will stop, and you'll have a mess to clean up when you notice it sometime after that. (And honestly, even in my set-up where I don't anticipate clients ever updating both servers simultaneously, I should have done this from the get go.)

2. Make sure your application is coded in such away that out-of-sync updates to a given field are handled gracefully. As Kieth pointed out, probably the best way to do this is to let the database do the math based on current values in the field.

I should also note that my applications currently do not use some of the more advanced features in the latest versions of MySQL (like transaction roll-backs), so I have no idea how these things might operate in a dual-master environment. As usual, YMMV. But please let us know if you *do* know how these things work in a dual-master environment.

One last note: Since I don't regularly monitor this entry, if you wish to contact me, please feel free to send an e-mail to: stephen@balukoff.com

Thanks!

-Stephen

Edmark Anthony R. Nengasca's picture

Star Like multi server set-up

Hi Stephen,

do you have configured star like configuration of multiple MYSQL server. Say i have main server as my center server and 5 slaves that access & updates the main server consequently so that all the slaves have the same data as the main server.

hope to hear from the soonest. Thank you very much.

Edmark Anthony R. Nengasca
earnengasca@yahoo.com

Stephen Balukoff's picture

I've never set up a

I've never set up a star-like configuration myself, no. Sorry!

Anonymous's picture

amazing!

i found this really intresting and hope you dont mind that i duplicated it on the http://anonet.org wiki as it is what i have been looking for.

one thing to note is that when you have the servers split apart and an update is made to a table that uses an autoincrement field the minute the servers are reconnected you'll be presented with problems

thanks
mrp

Stephen Balukoff's picture

Nope, I don't mind!  But

Nope, I don't mind!  But please do add the notes about auto_increment and intelligent coding of the client application as detailed in a comment above (however you see fit).

Anonymous's picture

totally great !!

just what i am looking for quiet sometime... it fill all the gaps im working on with out system here... it really helps..
you have mention about other server details i hoping you can post it soon.

thank a lot for sharing your good ideas....

doki rusiana
my_doki@yahoo.com
davao doctor hospital
philippines

Anonymous's picture

Wow just what I needed

This was just what I needed, now I think I can have a crack at this. It amazes me how sometimes the people who actually make these products can't show decent examples.

Any chance of reading your notes about :
Linux high-availability using keepalived

Thanks again

Tommy's picture

keepalived

where can we find the keepalived tutorial? =-)

 Thanks a lot, very helpful

Anonymous's picture

Very Useful

Thanks for that, its fillied in some of the gaps I was stumbling on.

Here here for documentation, we currently use druapl for an internal-sysadmin documentation site and its so very valuable.

sandalle's picture

Thanks Stephen (this is

Thanks Stephen (this is Eric ;))! I'll be sure to try these out on some of our extra computers as I have time (others in the LUG are welcome to play with them as well to help set this up).

hthash's picture

Very Nice

Nice info, I currently do one way mysql replication and will likely be wanting to turn that into bi-directional replication in the future, I'll be sure to check this out for refrence. Some of the other topics you mentioned that I'd be very interested in hearing about are keepalive, Linux VPNs, and advanced cacti usage.

Stephen Balukoff's picture

D'oh!

Forgot to mention: After all those GRANT commands you'll want to run a FLUSH PRIVILEGES;. (Sometimes I forget to write that sort of thing down because it's second-nature at this point. :P)

Anonymous's picture

Correction...

Just so everyone knows...you do NOT need to flush privileges when you have used GRANT.

In order to add a new user or update user's privileges in mysql grant tables login to mysql as a root user. 

There are two options: use GRANT/REVOKE command or manipulating the MySQL grant tables directly. 
The preferred method is to use GRANT statements - more concise and less error-prone.

If you modify the grant tables manually (using INSERT, UPDATE, etc.), you should execute 
a FLUSH PRIVILEGES statement to tell the server to reload the grant tables. 
Stephen Balukoff's picture

Really?  Huh...  in my

Really?  Huh...  in my experience, I've always had problems using the privileges granted using a GRANT statement until I run a flush privileges.

 

Maybe this is a bug they've fixed in more recent versions of MySQL. 

mola4ever's picture

Re: Really? Huh... in my

Grant and flush never caused me no problems, you sure you aren't the only one having this problem ? IMHO sql can cause a lot of probs. but if you figure them out then you have nothing to be affraid of.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.