Go to the first, previous, next, last section, table of contents.


11 Replication in MySQL

This chapter describes the various replication features in MySQL. It serves as a reference to the options available with replication. You will be introduced to replication and learn how to implement it. Towards the end, there are some frequently asked questions and descriptions of problems and how to solve them.

11.1 Introduction

One way replication can be used is to increase both robustness and speed. For robustness you can have two systems and can switch to the backup if you have problems with the master. The extra speed is achieved by sending a part of the non-updating queries to the replica server. Of course this only works if non-updating queries dominate, but that is the normal case.

バージョン 3.23.15 から、MySQL はワンウェイ・レプリケーションを サポートしました。 1つのサーバーがマスターの役をつとめ,もう一方は、スレーブの役をつとめます。 1つのサーバーはマスターとして動くことも、他に対するスレーブとして動作することも可能です。 マスターサーバーは update のバイナリログを保持しています( 「23.4 The Binary Log」節参照.)。 また、インデックスファイルは、バイナリログのローテーションの切り出し記録を残すために保持されます。 The slave, upon connecting, informs the master where it left off since the last successfully propagated update, catches up on the updates, and then blocks and waits for the master to notify it of the new updates.

もしデータベースの複製を行なうなら、このデータベースに対する全ての更新は マスター上で行なわなくてはならないことに注意!

古いバージョンでは、単純な複製に 更新ログファイルを使用します。 「22.1 更新ログを使用したデータベースの複製」節参照.

Another benefit of using replication is that one can get live backups of the system by doing a backup on a slave instead of doing it on the master. 「22.2 データベースのバックアップ」節参照.

11.2 Replication Implementation Overview

MySQL のレプリケーションは、データベースの全ての変更(update, delete, etc)を サーバーでのバイナリログに保持し、スレーブサーバーはマスターサーバーの バイナリログから保存されているクエリを読みだし、データのコピーのために 同じクエリを実行します。

It is very important to realize that the binary log is simply a record starting from a fixed point in time (the moment you enable binary logging). マスター上でバイナリログを有効にしたその時に、 いかなるスレーブサーバーもマスターからの全てのデータのコピーが必要です。 スレーブのデータがマスターに存在するデータと違う状態でスレーブを起動したならば、 バイナリログが開始されたときに、スレーブは失敗するでしょう。

MySQL の将来のバージョン(4.0)では、新しいスレーブサーバーのために、 (できる限り、)データのスナップショットを不要にするつもりでいます。 ロックをしなくても live backyup を通してスレーブをセットアップできるように。 しかし現時点では、スナップショットを取る間は、マスターを read lock を使って全ての書き込みから保護したり、 シャットダウンしたりする必要があります。

一旦スレーブが適切に構成され、実行していれば、スレーブは単にマスターに接続して、 更新が処理されるのを待つでしょう。 もしマスターがなくなったり、または、スレーブがマスターとの接続性を失えば、 スレーブは再接続できるまで master-connect-retry 秒毎に接続を試み、 そして、更新の監視を再開します。

Each slave keeps track of where it left off. The master server has no knowledge of how many slaves there are or which ones are up-to-date at any given time.

The next section explains the master/slave setup process in more detail.

11.3 HOWTO

Below is a quick description of how to set up complete replication on your current MySQL server. It assumes you want to replicate all your databases and have not configured replication before. You will need to shutdown your master server briefly to complete the steps outlined below.

  1. マスターとスレーブに、最新の MySQL (同じバージョン) をインストールします。 バージョン 3.23.29 以上を使用すること。 これより前のバージョンでは、バイナリログのフォーマットが違い、また、新しい バージョンで直っているバグも含まれます。 最新のバージョンで確かめるまでは、バグレポートを送らないでください。
  2. マスター上に、レプリケーション用の特別なユーザーを登録します。 このユーザーには FILE 権限が必要です。全てのスレーブからこのユーザーで 接続できるようにします。 もしユーザーがレプリケーションのみ(推奨)を行なうなら、 他の権限は与える必要は有りません。 例えば、repl という名前のユーザー(マスターにアクセス可能なユーザー)を 作成するには、次のようにします:
    GRANT FILE ON *.* TO repl@"%" IDENTIFIED BY '<password>';
    
  3. マスター上の MySQL を停止。
    mysqladmin -u root -p<password> shutdown
    
  4. マスターサーバーにある全てのデータのスナップショットを取る。 (Unixでは) もっとも簡単な方法は tar を使用してデータディレクトリの アーカーブを作成することです。 The exact data directory location depends on your installation.
    tar -cvf /tmp/mysql-snapshot.tar /path/to/data-dir
    
    Windows users can use WinZip or similar software to create an archive of the data directory.
  5. マスターの my.cnf ファイル中の [mysqld] セクションに、 log-binserver-id=unique number を加えます。 ここで指定するマスターの id 番号とスレーブの id 番号は違うものでなくてはなりません。 Think of server-id as something similar to the IP address - it uniquely identifies the server instance in the community of replication partners.
    [mysqld]
    log-bin
    server-id=1
    
  6. Restart MySQL on the master.
  7. スレーブの my.cnf ファイルに、次を追加します:
    master-host=<hostname of the master>
    master-user=<replication user name>
    master-password=<replication user password>
    master-port=<TCP/IP port for master>
    server-id=<some unique number between 2 and 2^32-1>
    
    replacing the values in <> with what is relevant to your system. server-id には、サーバーそれぞれで違う番号にしなくてはなりません。 (同じ複製のグループ内で)。 もし server-id を指定しなければ、 master-host が無い場合には 1 に なり、それ以外の場合には 2 に自動的になります。 マスターで server-id の記入漏れがあった場合、 マスターはスレーブからの接続を拒否します。 スレーブ上での記入漏れの場合には、スレーブはマスターへの接続を拒否します。 Thus, omitting server-id is only good for backup with a binary log.
  8. スレーブのデータディレクトリにデータのスナップショットをコピーします。 ファイルとディレクトリのユーザーとパーミッションは確実に正しいものに してください。 これらのファイルに対して、 MySQL を実行している アカウントで、読み書きできるようにする必要があります。
  9. スレーブの再起動。

上記を行なった後、スレーブはマスターに接続し、スナップショット以後の 更新をキャッチするはずです。

もしスレーブに server-id をセットし忘れた場合、エラーログファイルに 次のようなエラーが出るでしょう:

Warning: one should set server_id to a non-0 value if master_host is set.
The server will not act as a slave.

もしマスターにセットし忘れたなら、スレーブはマスターに接続できません。

もし何かの理由でスレーブが複製できなかったなら、スレーブ上のエラーログ ファイルに、エラーメッセージが出るでしょう。

一度スレーブがレプリケーションを始めたなら、 エラーログファイルと同じディレクトリに master.info ファイルを見ることができます。 master.info ファイルはスレーブに使用され、 これは、マスターのバイナリログのいくつまで処理したかを保持しています。 このファイルを消したり編集したりしては いけません。 (あなたがやろうとしていることが確実に分かるまでは)。 そういうやむを得ない場合には、 CHANGE MASTER TO コマンドの使用の方が良いです。

11.4 Replication Features and known problems

Below is an explanation of what is supported and what is not:

11.5 Replication Options in my.cnf

レプリケーションを使用する場合は、我々は MySQL Version 3.23.30 以降を 推奨します。 これより古いバージョンでも動きますが、古い物はバグがあったり機能が無かったりします。

マスターとスレーブの両方に、 server-id オプションが必要です。 これは一意のレプリケーションid をセットします。 マスター、スレーブそれぞれのために、一意な値を、1 から 2^32-1 までの間から 選ばねばなりません。 Example: server-id=3

The following table has the options you can use for the MASTER:

Option Description
log-bin=filename Write to a binary update log to the specified location. Note that if you give it a parameter with an extension (for example, log-bin=/mysql/logs/replication.log ) versions up to 3.23.24 will not work right during replication if you do FLUSH LOGS . The problem is fixed in Version 3.23.25. If you are using this kind of log name, FLUSH LOGS will be ignored on binlog. To clear the log, run FLUSH MASTER, and do not forget to run FLUSH SLAVE on all slaves. In Version 3.23.26 and in later versions you should use RESET MASTER and RESET SLAVE
log-bin-index=filename Because the user could issue the FLUSH LOGS command, we need to know which log is currently active and which ones have been rotated out and in what sequence. この情報はバイナリログindexファイルに記述されます。 デフォルトでは `hostname`.index というファイルになります。 違う名前にしたい場合に、このオプションを使用します。 (Example: log-bin-index=db.index)
sql-bin-update-same If set, setting SQL_LOG_BIN to a value will automatically set SQL_LOG_UPDATE to the same value and vice versa.
binlog-do-db=database_name Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned. (Example: binlog-do-db=some_database)
binlog-ignore-db=database_name Tells the master that updates to the given database should not be logged to the binary log (Example: binlog-ignore-db=some_database)

The following table has the options you can use for the SLAVE:

Option Description
master-host=host Master hostname or IP address for replication. If not set, the slave thread will not be started. (Example: master-host=db-master.mycompany.com)
master-user=username The user the slave thread will us for authentication when connecting to the master. The user must have FILE privilege. If the master user is not set, user test is assumed. (Example: master-user=scott)
master-password=password The password the slave thread will authenticate with when connecting to the master. If not set, an empty password is assumed. (Example: master-password=tiger)
master-port=portnumber The port the master is listening on. If not set, the compiled setting of MYSQL_PORT is assumed. If you have not tinkered with configure options, this should be 3306. (Example: master-port=3306)
master-connect-retry=seconds The number of seconds the slave thread will sleep before retrying to connect to the master in case the master goes down or the connection is lost. Default is 60. (Example: master-connect-retry=60)
master-info-file=filename The location of the file that remembers where we left off on the master during the replication process. The default is master.info in the data directory. Sasha: The only reason I see for ever changing the default is the desire to be rebelious. (Example: master-info-file=master.info)
replicate-do-table=db_name.table_name Tells the slave thread to restrict replication to the specified database. To specify more than one table, use the directive multiple times, once for each table. . (Example: replicate-do-table=some_db.some_table)
replicate-ignore-table=db_name.table_name Tells the slave thread to not replicate to the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table.(Example: replicate-ignore-table=db_name.some_table)
replicate-wild-do-table=db_name.table_name Tells the slave thread to restrict replication to the tables that match the specified wildcard pattern. . To specify more than one table, use the directive multiple times, once for each table. . (Example: replicate-do-table=foo%.bar% will replicate only updates to tables in all databases that start with foo and whose table names start with bar)
replicate-wild-ignore-table=db_name.table_name Tells the slave thread to not replicate to the tables that match the given wild card pattern. To specify more than one table to ignore, use the directive multiple times, once for each table.(Example: replicate-ignore-table=foo%.bar% - will not upates to tables in all databases that start with foo and whose table names start with bar)
replicate-ignore-db=database_name Tells the slave thread to not replicate to the specified database. To specify more than one database to ignore, use the directive multiple times, once for each database. This option will not work if you use cross database updates. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-ignore-table=db_name.%(Example: replicate-ignore-db=some_db)
replicate-do-db=database_name Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.% (Example: replicate-do-db=some_db)
log-slave-updates スレーブスレッドからの更新をバイナリログに記録するように、スレーブに告げます。 デフォルトは Off です・ もしスレーブのデイジーチェーン(daisy-chain)を考えているならば、 これを on にする必要があります。
replicate-rewrite-db=from_name->to_name Updates to a database with a different name than the original (Example: replicate-rewrite-db=master_db_name->slave_db_name
skip-slave-start Tells the slave server not to start the slave on the startup. The user can start it later with SLAVE START.

11.6 SQL Commands Related to Replication

Replication can be controlled through the SQL interface. Below is the summary of commands:

Command Description
SLAVE START Starts the slave thread. (Slave)
SLAVE STOP Stops the slave thread. (Slave)
SET SQL_LOG_BIN=0 Disables update logging if the user has process privilege. Ignored otherwise. (Master)
SET SQL_LOG_BIN=1 Re-enables update logging if the user has process privilege. Ignored otherwise. (Master)
SET SQL_SLAVE_SKIP_COUNTER=n Skip the next n events from the master. Only valid when the slave thread is not running, otherwise, gives an error. Useful for recovering from replication glitches.
RESET MASTER Deletes all binary logs listed in the index file, resetting the binlog index file to be empty. In pre-3.23.26 versions, FLUSH MASTER (Master)
RESET SLAVE Makes the slave forget its replication position in the master logs. In pre 3.23.26 versions the command was called FLUSH SLAVE(Slave)
LOAD TABLE tblname FROM MASTER Downloads a copy of the table from master to the slave. (Slave)
CHANGE MASTER TO master_def_list Changes the master parameters to the values specified in master_def_list and restarts the slave thread. master_def_list is a comma-separated list of master_def where master_def is one of the following: MASTER_HOST, MASTER_USER, MASTER_PASSWORD, MASTER_PORT, MASTER_CONNECT_RETRY, MASTER_LOG_FILE, MASTER_LOG_POS. Example:
CHANGE MASTER TO
  MASTER_HOST='master2.mycompany.com',
  MASTER_USER='replication',
  MASTER_PASSWORD='bigs3cret',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='master2-bin.001',
  MASTER_LOG_POS=4;

You only need to specify the values that need to be changed. The values that you omit will stay the same with the exception of when you change the host or the port. In that case, the slave will assume that since you are connecting to a different host or a different port, the master is different. Therefore, the old values of log and position are not applicable anymore, and will automatically be reset to an empty string and 0, respectively (the start values). Note that if you restart the slave, it will remember its last master. If this is not desirable, you should delete the `master.info' file before restarting, and the slave will read its master from my.cnf or the command line. (Slave)
SHOW MASTER STATUS Provides status information on the binlog of the master. (Master)
SHOW SLAVE STATUS Provides status information on essential parameters of the slave thread. (Slave)
SHOW MASTER LOGS Only available starting in Version 3.23.28. Lists the binary logs on the master. You should use this command prior to PURGE MASTER LOGS TO to find out how far you should go.
PURGE MASTER LOGS TO 'logname' バージョン 3.23.28 からの機能。 index ファイルに書かれているログファイルのうち、 指定されたログよりも前のログファイルを全て消します。 index ファイルのリストからもエントリを消します。 そして、指定されたログを一番最初の物とします。 例えば:
PURGE MASTER LOGS TO 'mysql-bin.010'
(訳注: このコマンドの場合、mysql-bin.001 ~ mysql-bin.009 までの ファイルは消され、mysql.index ファイルの中身は、mysql-bin.010 のみ、 記述される状態になるということ。) This command will do nothing and fail with an error if you have an active slave that is currently reading one of the logs you are trying to delete. However, if you have a dormant slave, and happen to purge one of the logs it wants to read, the slave will be unable to replicate once it comes up. The command is safe to run while slaves are replicating - you do not need to stop them. You must first check all the slaves with SHOW SLAVE STATUS to see which log they are on, then do a listing of the logs on the master with SHOW MASTER LOGS, find the earliest log among all the slaves (if all the slaves are up to date, this will be the last log on the list), backup all the logs you are about to delete (optional) and purge up to the target log.

11.7 Replication FAQ

Q: Why do I sometimes see more than one Binlog_Dump thread on the master after I have restarted the slave?

A: Binlog_Dump is a continuous process that is handled by the server in the following way:

So if the slave thread stops on the slave, the corresponding Binlog_Dump thread on the master will not notice it until after at least one update to the master (or a kill), which is needed to wake it up from pthread_cond_wait(). In the meantime, the slave could have opened another connection, which resulted in another Binlog_Dump thread.

The above problem should not be present in Version 3.23.26 and later versions. In Version 3.23.26 we added server-id to each replication server, and now all the old zombie threads are killed on the master when a new replication thread connects from the same slave

Q: replication log をどうやってローテートするの?

A: バージョン 3.23.28 からでは、PURGE MASTER LOGS TO コマンド を使用するべきです。 実行前には、どのログが消せれるか確認し、場合によっては バックアップを取っておきます。 In earlier versions the process is much more painful, and cannot be safely done without stopping all the slaves in the case that you plan to re-use log names. You will need to stop the slave threads, edit the binary log index file, delete all the old logs, restart the master, start slave threads, and then remove the old log files.

Q: How do I upgrade on a hot replication setup?

A: If you are upgrading pre-3.23.26 versions, you should just lock the master tables, let the slave catch up, then run FLUSH MASTER on the master, and FLUSH SLAVE on the slave to reset the logs, then restart new versions of the master and the slave. Note that the slave can stay down for some time - since the master is logging all the updates, the slave will be able to catch up once it is up and can connect.

After 3.23.26, we have locked the replication protocol for modifications, so you can upgrade masters and slave on the fly to a newer 3.23 version and you can have different versions of MySQL running on the slave and the master, as long as they are both newer than 3.23.26.

Q: What issues should I be aware of when setting up two-way replication?

A: MySQL replication currently does not support any locking protocol between master and slave to guarantee the atomicity of a distributed (cross-server) update. In in other words, it is possible for client A to make an update to co-master 1, and in the meantime, before it propagates to co-master 2, client B could make an update to co-master 2 that will make the update of client A work differently than it did on co-master 1. Thus when the update of client A will make it to co-master 2, it will produce tables that will be different than what you have on co-master 1, even after all the updates from co-master 2 have also propagated. So you should not co-chain two servers in a two-way replication relationship, unless you are sure that you updates can safely happen in any order, or unless you take care of mis-ordered updates somehow in the client code.

You must also realize that two-way replication actually does not improve performance very much, if at all, as far as updates are concerned. Both servers need to do the same amount of updates each, as you would have one server do. The only difference is that there will be a little less lock contention, because the updates originating on another server will be serialized in one slave thread. This benefit, though, might be offset by network delays.

Q: How can I use replication to improve performance of my system?

A: You should set up one server as the master, and direct all writes to it, and configure as many slaves as you have the money and rackspace for, distributing the reads among the master and the slaves. You can also start the slaves with --skip-bdb, --low-priority-updates and --delay-key-write-for-all-tables to get speed improvements for the slave. In this case the slave will use non-transactional MyISAM tables instead of BDB tables to get more speed.

Q: What should I do to prepare my client code to use performance-enhancing replication?

A: If the part of your code that is responsible for database access has been properly abstracted/modularized, converting it to run with the replicated setup should be very smooth and easy - just change the implementation of your database access to read from some slave or the master, and to always write to the master. If your code does not have this level of abstraction, setting up a replicated system will give you an opportunity/motivation to it clean up. You should start by creating a wrapper library /module with the following functions:

safe_ means that the function will take care of handling all the error conditions.

You should then convert your client code to use the wrapper library. It may be a painful and scary process at first, but it will pay off in the long run. All applications that follow the above pattern will be able to take advantage of one-master/many slaves solution. The code will be a lot easier to maintain, and adding troubleshooting options will be trivial. You will just need to modify one or two functions, for example, to log how long each query took, or which query, among your many thousands, gave you an error. If you have written a lot of code already, you may want to automate the conversion task by using Monty's replace utility, which comes with the standard distribution of MySQL, or just write your own Perl script. Hopefully, your code follows some recognizable pattern. If not, then you are probably better off re-writing it anyway, or at least going through and manually beating it into a pattern.

Note that, of course, you can use different names for the functions. What is important is having unified interface for connecting for reads, connecting for writes, doing a read, and doing a write.

Q: When and how much can MySQL replication improve the performance of my system?

A: MySQL replication is most beneficial for a system with frequent reads and not so frequent writes. In theory, by using a one master/many slaves setup you can scale by adding more slaves until you either run out of network bandwidth, or your update load grows to the point that the master cannot handle it.

In order to determine how many slaves you can get before the added benefits begin to level out, and how much you can improve performance of your site, you need to know your query patterns, and empirically (by benchmarking) determine the relationship between the throughput on reads (reads per second, or max_reads) and on writes max_writes) on a typical master and a typical slave. The example below will show you a rather simplified calculation of what you can get with replication for our imagined system.

Let's say our system load consists of 10% writes and 90% reads, and we have determined that max_reads = 1200 - 2 * max_writes, or in other words, our system can do 1200 reads per second with no writes, our average write is twice as slow as average read, and the relationship is linear. Let us suppose that our master and slave are of the same capacity, and we have N slaves and 1 master. Then we have for each server (master or slave):

reads = 1200 - 2 * writes (from bencmarks)

reads = 9* writes / (N + 1) (reads split, but writes go to all servers)

9*writes/(N+1) + 2 * writes = 1200

writes = 1200/(2 + 9/(N+1)

So if N = 0, which means we have no replication, our system can handle 1200/11, about 109 writes per second (which means we will have 9 times as many reads due to the nature of our application).

If N = 1, we can get up to 184 writes per second.

If N = 8, we get up to 400.

If N = 17, 480 writes.

Eventually as N approaches infinity (and our budget negative infinity), we can get very close to 600 writes per second, increasing system throughput about 5.5 times. However, with only 8 servers, we increased it almost 4 times already.

Note that our computations assumed infinite network bandwidth, and neglected several other factors that could turn out to be significant on your system. In many cases, you may not be able to make a computation similar to the one above that will accurately predict what will happen on your system if you add N replication slaves. However, answering the following questions should help you decided whether and how much, if at all, the replication will improve the performance of your system:

Q: How can I use replication to provide redundancy/high availability?

A: With the currently available features, you would have to set up a master and a slave (or several slaves), and write a script that will monitor the master to see if it is up, and instruct your applications and the slaves of the master change in case of failure. Some suggestions:

We are currently working on integrating an automatic master election system into MySQL, but until it is ready, you will have to create your own monitoring tools.

11.8 Troubleshooting Replication

If you have followed the instructions, and your replication setup is not working, first eliminate the user error factor by checking the following:

When you have determined that there is no user error involved, and replication still either does not work at all or is unstable, it is time to start working on a bug report. We need to get as much info as possible from you to be able to track down the bug. Please do spend some time and effort preparing a good bug report. Ideally, we would like to have a test case in the format found in mysql-test/t/rpl* directory of the source tree. If you submit a test case like that, you can expect a patch within a day or two in most cases, although, of course, you mileage may vary depending on a number of factors.

Second best option is a just program with easily configurable connection arguments for the master and the slave that will demonstrate the problem on our systems. You can write one in Perl or in C, depending on which language you know better.

If you have one of the above ways to demonstrate the bug, use mysqlbug to prepare a bug report and send it to bugs@lists.mysql.com. If you have a phantom - a problem that does occur but you cannot duplicate "at will":

Once you have collected the evidence on the phantom problem, try hard to isolate it into a separate test case first. Then report the problem to bugs@lists.mysql.com with as much info as possible.


Go to the first, previous, next, last section, table of contents.