public
Description: A simple how-to setup a MySQL master/master system
Homepage:
Clone URL: git://github.com/melo/mysql-master-master-how-to.git
melo (author)
Fri Jun 27 04:07:20 -0700 2008
commit  f9a717bbebc74c54a652db925e7cf3e49bc15656
tree    b0a71bb0495a1c73c3448339dda8418353d44cd2
parent  edf3cb9565b598ecc480120449dfe6f40a28a600
100644 373 lines (265 sloc) 15.872 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
"http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- Processed by MultiMarkdown -->
<meta name="Author" content="Pedro Melo" />
<link type="text/css" rel="stylesheet" href="css/multimarkdown.css" />
<meta name="Copyright" content="2008 Pedro Melo.
This work is licensed under a Creative Commons License.
http://creativecommons.org/licenses/by-sa/2.5/" />
<meta name="Date" content="2008-06-26" />
<meta name="Format" content="complete" />
<meta name="Keywords" content="mysql, master/master, replication" />
<title>How-to: Master/Master replication for MySQL</title>
<meta name="XMP" content="CCAttributionShareAlike" />
</head>
<body>
 
<h1 id="introduction">Introduction</h1>
 
<p>This How-To will walk you through the steps to create a MySQL master/master
setup.</p>
 
<p>Before you setup your database like this, make sure your application supports this. You should
<a href="http://dev.mysql.com/doc/refman/5.0/en/replication-faq.html#qandaitem-17-3-4-5" title="MySQL :: MySQL 5.0 Reference Manual :: 16.3.4 Replication FAQ">read this FAQ entry</a>.</p>
 
<h1 id="mastermasterreplicationpre-setup">Master/Master replication pre-setup</h1>
 
<p>This will create two mysql servers, running on the same hardware, on
ports 7001 and 7002.</p>
 
<p>To make the process easier, define these two environment variables:</p>
 
<ul>
<li><code>MY_DIR</code>: the directory where the mysql is installed, usually
<code>/usr/local/mysql</code>;</li>
<li><code>HOWTO_DIR</code>: the directory where this file is located.</li>
</ul>
 
<h2 id="schemafiles">Schema files</h2>
 
<p>I'll use the
<a href="http://www.tigase.org/" title="tigase.org | Open Source and Free (GPLv3) Jabber/XMPP environment.">Tigase</a>
<a href="http://projects.tigase.org/server/trac/browser/trunk/database/mysql-schema.sql" title="/trunk/database/mysql-schema.sql - Tigase Server - Trac">MySQL schema file
</a>
as my example schema.</p>
 
<p>The sample data I'll insert into the database, are just made up values
and probably not even valid from the point of view of Tigase.</p>
 
<h2 id="configurationfiles">Configuration files</h2>
 
<p>The two configuration files available in the <code>etc/</code> directory are based
on the <code>my-small.cnf</code> standard configuration file.</p>
 
<p>The following changes where done:</p>
 
<ul>
<li>all paths where changed to enable two MySQL servers running
simultaneously on the same hardware;</li>
<li>the <code>server-id</code> setting of each server is different: for a sucessful
replication setup, each server on the replication group must have a
different <code>server-id</code>;</li>
<li>"binlogs" are activated: they record all updates to the database;</li>
<li><code>port</code> and <code>socket</code> settings: updated to be different for each
server.</li>
</ul>
 
<p>For any MySQL command to use a specific server, you just need to
add a <code>--defaults-file=$HOWTO_DIR/etc/server-1.cnf</code> (replace 1 with 2 to work
on the second server).</p>
 
<h2 id="starttwoservers">Start two servers</h2>
 
<p>Setup the two new servers:</p>
 
<pre><code>sudo -s
mkdir -p /tmp/server-{1,2}
chown mysql:wheel /tmp/server-{1,2}
cd $MY_DIR
./scripts/mysql_install_db --defaults-file=$HOWTO_DIR/etc/server-1.cnf --user=mysql
./scripts/mysql_install_db --defaults-file=$HOWTO_DIR/etc/server-2.cnf --user=mysql
</code></pre>
 
<p>Start them up:</p>
 
<pre><code>cd $MY_DIR
./bin/mysqld_safe --defaults-file=$HOWTO_DIR/etc/server-1.cnf --user=mysql
./bin/mysqld_safe --defaults-file=$HOWTO_DIR/etc/server-2.cnf --user=mysql
</code></pre>
 
<p>At this point in time, both servers should be running. You can test by
connecting to each one:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root
mysql --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root
</code></pre>
 
<p><em>Please note</em> that this procedure did not set a <code>root</code> account password.
This means that anybody can connect as <code>root</code> to your database.</p>
 
<p>For production environments it is <strong>strongly recommended</strong> that you change
the <code>root</code> password, and delete the anonymous accounts.</p>
 
<p>For our tests purposes, we will not do that.</p>
 
<h2 id="createsampledbwithdataonserver1">Create sample db with data on server1</h2>
 
<p>On <code>server-1</code>, connect as root, and create the user used by the slave:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root &lt; $HOWTO_DIR/sql/repl_user.sql
</code></pre>
 
<p>We will also create the <code>tigasedb</code> database, and load our test schema:</p>
 
<pre><code>mysqladmin --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root create tigasedb
mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root tigasedb &lt; $HOWTO_DIR/sql/tigase-mysql-schema.sql
</code></pre>
 
<p>We should be able to see the <code>tigasedb</code> database and its tables. Lets
insert some data on them to test:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root tigasedb &lt; $HOWTO_DIR/sql/test-data-1.sql
</code></pre>
 
<h1 id="server1asmaster">Server 1 as Master</h1>
 
<p>We need to obtain the current master replication position, create a
stable snapshot of the data.</p>
 
<p>Connect as <code>root</code>:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root tigasedb
</code></pre>
 
<p>This connection must be left open for the rest of this procedure. This
is required to leave the <code>LOCK</code> in place.</p>
 
<p>Execute the following statements:</p>
 
<pre><code>FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
 
+---------------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------------------+----------+--------------+------------------+
| mysql-server-1-bin.000003 | 4514 | | |
+---------------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
</code></pre>
 
<p>This information tells you that the master position is the
<code>mysql-server-1-bin.000003</code> file at 4514.</p>
 
<p>Now create a dump of the data in the master:</p>
 
<pre><code>mysqldump --defaults-file=$HOWTO_DIR/etc/server-1.cnf \
          -u root \
          --lock-all-tables \
          tigasedb &gt; tigasedb_dump.sql
</code></pre>
 
<p>Now we need to setup the slave. First, create the <code>tigasedb</code> database and
load the SQL dump from the master:</p>
 
<pre><code>mysqladmin --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root create tigasedb
mysql --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root tigasedb &lt; tigasedb_dump.sql
</code></pre>
 
<p>You should have the same data on both servers now.</p>
 
<p>To finish the setup, you need to set the other master parameters on the
slave. Connect as <code>root</code>:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root
</code></pre>
 
<p>And setup the master link:</p>
 
<pre><code>CHANGE MASTER TO
       MASTER_HOST='127.0.0.1',
       MASTER_PORT=7001,
       MASTER_USER='repl_tig',
       MASTER_PASSWORD='pray4sync',
       MASTER_LOG_FILE='mysql-server-1-bin.000003',
       MASTER_LOG_POS=4514;
START SLAVE;
</code></pre>
 
<p>You can now end the server-1 session where the <code>LOCK</code> was created.</p>
 
<p>You should have a proper master/slave relation working between <code>server-1</code>
and <code>server-2</code>.</p>
 
<p>If you look at <code>SHOW MASTER STATUS</code> on <code>server-1</code> and compare to
<code>SHOW SLAVE STATUS\G</code> (use <code>\G</code> query terminator for a more useful layout)
on <code>server-2</code>, you should see the same <code>File</code> and <code>Position</code> on <code>server-1</code>
as <code>Master_Log_File</code> and <code>Read_Master_Log_Pos</code> on <code>server-2</code>.</p>
 
<p>To test, insert a new row in the <code>tig_user</code> table.</p>
 
<pre><code>INSERT INTO tig_users (uid, user_id) VALUES (3, 'user3');
</code></pre>
 
<p>If you <code>SELECT * FROM tig_users</code> on <code>server-2</code>, you should see the
<code>user3</code> row.</p>
 
<p>You can also re-check the <code>SHOW MASTER STATUS</code>/<code>SHOW SLAVE STATUS</code> and
compare the <code>File</code>/<code>Position</code>.</p>
 
<h1 id="server2asmaster">Server 2 as Master</h1>
 
<p>The last step is to set <code>server-2</code> as master of <code>server-1</code>.</p>
 
<h2 id="beforeweprocedesomenotes">Before we procede, some notes</h2>
 
<p>A master/master setup requires some configurations to make <code>AUTO_INCREMENT</code>
work correctly.</p>
 
<p>Our config files already include the proper <code>auto_increment_increment</code> and
<code>auto_increment_offset</code> values.</p>
 
<p>You should read:</p>
 
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_auto-increment-increment" title="MySQL :: MySQL 5.0 Reference Manual :: 5.1.3 System Variables">Explanation for <code>auto_increment_*</code> variables</a>;</li>
<li><a href="http://dev.mysql.com/doc/refman/5.0/en/replication-features-auto-increment.html" title="MySQL :: MySQL 5.0 Reference Manual :: 16.3.1.1 Replication and AUTO_INCREMENT">Notes about <code>AUTO_INCREMENT</code> and replication</a>.</li>
</ul>
 
<p>It boils down to this:</p>
 
<ul>
<li><code>auto_increment_increment</code> should be equal to the number of masters you have, <code>N</code>;</li>
<li><code>auto_increment_offset</code> should be different, from 1 to <code>N</code>, on each master.</li>
</ul>
 
<h2 id="makeserver1slavetoserver2">Make server 1 slave to server 2</h2>
 
<p>You need a replication user on <code>server-2</code>. We'll use the same one:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root &lt; $HOWTO_DIR/sql/repl_user.sql
</code></pre>
 
<p>Connect to <code>server-2</code>, lock tables and record the master position:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-2.cnf -u root tigasedb
 
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;
 
+---------------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------------------+----------+--------------+------------------+
| mysql-server-2-bin.000004 | 482 | | |
+---------------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
</code></pre>
 
<p>Then hop over to <code>server-1</code>, and connect as <code>root</code>:</p>
 
<pre><code>mysql --defaults-file=$HOWTO_DIR/etc/server-1.cnf -u root tigasedb
</code></pre>
 
<p>Make <code>server-1</code> a slave with the proper master position:</p>
 
<pre><code>CHANGE MASTER TO
       MASTER_HOST='127.0.0.1',
       MASTER_PORT=7002,
       MASTER_USER='repl_tig',
       MASTER_PASSWORD='pray4sync',
       MASTER_LOG_FILE='mysql-server-2-bin.000004',
       MASTER_LOG_POS=482;
START SLAVE;
</code></pre>
 
<p>Release the lock on <code>server-2</code>. The easiest way is just quiting the
<code>mysql</code> shell.</p>
 
<p>You should have a proper master/master relation working between <code>server-1</code>
and <code>server-2</code>.</p>
 
<p>If you look at <code>SHOW MASTER STATUS</code> on <code>server-2</code> and compare to
<code>SHOW SLAVE STATUS\G</code> (use <code>\G</code> query terminator for a more useful layout)
on <code>server-1</code>, you should see the same <code>File</code> and <code>Position</code> on <code>server-2</code>
as <code>Master_Log_File</code> and <code>Read_Master_Log_Pos</code> on <code>server-1</code>.</p>
 
<p>Do the same procedure again, but switch <code>server-1</code> with <code>server-2</code>. You
should also see equal values.</p>
 
<h2 id="finaltests">Final tests</h2>
 
<p>I recommend that you start two new connections, one to <code>server-1</code> and
the other to <code>server-2</code>.</p>
 
<p>Select, insert, update, delete from each table, and see if everything
is working.</p>
 
<p>Also try on one of the connections:</p>
 
<pre><code>CREATE TABLE test_ainc ( id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY);
</code></pre>
 
<p>And then insert rows with:</p>
 
<pre><code>INSERT INTO test_ainc VALUES (null), (null), (null);
</code></pre>
 
<p>Do this on both connections and see how the <code>AUTO_INCREMENT</code> columns
just work.</p>
 
<h1 id="finalnotes">Final Notes</h1>
 
<h2 id="innodb_flush_log_at_trx_commit">innodb_flush_log_at_trx_commit</h2>
 
<p><a href="http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/" title="Innodb Performance Optimization Basics | MySQL Performance Blog">One of the recommendations for InnoDB performance</a>
is to set <code>innodb_flush_log_at_trx_commit</code> to 2. The
<a href="http://dev.mysql.com/doc/refman/5.0/en/replication-howto-masterbaseconfig.html" title="MySQL :: MySQL 5.0 Reference Manual :: 16.1.1.2 Setting the Replication Master Configuration">MySQL documentation recommends setting to 1 as the most safe option</a>.</p>
 
<h2 id="replicate-do-db">replicate-do-db</h2>
 
<p>You could limit the replication to just the <code>tigasedb</code> database with a:</p>
 
<pre><code>replicate-do-db = tigasedb
</code></pre>
 
<p>in the configuration file, <code>mysqld</code> section.</p>
 
<p>Alternative, you could use this:</p>
 
<pre><code>replicate-ignore-db=mysql
</code></pre>
 
<p>This will replicate all the databases, except the system mysql. This is
usefull because it will replicate everything except users, passwords and
<code>GRANT</code>/<code>REVOKE</code> statements.</p>
 
<h2 id="masterconfig">master config</h2>
 
<p>You should notice that I didn't set the master host, port and other
settings on the configuration file.</p>
 
<p>The <code>CHANGE MASTER</code> command writes that information in a <code>master.info</code>
file. This file takes precedence over the configuration file.</p>
 
<h1 id="links">Links</h1>
 
<p>First, the best resource for all about replication will probably be the
<a href="http://www.highperfmysql.com/" title="High Performance MySQL &raquo; Home">High Performance MySQL (2nd. ed.) book</a>.
You should buy it.</p>
 
<p>A list of useful links:</p>
 
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.0/en/replication.html" title="MySQL :: MySQL 5.0 Reference Manual :: 16 Replication">The MySQL documentation about replication is very good</a>.
If you follow each step carefuly you should be ok;</li>
<li><a href="http://www.mysqlperformanceblog.com/" title="MySQL Performance Blog">The High-Performance MySQL site</a>
is one of the best for all things MySQL. Make sure you
<a href="http://www.mysqlperformanceblog.com/?s=replication" title="replication | MySQL Performance Blog">search for <code>replication</code></a>;</li>
<li>Browse
<a href="http://dev.mysql.com/doc/refman/5.0/en/replication-notes.html" title="MySQL :: MySQL 5.0 Reference Manual :: 16.3 Replication Notes and Tips">the Notes and Tips section</a>;</li>
<li><a href="http://www.onlamp.com/pub/a/onlamp/2006/04/20/advanced-mysql-replication.html" title="ONLamp.com -- Advanced MySQL Replication Techniques">An old article about MySQL replication at OnLamp.com</a>.
You should double-check the commands, but the graphics are pretty and usefull.</li>
</ul>
 
<p>The top hit on
<a href="http://www.google.com/search?q=master/master+replication+mysql" title="master/master replication mysql - Google Search">Google for MySQL master/master setup</a>
is a
<a href="http://www.howtoforge.com/mysql5_master_master_replication_debian_etch" title="Setting Up Master-Master Replication With MySQL 5 On Debian Etch | HowtoForge - Linux Howtos and Tutorials">how-to at HowtoForge</a>.
Personally I found it a bit dense, but that's just me.</p>
</body>
</html>