Five Pounds of Flax

Every culture has a burrito.

MySQL 5 Replication and Rails: schweet!

Saturday, March 17, 2007posted by Michael Rothwell @ 6:01 PM

I just got master-master replication working between my Mac (OS 10.4.8, MySQL 5.0.19) and one of my Linux servers (Fedora Core 4, MySQL 5.0.37).

I created a database on the Mac for rails development, and it was automatically created on the Linux server as well. I did 'rake db:migrate' on the Mac, and the schema was created on the linux side as well. Then I used the Rails console (script/console) to create a record and save it. I started up the console on the Linux server and listed all of the records, and the new one was there. I created a record on the Linux server and looked on the Mac -- both had the same two records.

Sweet!

An important thing in master-master replication is to take measures to prevent key collision. Rails apps depend on each table having an auto-increment field named "id". If you don't change your MySQL servers' auto-increment behavior, you'll get collisions: one server will allocate id #1, then the second server will try to allocate id #1, then -- boom.

Here's a two-node circular replication setup. NodeA is nodeB's slave, and vice-versa.

Node A:

[mysqld]
server-id = 10 #this should be unique across servers

auto_increment_increment = 10 #an increment value >1 is needed. set this according to # of servers

auto_increment_offset = 1 # where to start autoincrement IDs

master-host = 10.2.3.3 #other machine's address>


master-user = repluser #pre-configured 'replication' user on other server


master-password = replpass # pre-configured 'replication' user's password on other server


log-slave-updates #you need this


replicate-same-server-id = 0 # prevent looping


report-host = nodeA # this should be unique across servers


log-bin = mysql-bin #you need this

Node B:

[mysqld]

server-id = 20 #this should be unique across servers


auto_increment_increment = 10 #an increment value >1 is needed. set this according to # of servers


auto_increment_offset = 2 # where to start autoincrement IDs


master-host = 10.2.3.4 #other machine's address>


master-user = repluser #pre-configured 'replication' user on other server


master-password = replpass # pre-configured 'replication' user's password on other server


log-slave-updates #you need this


replicate-same-server-id = 0 # prevent looping


report-host = nodeB # this should be unique across servers


log-bin = mysql-bin #you need this

I've highlighted the differences between the two configurations in blue, bold text. With this setup, nodeA will create auto-increment IDs of the form: 1, 11, 21, etc., while nodeB will create auto-increment IDs of the form: 2, 12, 22, etc. This prevents key collision. Notice further that I will be limited in the number of master nodes I can add to this setup before I begin to suffer from key collisions. Additionally, increasing the increment reduces the number of records you can store in the table. With a signed INT type for the auto-increment columns, you can store 2147483647/auto_increment_increment records.

Replication copies *everything* between the servers (all databases, etc), so it is easier to start with two empty mysql configurations. You can also zero out both servers if they have been used before: delete master.info, the bin and log files, etc. The file "master.info" keeps track of where the replication has progressed, so it's important to delete it to reset replication. Keep in mind that you'll lose *all* of your data when you do this kind of "reset"!