Personal tools
You are here: Home Docs MySQL Cluster Excerpt 5.1 Chapter 9. MySQL Cluster Replication

Chapter 9. MySQL Cluster Replication

Chapter 9. MySQL Cluster Replication

Previous to MySQL 5.1.6, asynchronous replication, more usually referred to simply as “replication”, was not available when using MySQL Cluster. MySQL 5.1.6 introduces master-slave replication of this type for MySQL Cluster databases. This section explains how to set up and manage a configuration wherein one group of computers operating as a MySQL Cluster replicates to a second computer or group of computers. We assume some familiarity on the part of the reader with standard MySQL replication as discussed elsewhere in this Manual. (See Replication).

Normal (nonclustered) replication involves a “master” server and a “slave” server, the master being the source of the operations and data to be replicated and the slave being the recipient of these. In MySQL Cluster, replication is conceptually very similar but can be more complex in practice, as it may be extended to cover a number of different configurations including replicating between two complete clusters. Although a MySQL Cluster itself depends on the NDBCLUSTER storage engine for clustering functionality, it is not necessary to use the Cluster storage engine on the slave. However, for maximum availability, it is possible to replicate from one MySQL Cluster to another, and it is this type of configuration that we discuss, as shown in the following figure:

MySQL Cluster-to-Cluster Replication
      Layout

In this scenario, the replication process is one in which successive states of a master cluster are logged and saved to a slave cluster. This process is accomplished by a special thread known as the NDB binlog injector thread, which runs on each MySQL server and produces a binary log (binlog). This thread ensures that all changes in the cluster producing the binary log — and not just those changes that are effected via the MySQL Server — are inserted into the binary log with the correct serialization order. We refer to the MySQL replication master and replication slave servers as replication servers or replication nodes, and the data flow or line of communication between them as a replication channel.

9.1. MySQL Cluster Replication — Abbreviations and Symbols

Throughout this section, we use the following abbreviations or symbols for referring to the master and slave clusters, and to processes and commands run on the clusters or cluster nodes:

Symbol or AbbreviationDescription (Refers to...)
MThe cluster serving as the (primary) replication master
SThe cluster acting as the (primary) replication slave
shellM>Shell command to be issued on the master cluster
mysqlM>MySQL client command issued on a single MySQL server running as an SQL node on the master cluster
mysqlM*>MySQL client command to be issued on all SQL nodes participating in the replication master cluster
shellS>Shell command to be issued on the slave cluster
mysqlS>MySQL client command issued on a single MySQL server running as an SQL node on the slave cluster
mysqlS*>MySQL client command to be issued on all SQL nodes participating in the replication slave cluster
CPrimary replication channel
C'Secondary replication channel
M'Secondary replication master
S'Secondary replication slave

9.2. MySQL Cluster Replication — Assumptions and General Requirements

A replication channel requires two MySQL servers acting as replication servers (one each for the master and slave). For example, this means that in the case of a replication setup with two replication channels (to provide an extra channel for redundancy), there will be a total of four replication nodes, two per cluster.

Replication of a MySQL Cluster as described in this section and those following is dependent on row-based replication. This means that the replication master MySQL server must be started with --binlog-format=ROW or --binlog-format=MIXED, as described in Section 9.6, “Starting MySQL Cluster Replication (Single Replication Channel)”. For general information about row-based replication, see Replication Formats.

Important

If you attempt to use MySQL Cluster Replication with --binlog-format=STATEMENT, replication fails to work properly because the ndb_binlog_index table on the master and the epoch column of the ndb_apply_status table on the slave are not updated (see Section 9.4, “MySQL Cluster Replication Schema and Tables”). Instead, only updates on the MySQL server acting as the replication master propagate to the slave, and no updates from any other SQL nodes on the master cluster are replicated.

In all MySQL Cluster NDB 6.x releases, the default value for the --binlog-format option is MIXED.

Each MySQL server used for replication in either cluster must be uniquely identified among all the MySQL replication servers participating in either cluster (you cannot have replication servers on both the master and slave clusters sharing the same ID). This can be done by starting each SQL node using the --server-id=id option, where id is a unique integer. Although it is not strictly necessary, we will assume for purposes of this discussion that all MySQL installations are the same version.

In any event, both MySQL servers involved in replication must be compatible with one another with respect to both the version of the replication protocol used and the SQL feature sets which they support; the simplest and easiest way to assure that this is the case is to use the same MySQL version for all servers involved. Note that in many cases it is not possible to replicate to a slave running a version of MySQL with a lower version number than that of the master — see Replication Compatibility Between MySQL Versions, for details.

We assume that the slave server or cluster is dedicated to replication of the master, and that no other data is being stored on it.

Note

It is possible to replicate a MySQL Cluster using statement-based replication. However, in this case, the following restrictions apply:

  • All updates to data rows on the cluster acting as the master must be directed to a single MySQL server.

  • It is not possible to replicate a cluster using multiple simultaneous MySQL replication processes.

  • Only changes made at the SQL level are replicated.

These are in addition to the other limitations of statement-based replication as opposed to row-based replication; see Comparison of Statement-Based and Row-Based Replication, for more specific information concerning the differences between the two replication formats.

9.3. Known Issues in MySQL Cluster Replication

The following are known problems or issues when using replication with MySQL Cluster in MySQL 5.1:

  • Loss of master-slave connection.  Prior to MySQL 5.1.18, a MySQL Cluster replication slave mysqld had no way of detecting that the connection from the master had been interrupted (due to, for instance, the master going down or a network failure). For this reason, it was possible for the slave to become inconsistent with the master.

    Beginning with MySQL 5.1.18, the master issues a “gap” event when connecting to the cluster. When the slave encounters a gap in the replication log, it stops with an error message. This message is available in the output of SHOW SLAVE STATUS, and indicates that the SQL thread has stopped due to an incident registered in the replication stream, and that manual intervention is required. In order to restart the slave, it is necessary to issue the following commands:

    SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
    START SLAVE;
    

    The slave then resumes reading the master binlog from the point where the gap was recorded.

    Important

    If high availability is a requirement for the slave server or cluster, then it is still advisable to set up multiple replication lines, to monitor the master mysqld on the primary replication line, and to fail over to a secondary line if and as necessary. For information about implementing this type of setup, see Section 9.7, “Using Two Replication Channels for MySQL Cluster Replication”, and Section 9.8, “Implementing Failover with MySQL Cluster Replication”.

    However, if you are replicating from a standalone MySQL server to a MySQL Cluster, one channel is usually sufficient.

  • Multi-byte character sets.  There are several known issues with regard to the use of multi-byte characters sets with MySQL Cluster Replication. See Bug#27404 (fixed in MySQL 5.1.21), Bug#29562, Bug#29563, and Bug#29564 for more information.

  • Circular replication.  Prior to MySQL 5.1.18, circular replication was not supported with MySQL Cluster replication, due to the fact that all log events created in a particular MySQL Cluster were wrongly tagged with the server ID of the MySQL server used as master and not with the server ID of the originating server.

    Beginning with MySQL 5.1.18, this limitation is lifted, as discussed in the next few paragraphs, in which we consider the example of a replication setup involving three MySQL Clusters numbered 1, 2, and 3, in which Cluster 1 acts as the replication master for Cluster 2, Cluster 2 acts as the master for Cluster 3, and Cluster 3 acts as the master for Cluster 1. Each cluster has two SQL nodes, with SQL nodes A and B belonging to Cluster 1, SQL nodes C and D belonging to Cluster 2, and SQL nodes E and F belonging to Cluster 3.

    Circular replication using these clusters is supported as long as:

    • The SQL nodes on all masters and slaves are the same

    • All SQL nodes acting as replication masters and slaves are started using the --log-slave-updates option

    This type of circular replication setup is shown in the following diagram:

    Cluster circular replication scheme in
              which all master SQL nodes are also slaves.

    In this scenario, SQL node A in Cluster 1 replicates to SQL node C in Cluster 2; SQL node C replicates to SQL node E in Cluster 3; SQL node E replicates to SQL node A. In other words, the replication line (indicated by the red arrows in the diagram) directly connects all SQL nodes used as replication masters and slaves.

    It should also be possible to set up circular replication in which not all master SQL nodes are also slaves, as shown here:

    Cluster circular replication scheme in
              which all master SQL nodes are not also necessarily
              slaves.

    In this case, different SQL nodes in each cluster are used as replication masters and slaves. However, you must not start any of the SQL nodes using --log-slave-updates (see the description of this option for more information). This type of circular replication scheme for MySQL Cluster, in which the line of replication (again indicated by the red arrows in the diagram) is discontinuous, should be possible, but it should be noted that it has not yet been thoroughly tested and must therefore still be considered experimental.

    Important

    Beginning with MySQL 5.1.24, you should execute the following statement before starting circular replication:

    mysql> SET GLOBAL slave_exec_mode = 'IDEMPOTENT';
    

    This is necessary to suppress duplicate-key and other errors that otherwise break circular replication of MySQL Cluster. IDEMPOTENT mode is also required for multi-master replication when using MySQL Cluster. (Bug#31609)

    See slave_exec_mode, for more information.

  • DDL statements.  The use of data definition statements, such as CREATE TABLE, DROP TABLE, and ALTER TABLE, are recorded in the binary log for only the MySQL server on which they are issued.

  • Cluster replication and primary keys.  In MySQL 5.1.6, only those NDB tables having explicit primary keys could be replicated. This limitation was lifted in MySQL 5.1.7. However, in the event of a node failure, errors in replication of NDB tables without primary keys can still occur, due to the possibility of duplicate rows being inserted in such cases. For this reason, it is highly recommended that all NDB tables being replicated have primary keys.

  • Restarting with --initial Restarting the cluster with the --initial option causes the sequence of GCI and epoch numbers to start over from 0. (This is generally true of MySQL Cluster and not limited to replication scenarios involving Cluster.) The MySQL servers involved in replication should in this case be restarted. After this, you should use the RESET MASTER and RESET SLAVE statements to clear the invalid ndb_binlog_index and ndb_apply_status tables. respectively.

  • auto_increment_offset and auto_increment_increment variables.  The use of the auto_increment_offset and auto_increment_increment server system variables is supported beginning with MySQL 5.1.20. Previously, these produced unpredictable results when used with NDB tables or MySQL Cluster replication.

  • Replication from NDBCLUSTER to other storage engines.  If you attempt to replicate from a MySQL Cluster to a slave that uses a storage engine that does not handle its own binary logging, the replication process aborts with the error Binary logging not possible ... Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging (Error 1595). It is possible to work around this issue in one of the following ways:

    • Turn off binary logging on the slave.  This can be accomplished by setting sql_log_bin = 0.

    • Change the storage engine used for the mysql.ndb_apply_status table.  Causing this table to use an engine that does not handle its own binary logging can also eliminate the conflict. This can be done by issuing a statement such as ALTER TABLE mysql.ndb_apply_status ENGINE=MyISAM on the slave. It is safe to do this when using a non-NDB storage engine on the slave, since you do not then need to worry about keeping multiple slave SQL nodes synchronized.

    • Filter out changes to the mysql.ndb_apply_status table on the slave.  This can be done by starting the slave SQL node with the option --replicate-ignore-table=mysql.ndb_apply_status. If you need for other tables to be ignored by replication, you might wish to use an appropriate --replicate-wild-ignore-table option instead.

    Important

    You should not disable replication or binary logging of mysql.ndb_apply_status or change the storage engine used for this table when replicating from one MySQL Cluster to another. See Replication and binary log filtering rules with replication between MySQL Clusters elsewhere in this section for details.

    When replicating from NDBCLUSTER to a nontransactional storage engine such as MyISAM, you may encounter unnecessary duplicate key errors when replicating INSERT ... ON DUPLICATE KEY UPDATE statements. You can suppress these in MySQL Cluster NDB 6.2 by using --ndb-log-update-as-write=0, which forces all columns from updated rows to be sent (and not just those that were updated). For MySQL Cluster NDB 6.3.3 and later, there are additional way to determine whether or not an update to the row on the master should be applied on the slave mysqld; see Section 9.11, “MySQL Cluster Replication Conflict Resolution”, for more information about these methods.

  • Replication and binary log filtering rules with replication between MySQL Clusters.  If you are using any of the options --replicate-do-*, --replicate-ignore-*, --binlog-do-db, or --binlog-ignore-db to filter databases or tables being replicated, care must be taken not to block replication or binary logging of the mysql.ndb_apply_status, which is required for replication between MySQL Clusters to operate properly. In particular, you must keep in mind the following:

    1. Using --replicate-do-db=db_name (and no other --replicate-do-* or --replicate-ignore-* options) means that only tables in database db_name are replicated. In this case, you should also use --replicate-do-db=mysql, --binlog-do-db=mysql, or --replicate-do-table=mysql.ndb_apply_status to insure that mysql.ndb_apply_status is populated on slaves.

      Using --binlog-do-db=db_name (and no other --binlog-do-db options) means that changes only to tables in database db_name are written to the binary log. In this case, you should also use --replicate-do-db=mysql, --binlog-do-db=mysql, or --replicate-do-table=mysql.ndb_apply_status to insure that mysql.ndb_apply_status is populated on slaves.

    2. Using --replicate-ignore-db=mysql means that no tables in the mysql database are replicated. In this case, you should also use --replicate-do-table=mysql.ndb_apply_status to insure that mysql.ndb_apply_status is replicated.

      Using --binlog-ignore-db=mysql means that no changes to tables in the mysql database are written to the binary log. In this case, you should also use --replicate-do-table=mysql.ndb_apply_status to insure that mysql.ndb_apply_status is replicated.

    You should also remember that:

    1. Each replication filtering rule requires its own --replicate-do-* or --replicate-ignore-* option, and that multiple rules cannot be expressed in a single replication filtering option. For information about these rules, see Replication and Binary Logging Options and Variables.

    2. Each binary log filtering rule requires its own --binlog-do-db or --binlog-ignore-db option, and that multiple rules cannot be expressed in a single binary log filtering option. For information about these rules, see The Binary Log.

    Note

    If you are replicating a MySQL Cluster to a slave that uses a storage engine other than NDBCLUSTER, the considerations just given previously may not apply. See Replication from NDBCLUSTER to other storage engines elsewhere in this section for details.

  • MySQL Cluster Replication and IPv6.  Currently, the NDB API and MGM API do not support IPv6. However, beginning with MySQL Cluster NDB 6.4.1, MySQL Servers — including those acting as SQL nodes in a MySQL Cluster — can use IPv6 to contact other MySQL Servers. This means that you can replicate between MySQL Clusters using IPv6 to connect the master and slave SQL nodes as shown by the dotted arrow in the following diagram:

    IPv6 Used to Connect Between MySQL
                Cluster SQL Nodes in Replication

    However, all connections originating within the MySQL Cluster — shown in the diagram by solid arrows — must use IPv4.

    All MySQL Cluster data nodes, management servers, and management clients must be accessible from one another using IPv4. In addition, SQL nodes must use IPv4 to communicate with the cluster. There is not currently any support in the NDB and MGM APIs for IPv6, which means that any applications written using these APIs must also make all connections using IPv4.

9.4. MySQL Cluster Replication Schema and Tables

Replication in MySQL Cluster makes use of a number of dedicated tables in the mysql database on each MySQL Server instance acting as an SQL node in both the cluster being replicated and the replication slave (whether the slave is a single server or a cluster). These tables are created during the MySQL installation process by the mysql_install_db script, and include a table for storing the binary log's indexing data. Since the ndb_binlog_index table is local to each MySQL server and does not participate in clustering, it uses the MyISAM storage engine. This means that it must be created separately on each mysqld participating in the master cluster. (However, the binlog itself contains updates from all MySQL servers in the cluster to be replicated.) This table is defined as follows:

CREATE TABLE `ndb_binlog_index` (
    `Position`  BIGINT(20) UNSIGNED NOT NULL,
    `File`      VARCHAR(255) NOT NULL,
    `epoch`     BIGINT(20) UNSIGNED NOT NULL,
    `inserts`   BIGINT(20) UNSIGNED NOT NULL,
    `updates`   BIGINT(20) UNSIGNED NOT NULL,
    `deletes`   BIGINT(20) UNSIGNED NOT NULL,
    `schemaops` BIGINT(20) UNSIGNED NOT NULL,
    PRIMARY KEY (`epoch`)
) ENGINE=MYISAM  DEFAULT CHARSET=latin1;

Important

Prior to MySQL 5.1.14, the ndb_binlog_index table was known as binlog_index, and was kept in a separate cluster database, which in MySQL 5.1.7 and earlier was known as the cluster_replication database. Similarly, the ndb_apply_status and ndb_schema tables were known as apply_status and schema, and were also found in the cluster (earlier cluster_replication) database. However, beginning with MySQL 5.1.14, all MySQL Cluster replication tables reside in the mysql system database.

Information about how this change affects upgrades from MySQL Cluster 5.1.13 and earlier to 5.1.14 and later versions can be found in Changes in MySQL 5.1.14.

Beginning with MySQL Cluster NDB 6.3.2, this table has been changed to facilitate 3-way replication recovery. Two columns orig_server_id and orig_epoch have been added to this table; when mysqld is started with the --ndb-log-orig option, these columns store, respectively, the ID of the server on which the event originated and the epoch in which the event took place on the originating server. In addition, the table's primary key now includes these two columns. The modified table definition is shown here:

CREATE TABLE `ndb_binlog_index` (
    `Position` BIGINT(20) UNSIGNED NOT NULL,
    `File` VARCHAR(255) NOT NULL,
    `epoch` BIGINT(20) UNSIGNED NOT NULL,
    `inserts` INT(10) UNSIGNED NOT NULL,
    `updates` INT(10) UNSIGNED NOT NULL,
    `deletes` INT(10) UNSIGNED NOT NULL,
    `schemaops` INT(10) UNSIGNED NOT NULL,
    `orig_server_id` INT(10) UNSIGNED NOT NULL,
    `orig_epoch` BIGINT(20) UNSIGNED NOT NULL,
    `gci` INT(10) UNSIGNED NOT NULL,
    PRIMARY KEY (`epoch`,`orig_server_id`,`orig_epoch`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

The gci column was added in MySQL Cluster NDB 6.2.6 and MySQL Cluster NDB 6.3.2.

The following figure shows the relationship of the MySQL Cluster replication master server, its binlog injector thread, and the mysql.ndb_binlog_index table.

The replication master cluster, the
        binlog-injector thread, and the
        ndb_binlog_index table

An additional table, named ndb_apply_status, is used to keep a record of the operations that have been replicated from the master to the slave. Unlike the case with ndb_binlog_index, the data in this table is not specific to any one SQL node in the (slave) cluster, and so ndb_apply_status can use the NDB Cluster storage engine, as shown here:

CREATE TABLE `ndb_apply_status` (
    `server_id`   INT(10) UNSIGNED NOT NULL,
    `epoch`       BIGINT(20) UNSIGNED NOT NULL,
    `log_name`    VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
    `start_pos`   BIGINT(20) UNSIGNED NOT NULL,
    `end_pos`     BIGINT(20) UNSIGNED NOT NULL,
    PRIMARY KEY (`server_id`) USING HASH
) ENGINE=NDBCLUSTER   DEFAULT CHARSET=latin1;

This table is populated only on slaves; on the master, no DataMemory is allocated to it. However, the table is populated from the master. For this reason, this table must be replicated and any replication filtering or binary log filtering rules that prevent this prevent replication between clusters from operating properly. For more information about potential problems arising from such filtering rules, see Section 9.3, “Known Issues in MySQL Cluster Replication”.

The log_name, start_pos, and end_pos columns were added in MySQL 5.1.18.

Important

If you are using MySQL Cluster replication, see Section 5.2, “MySQL Cluster 5.1 and MySQL Cluster NDB 6.x/7.x Upgrade and Downgrade Compatibility” before upgrading to MySQL 5.1.18 or later from an earlier version.

The ndb_binlog_index and ndb_apply_status tables are created in the mysql database because they should not be replicated. No user intervention is normally required to create or maintain either of them. Both the ndb_binlog_index and the ndb_apply_status tables are maintained by the NDB injector thread. This keeps the master mysqld process updated to changes performed by the NDB storage engine. The NDB binlog injector thread receives events directly from the NDB storage engine. The NDB injector is responsible for capturing all the data events within the cluster, and ensures that all events which change, insert, or delete data are recorded in the ndb_binlog_index table. The slave I/O thread transfers the events from the master's binary log to the slave's relay log.

However, it is advisable to check for the existence and integrity of these tables as an initial step in preparing a MySQL Cluster for replication. It is possible to view event data recorded in the binary log by querying the mysql.ndb_binlog_index table directly on the master. This can be also be accomplished using the SHOW BINLOG EVENTS statement on either the replication master or slave MySQL servers. (See SHOW BINLOG EVENTS Syntax.)

You can also obtain useful information from the output of SHOW ENGINE NDB STATUS.

The ndb_schema table is used to track schema changes made to NDB tables. It is defined as shown here:

CREATE TABLE ndb_schema (
    `db` VARBINARY(63) NOT NULL,
    `name` VARBINARY(63) NOT NULL,
    `slock` BINARY(32) NOT NULL,
    `query` BLOB NOT NULL,
    `node_id` INT UNSIGNED NOT NULL,
    `epoch` BIGINT UNSIGNED NOT NULL,
    `id` INT UNSIGNED NOT NULL,
    `version` INT UNSIGNED NOT NULL,
    `type` INT UNSIGNED NOT NULL,
    PRIMARY KEY USING HASH (db,name)
) ENGINE=NDB   DEFAULT CHARSET=latin1;

Unlike the two tables previously mentioned in this section, the ndb_schema table is not visible either to MySQL SHOW statements, or in any INFORMATION_SCHEMA tables; however, it can be seen in the output of ndb_show_tables, as shown here:

shell> ndb_show_tables -t 2
id    type                 state    logging database     schema   name
4     UserTable            Online   Yes     mysql        def      ndb_apply_status
5     UserTable            Online   Yes     ndbworld     def      City
6     UserTable            Online   Yes     ndbworld     def      Country
3     UserTable            Online   Yes     mysql        def      NDB$BLOB_2_3
7     UserTable            Online   Yes     ndbworld     def      CountryLanguage
2     UserTable            Online   Yes     mysql        def      ndb_schema
NDBT_ProgramExit: 0 - OK

It is also possible to SELECT from this table in mysql and other MySQL client applications, as shown here:

mysql> SELECT * FROM mysql.ndb_schema WHERE name='City' \G
*************************** 1. row ***************************
     db: ndbworld
   name: City
  slock:
  query: alter table City engine=ndb
node_id: 4
  epoch: 0
     id: 0
version: 0
   type: 7
1 row in set (0.00 sec)

This can sometimes be useful when debugging applications.

Note

When performing schema changes on NDB tables, applications should wait until the ALTER TABLE statement has returned in the MySQL client connection that issued the statement before attempting to use the updated definition of the table.

The ndb_schema table was added in MySQL 5.1.8.

Beginning with MySQL 5.1.14, if either of the ndb_apply_status or ndb_schema tables does not exist on the slave, it is created by ndb_restore. (Bug#14612)

Conflict resolution for MySQL Cluster Replication requires the presence of an additional mysql.ndb_replication table. Currently, this table must be created manually. For details, see Section 9.11, “MySQL Cluster Replication Conflict Resolution”.

9.5. Preparing the MySQL Cluster for Replication

Preparing the MySQL Cluster for replication consists of the following steps:

  1. Check all MySQL servers for version compatibility (see Section 9.2, “MySQL Cluster Replication — Assumptions and General Requirements”).

  2. Create a slave account on the master Cluster with the appropriate privileges:

    mysqlM> GRANT REPLICATION SLAVE
         -> ON *.* TO 'slave_user'@'slave_host'
         -> IDENTIFIED BY 'slave_password';
    

    In the previous statement, slave_user is the slave account user name, slave_host is the host name or IP address of the replication slave, and slave_password is the password to assign to this account.

    For example, to create a slave user account with the name “myslave,” logging in from the host named “rep-slave,” and using the password “53cr37,” use the following GRANT statement:

    mysqlM> GRANT REPLICATION SLAVE
         -> ON *.* TO 'myslave'@'rep-slave'
         -> IDENTIFIED BY '53cr37';
    

    For security reasons, it is preferable to use a unique user account — not employed for any other purpose — for the replication slave account.

  3. Configure the slave to use the master. Using the MySQL Monitor, this can be accomplished with the CHANGE MASTER TO statement:

    mysqlS> CHANGE MASTER TO
         -> MASTER_HOST='master_host',
         -> MASTER_PORT=master_port,
         -> MASTER_USER='slave_user',
         -> MASTER_PASSWORD='slave_password';
    

    In the previous statement, master_host is the host name or IP address of the replication master, master_port is the port for the slave to use for connecting to the master, slave_user is the user name set up for the slave on the master, and slave_password is the password set for that user account in the previous step.

    For example, to tell the slave to replicate from the MySQL server whose host name is “rep-master,” using the replication slave account created in the previous step, use the following statement:

    mysqlS> CHANGE MASTER TO
         -> MASTER_HOST='rep-master'
         -> MASTER_PORT=3306,
         -> MASTER_USER='myslave'
         -> MASTER_PASSWORD='53cr37';
    

    For a complete list of clauses that can be used with this statement, see CHANGE MASTER TO Syntax.

    You can also configure the slave to use the master by setting the corresponding startup options in the slave server's my.cnf file. To configure the slave in the same way as the preceding example CHANGE MASTER TO statement, the following information would need to be included in the slave's my.cnf file:

    [mysqld]
    master-host=rep-master
    master-port=3306
    master-user=myslave
    master-password=53cr37
    

    For additional options that can be set in my.cnf for replication slaves, see Replication and Binary Logging Options and Variables.

    Note

    To provide replication backup capability, you will also need to add an ndb-connectstring option to the slave's my.cnf file prior to starting the replication process. See Section 9.9, “MySQL Cluster Backups With MySQL Cluster Replication”, for details.

  4. If the master cluster is already in use, you can create a backup of the master and load this onto the slave to cut down on the amount of time required for the slave to synchronize itself with the master. If the slave is also running MySQL Cluster, this can be accomplished using the backup and restore procedure described in Section 9.9, “MySQL Cluster Backups With MySQL Cluster Replication”.

    ndb-connectstring=management_host[:port]
    

    In the event that you are not using MySQL Cluster on the replication slave, you can create a backup with this command on the replication master:

    shellM> mysqldump --master-data=1
    

    Then import the resulting data dump onto the slave by copying the dump file over to the slave. After this, you can use the mysql client to import the data from the dumpfile into the slave database as shown here, where dump_file is the name of the file that was generated using mysqldump on the master, and db_name is the name of the database to be replicated:

    shellS> mysql -u root -p db_name < dump_file
    

    For a complete list of options to use with mysqldump, see mysqldump.

    Note

    If you copy the data to the slave in this fashion, you should make sure that the slave is started with the --skip-slave-start option on the command line, or else include skip-slave-start in the slave's my.cnf file to keep it from trying to connect to the master to begin replicating before all the data has been loaded. Once the data loading has completed, follow the additional steps outlined in the next two sections.

  5. Ensure that each MySQL server acting as a replication master is configured with a unique server ID, and with binary logging enabled, using the row format. (See Replication Formats.) These options can be set either in the master server's my.cnf file, or on the command line when starting the master mysqld process. See Section 9.6, “Starting MySQL Cluster Replication (Single Replication Channel)”, for information regarding the latter option.

9.6. Starting MySQL Cluster Replication (Single Replication Channel)

This section outlines the procedure for starting MySQL CLuster replication using a single replication channel.

  1. Start the MySQL replication master server by issuing this command:

    shellM> mysqld --ndbcluster --server-id=id \
            --log-bin --binlog-format=ROW &
    

    In the previous statement, id is this server's unique ID (see Section 9.2, “MySQL Cluster Replication — Assumptions and General Requirements”). This starts the server's mysqld process with binary logging enabled using the proper logging format.

    Note

    You can also start the master with --binlog-format=MIXED, in which case row-based replication is used automatically when replicating between clusters.

  2. Start the MySQL replication slave server as shown here:

    shellS> mysqld --ndbcluster --server-id=id &
    

    In the previous statement, id is the slave server's unique ID. It is not necessary to enable logging on the replication slave.

    Note

    You should use the --skip-slave-start option with this command or else you should include skip-slave-start in the slave server's my.cnf file, unless you want replication to begin immediately. With the use of this option, the start of replication is delayed until the appropriate START SLAVE statement has been issued, as explained in Step 4 below.

  3. It is necessary to synchronize the slave server with the master server's replication binlog. If binary logging has not previously been running on the master, run the following statement on the slave:

    mysqlS> CHANGE MASTER TO
         -> MASTER_LOG_FILE='',
         -> MASTER_LOG_POS=4;
    

    This instructs the slave to begin reading the master's binary log from the log's starting point. Otherwise — that is, if you are loading data from the master using a backup — see Section 9.8, “Implementing Failover with MySQL Cluster Replication”, for information on how to obtain the correct values to use for MASTER_LOG_FILE and MASTER_LOG_POS in such cases.

  4. Finally, you must instruct the slave to begin applying replication by issuing this command from the mysql client on the replication slave:

    mysqlS> START SLAVE;
    

    This also initiates the transmission of replication data from the master to the slave.

It is also possible to use two replication channels, in a manner simliar to the procedure described in the next section; the differences between this and using a single replication channel are covered in Section 9.7, “Using Two Replication Channels for MySQL Cluster Replication”.

Beginning with MySQL Cluster NDB 6.2.3, it is possible to improve cluster replication performance by enabling batched updates. This can be accomplished by starting slave mysqld processes with the --slave-allow-batching option. Normally, updates are applied as soon as they are received. However, the use of batching causes updates to be applied in 32 KB batches, which can result in higher throughput and less CPU usage, particularly where individual updates are relatively small.

Note

Slave batching works on a per-epoch basis; updates belonging to more than one transaction can be sent as part of the same batch.

All outstanding updates are applied when the end of an epoch is reached, even if the updates total less than 32 KB.

Batching can be turned on and off at runtime. To activate it at runtime, you can use either of these two statements:

SET GLOBAL slave_allow_batching = 1;
SET GLOBAL slave_allow_batching = ON;

If a particular batch causes problems (such as a statement whose effects do not appear to be replicated correctly), slave batching can be deactivated using either of the following statements:

SET GLOBAL slave_allow_batching = 0;
SET GLOBAL slave_allow_batching = OFF;

You can check whether slave batching is currently being used by means of an appropriate SHOW VARIABLES statement, like this one:

mysql> SHOW VARIABLES LIKE 'slave%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| slave_allow_batching      | ON    |
| slave_compressed_protocol | OFF   |
| slave_load_tmpdir         | /tmp  |
| slave_net_timeout         | 3600  |
| slave_skip_errors         | OFF   |
| slave_transaction_retries | 10    |
+---------------------------+-------+
6 rows in set (0.00 sec)

9.7. Using Two Replication Channels for MySQL Cluster Replication

In a more complete example scenario, we envision two replication channels to provide redundancy and thereby guard against possible failure of a single replication channel. This requires a total of four replication servers, two masters for the master cluster and two slave servers for the slave cluster. For purposes of the discussion that follows, we assume that unique identifiers are assigned as shown here:

Server IDDescription
1Master - primary replication channel (M)
2Master - secondary replication channel (M')
3Slave - primary replication channel (S)
4Slave - secondary replication channel (S')

Setting up replication with two channels is not radically different from setting up a single replication channel. First, the mysqld processes for the primary and secondary replication masters must be started, followed by those for the primary and secondary slaves. Then the replication processes may be initiated by issuing the START SLAVE statement on each of the slaves. The commands and the order in which they need to be issued are shown here:

  1. Start the primary replication master:

    shellM> mysqld --ndbcluster --server-id=1 \
                   --log-bin --binlog-format=row &
    
  2. Start the secondary replication master:

    shellM'> mysqld --ndbcluster --server-id=2 \
                   --log-bin --binlog-format=row &
    
  3. Start the primary replication slave server:

    shellS> mysqld --ndbcluster --server-id=3 \
                   --skip-slave-start &
    
  4. Start the secondary replication slave:

    shellS'> mysqld --ndbcluster --server-id=4 \
                    --skip-slave-start &
    
  5. Finally, initiate replication on the primary channel by executing the START SLAVE statement on the primary slave as shown here:

    mysqlS> START SLAVE;
    

    Warning

    Only the primary channel is to be started at this point. The secondary replication channel is to be started only in the event that the primary replication channel fails, as described in Section 9.8, “Implementing Failover with MySQL Cluster Replication”. Running multiple replication channels simultaneously can result in unwanted duplicate records being created on the replication slaves.

As mentioned previously, it is not necessary to enable binary logging on replication slaves.

9.8. Implementing Failover with MySQL Cluster Replication

In the event that the primary Cluster replication process fails, it is possible to switch over to the secondary replication channel. The following procedure describes the steps required to accomplish this.

  1. Obtain the time of the most recent global checkpoint (GCP). That is, you need to determine the most recent epoch from the ndb_apply_status table on the slave cluster, which can be found using the following query:

    mysqlS'> SELECT @latest:=MAX(epoch)
          ->        FROM mysql.ndb_apply_status;
    
  2. Using the information obtained from the query shown in Step 1, obtain the corresponding records from the ndb_binlog_index table on the master cluster as shown here:

    mysqlM'> SELECT
          ->     @file:=SUBSTRING_INDEX(File, '/', -1),
          ->     @pos:=Position
          -> FROM mysql.ndb_binlog_index
          -> WHERE epoch > @latest
          -> ORDER BY epoch ASC LIMIT 1;
    

    These are the records saved on the master since the failure of the primary replication channel. We have employed a user variable @latest here to represent the value obtained in Step 1. Of course, it is not possible for one mysqld instance to access user variables set on another server instance directly. These values must be “plugged in” to the second query manually or in application code.

  3. Now it is possible to synchronize the secondary channel by running the following query on the secondary slave server:

    mysqlS'> CHANGE MASTER TO
          ->     MASTER_LOG_FILE='@file',
          ->     MASTER_LOG_POS=@pos;
    

    Again we have employed user variables (in this case @file and @pos) to represent the values obtained in Step 2 and applied in Step 3; in practice these values must be inserted manually or using application code that can access both of the servers involved.

    Note

    @file is a string value such as '/var/log/mysql/replication-master-bin.00001', and so must be quoted when used in SQL or application code. However, the value represented by @pos must not be quoted. Although MySQL normally attempts to convert strings to numbers, this case is an exception.

  4. You can now initiate replication on the secondary channel by issuing the appropriate command on the secondary slave mysqld:

    mysqlS'> START SLAVE;
    

Once the secondary replication channel is active, you can investigate the failure of the primary and effect repairs. The precise actions required to do this will depend upon the reasons for which the primary channel failed.

Warning

The secondary replication channel is to be started only if and when the primary replication channel has failed. Running multiple replication channels simultaneously can result in unwanted duplicate records being created on the replication slaves.

If the failure is limited to a single server, it should (in theory) be possible to replicate from M to S', or from M' to S; however, this has not yet been tested.

9.9. MySQL Cluster Backups With MySQL Cluster Replication

This section discusses making backups and restoring from them using MySQL Cluster replication. We assume that the replication servers have already been configured as covered previously (see Section 9.5, “Preparing the MySQL Cluster for Replication”, and the sections immediately following). This having been done, the procedure for making a backup and then restoring from it is as follows:

  1. There are two different methods by which the backup may be started.

    • Method A.  This method requires that the cluster backup process was previously enabled on the master server, prior to starting the replication process. This can be done by including the following line in a [mysql_cluster] section in the my.cnf file, where management_host is the IP address or host name of the NDB management server for the master cluster, and port is the management server's port number:

      ndb-connectstring=management_host[:port]
      

      Note

      The port number needs to be specified only if the default port (1186) is not being used. See Section 2.3, “MySQL Cluster Multi-Computer Configuration”, for more information about ports and port allocation in MySQL Cluster.

      In this case, the backup can be started by executing this statement on the replication master:

      shellM> ndb_mgm -e "START BACKUP"
      

    • Method B.  If the my.cnf file does not specify where to find the management host, you can start the backup process by passing this information to the NDB management client as part of the START BACKUP command. This can be done as shown here, where management_host and port are the host name and port number of the management server:

      shellM> ndb_mgm management_host:port -e "START BACKUP"
      

      In our scenario as outlined earlier (see Section 9.5, “Preparing the MySQL Cluster for Replication”), this would be executed as follows:

      shellM> ndb_mgm rep-master:1186 -e "START BACKUP"
      

  2. Copy the cluster backup files to the slave that is being brought on line. Each system running an ndbd process for the master cluster will have cluster backup files located on it, and all of these files must be copied to the slave to ensure a successful restore. The backup files can be copied into any directory on the computer where the slave management host resides, so long as the MySQL and NDB binaries have read permissions in that directory. In this case, we will assume that these files have been copied into the directory /var/BACKUPS/BACKUP-1.

    It is not necessary that the slave cluster have the same number of ndbd processes (data nodes) as the master; however, it is highly recommended this number be the same. It is necessary that the slave be started with the --skip-slave-start option, to prevent premature startup of the replication process.

  3. Create any databases on the slave cluster that are present on the master cluster that are to be replicated to the slave.

    Important

    A CREATE DATABASE (or CREATE SCHEMA) statement corresponding to each database to be replicated must be executed on each SQL node in the slave cluster.

  4. Reset the slave cluster using this statement in the MySQL Monitor:

    mysqlS> RESET SLAVE;
    

    It is important to make sure that the slave's apply_status table does not contain any records prior to running the restore process. You can accomplish this by running this SQL statement on the slave:

    mysqlS> DELETE FROM mysql.ndb_apply_status;
    
  5. You can now start the cluster restoration process on the replication slave using the ndb_restore command for each backup file in turn. For the first of these, it is necessary to include the -m option to restore the cluster metadata:

    shellS> ndb_restore -c slave_host:port -n node-id \
            -b backup-id -m -r dir
    

    dir is the path to the directory where the backup files have been placed on the replication slave. For the ndb_restore commands corresponding to the remaining backup files, the -m option should not be used.

    For restoring from a master cluster with four data nodes (as shown in the figure in Chapter 9, MySQL Cluster Replication) where the backup files have been copied to the directory /var/BACKUPS/BACKUP-1, the proper sequence of commands to be executed on the slave might look like this:

    shellS> ndb_restore -c rep-slave:1186 -n 2 -b 1 -m \
            -r ./var/BACKUPS/BACKUP-1
    shellS> ndb_restore -c rep-slave:1186 -n 3 -b 1 \
            -r ./var/BACKUPS/BACKUP-1
    shellS> ndb_restore -c rep-slave:1186 -n 4 -b 1 \
            -r ./var/BACKUPS/BACKUP-1
    shellS> ndb_restore -c rep-slave:1186 -n 5 -b 1 -e \
            -r ./var/BACKUPS/BACKUP-1
    

    Important

    The -e (or --restore-epoch) option in the final invocation of ndb_restore in this example is required in order that the epoch is written to the slave mysql.ndb_apply_status. Without this information, the slave will not be able to synchronize properly with the master. (See Section 6.17, “ndb_restore — Restore a MySQL Cluster Backup”.)

  6. Now you need to obtain the most recent epoch from the ndb_apply_status table on the slave (as discussed in Section 9.8, “Implementing Failover with MySQL Cluster Replication”):

    mysqlS> SELECT @latest:=MAX(epoch)
            FROM mysql.ndb_apply_status;
    
  7. Using @latest as the epoch value obtained in the previous step, you can obtain the correct starting position @pos in the correct binary log file @file from the master's mysql.ndb_binlog_index table using the query shown here:

    mysqlM> SELECT
         ->     @file:=SUBSTRING_INDEX(File, '/', -1),
         ->     @pos:=Position
         -> FROM mysql.ndb_binlog_index
         -> WHERE epoch > @latest
         -> ORDER BY epoch ASC LIMIT 1;
    

    In the event that there is currently no replication traffic, you can get this information by running SHOW MASTER STATUS on the master and using the value in the Position column for the file whose name has the suffix with the greatest value for all files shown in the File column. However, in this case, you must determine this and supply it in the next step manually or by parsing the output with a script.

  8. Using the values obtained in the previous step, you can now issue the appropriate CHANGE MASTER TO statement in the slave's mysql client:

    mysqlS> CHANGE MASTER TO
         ->     MASTER_LOG_FILE='@file',
         ->     MASTER_LOG_POS=@pos;
    
  9. Now that the slave “knows” from what point in which binlog file to start reading data from the master, you can cause the slave to begin replicating with this standard MySQL statement:

    mysqlS> START SLAVE;
    

To perform a backup and restore on a second replication channel, it is necessary only to repeat these steps, substituting the host names and IDs of the secondary master and slave for those of the primary master and slave replication servers where appropriate, and running the preceding statements on them.

For additional information on performing Cluster backups and restoring Cluster from backups, see Section 7.3, “Online Backup of MySQL Cluster”.

9.9.1. MySQL Cluster Replication — Automating Synchronization of the Replication Slave to the Master Binary Log

It is possible to automate much of the process described in the previous section (see Section 9.9, “MySQL Cluster Backups With MySQL Cluster Replication”). The following Perl script reset-slave.pl serves as an example of how you can do this.

#!/user/bin/perl -w
#  file: reset-slave.pl
#  Copyright ©2005 MySQL AB
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to:
#  Free Software Foundation, Inc.
#  59 Temple Place, Suite 330
#  Boston, MA 02111-1307 USA
#
#  Version 1.1
######################## Includes ###############################
use DBI;
######################## Globals ################################
my  $m_host='';
my  $m_port='';
my  $m_user='';
my  $m_pass='';
my  $s_host='';
my  $s_port='';
my  $s_user='';
my  $s_pass='';
my  $dbhM='';
my  $dbhS='';
####################### Sub Prototypes ##########################
sub CollectCommandPromptInfo;
sub ConnectToDatabases;
sub DisconnectFromDatabases;
sub GetSlaveEpoch;
sub GetMasterInfo;
sub UpdateSlave;
######################## Program Main ###########################
CollectCommandPromptInfo;
ConnectToDatabases;
GetSlaveEpoch;
GetMasterInfo;
UpdateSlave;
DisconnectFromDatabases;
################## Collect Command Prompt Info ##################
sub CollectCommandPromptInfo
{
  ### Check that user has supplied correct number of command line args
  die "Usage:\n
       reset-slave >master MySQL host< >master MySQL port< \n
                   >master user< >master pass< >slave MySQL host< \n
                   >slave MySQL port< >slave user< >slave pass< \n
       All 8 arguments must be passed. Use BLANK for NULL passwords\n"
       unless @ARGV == 8;
  $m_host  =  $ARGV[0];
  $m_port  =  $ARGV[1];
  $m_user  =  $ARGV[2];
  $m_pass  =  $ARGV[3];
  $s_host  =  $ARGV[4];
  $s_port  =  $ARGV[5];
  $s_user  =  $ARGV[6];
  $s_pass  =  $ARGV[7];
  if ($m_pass eq "BLANK") { $m_pass = '';}
  if ($s_pass eq "BLANK") { $s_pass = '';}
}
###############  Make connections to both databases #############
sub ConnectToDatabases
{
  ### Connect to both master and slave cluster databases
  ### Connect to master
  $dbhM
    = DBI->connect(
    "dbi:mysql:database=mysql;host=$m_host;port=$m_port",
    "$m_user", "$m_pass")
      or die "Can't connect to Master Cluster MySQL process!
              Error: $DBI::errstr\n";
  ### Connect to slave
  $dbhS
    = DBI->connect(
          "dbi:mysql:database=mysql;host=$s_host",
          "$s_user", "$s_pass")
    or die "Can't connect to Slave Cluster MySQL process!
            Error: $DBI::errstr\n";
}
################  Disconnect from both databases ################
sub DisconnectFromDatabases
{
  ### Disconnect from master
  $dbhM->disconnect
  or warn " Disconnection failed: $DBI::errstr\n";
  ### Disconnect from slave
  $dbhS->disconnect
  or warn " Disconnection failed: $DBI::errstr\n";
}
######################  Find the last good GCI ##################
sub GetSlaveEpoch
{
  $sth = $dbhS->prepare("SELECT MAX(epoch)
                         FROM mysql.ndb_apply_status;")
      or die "Error while preparing to select epoch from slave: ",
             $dbhS->errstr;
  $sth->execute
      or die "Selecting epoch from slave error: ", $sth->errstr;
  $sth->bind_col (1, \$epoch);
  $sth->fetch;
  print "\tSlave Epoch =  $epoch\n";
  $sth->finish;
}
#######  Find the position of the last GCI in the binlog ########
sub GetMasterInfo
{
  $sth = $dbhM->prepare("SELECT
                           SUBSTRING_INDEX(File, '/', -1), Position
                         FROM mysql.ndb_binlog_index
                         WHERE epoch > $epoch
                         ORDER BY epoch ASC LIMIT 1;")
      or die "Prepare to select from master error: ", $dbhM->errstr;
  $sth->execute
      or die "Selecting from master error: ", $sth->errstr;
  $sth->bind_col (1, \$binlog);
  $sth->bind_col (2, \$binpos);
  $sth->fetch;
  print "\tMaster bin log =  $binlog\n";
  print "\tMaster Bin Log position =  $binpos\n";
  $sth->finish;
}
##########  Set the slave to process from that location #########
sub UpdateSlave
{
  $sth = $dbhS->prepare("CHANGE MASTER TO
                         MASTER_LOG_FILE='$binlog',
                         MASTER_LOG_POS=$binpos;")
      or die "Prepare to CHANGE MASTER error: ", $dbhS->errstr;
  $sth->execute
       or die "CHANGE MASTER on slave error: ", $sth->errstr;
  $sth->finish;
  print "\tSlave has been updated. You may now start the slave.\n";
}
# end reset-slave.pl

9.10. MySQL Cluster Replication — Multi-Master and Circular Replication

Beginning with MySQL 5.1.18, it is possible to use MySQL Cluster in multi-master replication, including circular replication between a number of MySQL Clusters.

Note

Prior to MySQL 5.1.18, multi-master replication including circular replication was not supported with MySQL Cluster replication. This was because log events created in a particular MySQL Cluster were wrongly tagged with the server ID of the master rather than the server ID of the originating server.

Circular replication example.  In the next few paragraphs we consider the example of a replication setup involving three MySQL Clusters numbered 1, 2, and 3, in which Cluster 1 acts as the replication master for Cluster 2, Cluster 2 acts as the master for Cluster 3, and Cluster 3 acts as the master for Cluster 1. Each cluster has two SQL nodes, with SQL nodes A and B belonging to Cluster 1, SQL nodes C and D belonging to Cluster 2, and SQL nodes E and F belonging to Cluster 3.

Circular replication using these clusters is supported as long as:

  • The SQL nodes on all masters and slaves are the same

  • All SQL nodes acting as replication masters and slaves are started using the --log-slave-updates option

This type of circular replication setup is shown in the following diagram:

Cluster circular replication scheme in which
          all master SQL nodes are also slaves.

In this scenario, SQL node A in Cluster 1 replicates to SQL node C in Cluster 2; SQL node C replicates to SQL node E in Cluster 3; SQL node E replicates to SQL node A. In other words, the replication line (indicated by the red arrows in the diagram) directly connects all SQL nodes used as replication masters and slaves.

It is also possible to set up circular replication in such a way that not all master SQL nodes are also slaves, as shown here:

Cluster circular replication scheme in which
          all master SQL nodes are not also necessarily slaves.

In this case, different SQL nodes in each cluster are used as replication masters and slaves. However, you must not start any of the SQL nodes using --log-slave-updates (see the description of this option for more information). This type of circular replication scheme for MySQL Cluster, in which the line of replication (again indicated by the red arrows in the diagram) is discontinuous, should be possible, but it should be noted that it has not yet been thoroughly tested and must therefore still be considered experimental.

Important

Beginning with MySQL 5.1.24, you should execute the following statement before starting circular replication:

mysql> SET GLOBAL SLAVE_EXEC_MODE = 'IDEMPOTENT';

This is necessary to suppress duplicate-key and other errors that otherwise break circular replication in MySQL Cluster. IDEMPOTENT mode is also required for multi-master replication when using MySQL Cluster. (Bug#31609)

See slave_exec_mode, for more information.

Using NDB-native backup and restore to initialize a slave MySQL Cluster.  When setting up circular replication, it is possible to initialize the slave cluster by using the management client BACKUP command on one MySQL Cluster to create a backup and then applying this backup on another MySQL Cluster using ndb_restore. However, this does not automatically create binary logs on the second MySQL Cluster's SQL node acting as the replication slave. In order to cause the binary logs to be created, you must issue a SHOW TABLES statement on that SQL node; this should be done prior to running START SLAVE.

This is a known issue which we intend to address in a future release.

Multi-master failover example.  In this section, we discuss failover in a multi-master MySQL Cluster replication setup with three MySQL Clusters having server IDs 1, 2, and 3. In this scenario, Cluster 1 replicates to Clusters 2 and 3; Cluster 2 also replicates to Cluster 3. This relationship is shown here:

Multi-master MySQL Cluster replication
            setup, with three MySQL Clusters

In other words, data replicates from Cluster 1 to Cluster 3 via 2 different routes: directly, and by way of Cluster 2.

Not all MySQL servers taking part in multi-master replication must act as both master and slave, and a given MySQL Cluster might use different SQL nodes for diffferent replication channels. Such a case is shown here:

Multi-master MySQL Cluster replication
          setup, detail with MySQL Servers

MySQL servers acting as replication slaves must be run with the --log-slave-updates option. Which mysqld processes require this option is also shown in the preceding diagram.

Note

Using the --log-slave-updates option has no effect on servers not being run as replication slaves.

The need for failover arises when one of the replicating clusters goes down. In this example, we consider the case where Cluster 1 is lost to service, and so Cluster 3 loses 2 sources of updates from Cluster 1. Because replication between MySQL Clusters is asynchronous, there is no guarantee that Cluster 3's updates originating directly from Cluster 1 are more recent than those received via Cluster 2. You can handle this by ensuring that Cluster 3 catches up to Cluster 2 with regard to updates from Cluster 1. In terms of MySQL servers, this means that you need to replicate any outstanding updates from MySQL server C to server F.

On server C, perform the following queries:

mysqlC> SELECT @latest:=MAX(epoch)
     ->     FROM mysql.ndb_apply_status
     ->     WHERE server_id=1;
mysqlC> SELECT
     ->     @file:=SUBSTRING_INDEX(File, '/', -1),
     ->     @pos:=Position
     ->     FROM mysql.ndb_binlog_index
     ->     WHERE orig_epoch >= @latest
     ->     AND orig_server_id = 1
     ->     ORDER BY epoch ASC LIMIT 1;

Copy over the values for @file and @pos manually from server C to server F (or have your application perform the equivalent). Then, on server F, execute the following CHANGE MASTER TO statement:

mysqlF> CHANGE MASTER TO
     ->     MASTER_HOST = 'serverC'
     ->     MASTER_LOG_FILE='@file',
     ->     MASTER_LOG_POS=@pos;

Once this has been done, you can issue a START SLAVE statement on MySQL server F, and any missing updates originating from server B will be replicated to server F.

9.11. MySQL Cluster Replication Conflict Resolution

When using a replication setup involving multiple masters (including circular replication), it is possible that different masters may try to update the same row on the slave with different data. Conflict resolution in MySQL Cluster Replication provides a means of resolving such conflicts by allowing a user defined resolution column to be used to determine whether or not an update to the row on a given master should be applied on the slave. (This column is sometimes referred to as a “timestamp” column, even though this column' type cannot be TIMESTAMP, as explained later in this section.) Different methods can be used to compare resolution column values on the slave when conflicts occur, as explained later in this section; the method used can be set on a per-table basis.

Important

Conflict resolution as described in this section is always applied on a row-by-row basis rather than a transactional basis. In addition, it is the application's responsibility to ensure that the resolution column is correctly populated with relevant values, so that the resolution function can make the appropriate choice when determining whether to apply an update.

Requirements.  Preparations for conflict resolution must be made on both the master and the slave:

  • On the master writing the binlogs, you must determine which columns are sent (all columns or only those that have been updated). This is done for the MySQL Server as a whole by applying the mysqld startup option -–ndb-log-updated-only (described later in this section) or on a per-table basis by entries in the mysql.ndb_replication table.

  • On the slave, you must determine which type of conflict resolution to apply (“latest timestamp wins”, “same timestamp wins”, or none). This is done using the mysql.ndb_replication system table, on a per-table basis.

If only some but not all columns are sent, then the master and slave can diverge.

Note

We refer to the column used for determining updates as a “timestamp” column, but the data type of this column is never TIMESTAMP; rather, its data type should be INT (INTEGER) or BIGINT. This column should be UNSIGNED and NOT NULL.

Master column control.  We can see update operations in terms of “before” and “after” images — that is, the states of the table before and after the update is applied. Normally, when updating a table with a primary key, the “before” image is not of great interest; however, when we need to determine on a per-update basis whether or not to use the updated values on a replication slave, we need to make sure that both images are written to the master's binary log. This is done with the --ndb-log-update-as-write option for mysqld, as described later in this section.

Important

Whether logging of complete rows or of updated columns only is done is decided when the MySQL server is started, and cannot be changed online; you must either restart mysqld, or start a new mysqld instance with different logging options.

Logging full or partial rows (--ndb-log-updated-only option).  For purposes of conflict resolution, there are two basic methods of logging rows, as determined by the setting of the --ndb-log-updated-only option for mysqld:

  • Log complete rows

  • Log only column data that has been updated — that is, column data whose value has been set, regardless of whether or not this value was actually changed.

It is more efficient to log updated columns only; however, if you need to log full rows, you can do so by setting --ndb-log-updated-only to 0 or OFF.

Logging changed data as updates (--ndb-log-update-as-write option).  Either of these logging methods can be configured to be done with or without the “before” image as determined by the setting of another MySQL Server option --ndb-log-update-as-write. Because conflict resolution is done in the MySQL Server's update handler, it is necessary to control logging on the master such that updates are updates and not writes; that is, such that updates are treated as changes in existing rows rather than the writing of new rows (even though these replace existing rows). This option is turned on by default; to turn it off, start the server with --ndb-log-update-as-write=0 or --ndb-log-update-as-write=OFF.

Conflict resolution control.  Conflict resolution is usually enabled on the server where conflicts can occur. Like logging method selection, it is enabled by entries in the mysql.ndb_replication table.

The ndb_replication system table.  To enable conflict resolution, it is necessary to create an ndb_replication table in the mysql system database on the master, the slave, or both, depending on the conflict resolution type and method to be employed. This table is used to control logging and conflict resolution functions on a per-table basis, and has one row per table involved in replication. ndb_replication is created and filled with control information on the server where the conflict is to be resolved. In a simple master-slave setup where data can also be changed locally on the slave this will typically be the slave. In a more complex master-master (2-way) replication schema this will usually be all of the masters involved. Each row in mysql.ndb_replication corresponds to a table being replicated, and specifies how to log and resolve conflicts (that is, which conflict resolution function, if any, to use) for that table. The definition of the mysql.ndb_replication table is shown here:

CREATE TABLE mysql.ndb_replication  (
    db VARBINARY(63),
    table_name VARBINARY(63),
    server_id INT UNSIGNED,
    binlog_type INT UNSIGNED,
    conflict_fn VARBINARY(128),
    PRIMARY KEY USING HASH (db, table_name, server_id)
)   ENGINE=NDB
PARTITION BY KEY(db,table_name);

The columns in this table are described in the following list:

  • db The name of the database containing the table to be replicated.

  • table_name The name of the table to be replicated.

  • server_id The unique server ID of the MySQL instance (SQL node) where the table resides.

  • binlog_type The type of binary logging to be employed. This is determined as shown in the following table:

    ValueInternal ValueDescription
    0NBT_DEFAULTUse server default
    1NBT_NO_LOGGINGDo not log this table in the binary log
    2NBT_UPDATED_ONLYOnly updated attributes are logged
    3NBT_FULLLog full row, even if not updated (MySQL server default behavior)
    4NBT_USE_UPDATE(For generating NBT_UPDATED_ONLY_USE_UPDATE and NBT_FULL_USE_UPDATE values only — not intended for separate use)
    5[Not used]---
    6NBT_UPDATED_ONLY_USE_UPDATE (equal to NBT_UPDATED_ONLY | NBT_USE_UPDATE)Use updated attributes, even if values are unchanged
    7NBT_FULL_USE_UPDATE (equal to NBT_FULL | NBT_USE_UPDATE)Use full row, even if values are unchanged

  • conflict_fn The conflict resolution function to be applied. This function must be specified as one of the following:

    • NDB$MAX(column_name).  If the “timestamp” column value for a given row coming from the master is higher than that on the slave, it is applied; otherwise it is not applied on the slave. This is illustrated by the following pseudocode:

      if (master_new_column_value > slave_current_column_value)
        perform_update();
      

      This function can be used for “greatest timestamp wins” conflict resolution. This type of conflict resolution ensures that, in the event of a conflict, the version of the row that was most recently updated is the version that persists.

      Important

      The column value from the master's “after” image is used by this function.

      This conflict resolution function is available beginning with MySQL Cluster NDB 6.3.0.

    • NDB$OLD(column_name).  If the value of column_name is the same on both the master and the slave, then the update is applied; otherwise, the update is not applied on the slave and an exception is written to the log. This is illustrated by the following pseudocode:

      if (master_old_column_value == slave_current_column_value)
        perform_update();
      else
        log_exception();
      

      This function can be used for “same value wins” conflict resolution. This type of conflict resolution ensures that updates are not applied on the slave from the wrong master.

      Important

      The column value from the master's “before” image is used by this function.

      This conflict resolution function is available beginning with MySQL Cluster NDB 6.3.4.

    • NULL: Indicates that conflict resolution is not to be used for the corresponding table

    .

Status information.  Beginning with MySQL Cluster NDB 6.3.3, a server status variable Ndb_conflict_fn_max provides a count of the number of times that a row was not applied on the current SQL node due to “greatest timestamp wins” conflict resolution since the last time that mysqld was started.

Beginning with MySQL Cluster NDB 6.3.4, the number of times that a row was not applied as the result of “same timestamp wins” conflict resolution on a given mysqld since the last time it was restarted is given by the global status variable Ndb_conflict_fn_old. In addition to incrementing Ndb_conflict_fn_old, the primary key of the row that was not used is inserted into an exceptions table, as explained later in this section.

Additional requirements for “Same timestamp wins” conflict resolution.  To use the NDB$OLD() conflict resolution function, it is also necessary to create an exceptions table corresponding to each NDB table for which this type of conflict resolution is to be employed. The name of this table is that of the table for which “same timestamp wins” conflict resolution is to be applied, with the string $EX appended. (For example, if the name of the original table is mytable, the name of the corresponding exception table name should be mytable$EX.) This table is created as follows:

CREATE TABLE original_table$EX  (
    server_id INT UNSIGNED,
    master_server_id INT UNSIGNED,
    master_epoch BIGINT UNSIGNED,
    count INT UNSIGNED,
    original_table_pk_columns,
    [additional_columns,]
    PRIMARY KEY(server_id, master_server_id, master_epoch, count)
) ENGINE=NDB;

The first four columns are required. Following these columns, the columns making up the original table's primary key should be copied in the order in which they are used to define the primary key of the original table.

Note

The names of the first four columns and the columns matching the original table's primary key columns are not critical; however, we suggest for reasons of clarity and consistency, that you use the names shown here for the server_id, master_server_id, master_epoch, and count columns, and that you use the same names as in the original table for the columns matching those in the original table's primary key.

The data types for the columns duplicating the primary key columns of the original table should be the same as for (or larger than) the original columns.

Additional columns may optionally be defined following these columns, but not before any of them; any such extra columns cannot be NOT NULL. The exception table's primary key must be defined as shown. The exception table must use the NDB storage engine. An example of use for NDB$OLD() and an exception table is given later in this section.

Important

The mysql.ndb_replication table is read when a data table is set up for replication, so the row corresponding to a table to be replicated must be inserted into mysql.ndb_replication before the table to be replicated is created.

Examples.  The following examples assume that you have already a working MySQL Cluster replication setup, as described in Section 9.5, “Preparing the MySQL Cluster for Replication”, and Section 9.6, “Starting MySQL Cluster Replication (Single Replication Channel)”.

  • NDB$MAX() example.  Suppose you wish to enable “greatest timestamp wins” conflict resolution on table test.t1, using column mycol as the “timestamp”. This can be done using the following steps:

    1. Make sure that you have started the master mysqld with -–ndb-log-update-as-write=OFF.

    2. On the master, perform this INSERT statement:

      INSERT INTO mysql.ndb_replication
          VALUES ('test', 't1', 0, NULL, 'NDB$MAX(mycol)');
      

      Inserting a 0 into the server_id indicates that all SQL nodes accessing this table should use conflict resolution. If you want to use conflict resolution on a specific mysqld only, use the actual server ID.

      Inserting NULL into the binlog_type column has the same effect as inserting 0 (NBT_DEFAULT); the server default is used.

    3. Create the test.t1 table:

      CREATE TABLE test.t1 (
          columns
          mycol INT UNSIGNED,
          columns
      ) ENGINE=NDB;
      

      Now, when updates are done on this table, conflict resolution will be applied, and the version of the row having the greatest value for mycol will be written to the slave.

    Note

    Other binlog_type options — such as NBT_UPDATED_ONLY_USE_UPDATE should be used in order to control logging on the master via the ndb_replication table rather than by using command-line options.

  • NDB$OLD() example.  Suppose an NDB table such as the one defined here is being replicated, and you wish to enable “same timestamp wins” conflict resolution for updates to this table:

    CREATE TABLE test.t2  (
        a INT UNSIGNED NOT NULL,
        b CHAR(25) NOT NULL,
        columns,
        mycol INT UNSIGNED NOT NULL,
        columns,
        PRIMARY KEY pk (a, b)
    )   ENGINE=NDB;
    

    The following steps are required, in the order shown:

    1. First — and prior to creating test.t2 — you must insert a row into the mysql.ndb_replication table, as shown here:

      INSERT INTO mysql.ndb_replication
          VALUES ('test', 't2', 0, NULL, 'NDB$OLD(mycol)');
      

      Possible values for the binlog_type column are shown earlier in this section. The value 'NDB$OLD(mycol)' should be inserted into the conflict_fn column.

    2. Create an appropriate exceptions table for test.t2. The table creation statement shown here includes all required columns; any additional columns must be declared following these columns, and before the definition of the table's primary key.

      CREATE TABLE test.t2$EX  (
          server_id SMALLINT UNSIGNED,
          master_server_id INT UNSIGNED,
          master_epoch BIGINT UNSIGNED,
          count BIGINT UNSIGNED,
          a INT UNSIGNED NOT NULL,
          b CHAR(25) NOT NULL,
          [additional_columns,]
          PRIMARY KEY(server_id, master_server_id, master_epoch, count)
      )   ENGINE=NDB;
      

    3. Create the table test.t2 as shown previously.

    These steps must be followed for every table for which you wish to perform conflict resolution using NDB$OLD(). For each such table, there must be a corresponding row in mysql.ndb_replication, and there must be an exceptions table in the same database as the table being replicated.

Document Actions