MySQL Cluster database & MySQL Replication
RSS icon Email icon Home icon
  • MySQL Cluster Evaluation Guide – refreshed for Cluster 7.2 DMR

    Posted on January 11th, 2012 admin 2 comments

     There is an updated version of the MySQL Cluster Evaluation Guide to go with the MySQL Cluster 7.2 Development Milestone Release.

    The purpose of this guide is to enable you to efficiently evaluate the MySQL
    Cluster database and determine if it is the right choice for your application,
    whether as part of a new project or an upgrade to an existing service.
    This guide presents a brief overview of the MySQL Cluster database and new
    features in the latest 7.2 Development Milestone Release, and then discusses:

    • Considerations before initiating an evaluation
    • Evaluation best practices
    • Configuration options and sanity checking
    • Troubleshooting

    By following the recommendations in this Guide, you will be able to quickly and
    effectively evaluate the MySQL Cluster 7.2 Development Milestone Release
    (DMR).

    Please note that the MySQL Cluster 7.2 Development Milestone is not a currently
    production-ready release. It is published to provide a preview of new features that
    are planned, but not committed, for the next production-ready “General
    Availability” release of MySQL Cluster.

  • Enhanced conflict resolution with MySQL Cluster active-active replication

    Posted on November 22nd, 2011 admin 3 comments

    Detecting conflicts

    Part of the latest MySQL Cluster Development Milestone Release (MySQL Cluster 7.2.1 – select the “Development Release” tab at http://dev.mysql.com/downloads/cluster/#downloads) is a couple of enhancements to the conflict detection and resolution mechanism for active-active (multi-master) replication. While MySQL Cluster has had conflict detection for years it has now been made much more complete and a lot easier to use:

    • No changes needed to the application schema
    • Entire conflicting transaction is rolled back together with any dependent transactions

    The focus of this post will be to step through how to use this feature – while it will also attempt to explain how it works at a high level, you should refer to the following posts for the design details and philosophy: Eventual consistency with MySQL & Eventual Consistency – detecting conflicts.

    What is a conflict?

    MySQL Cluster allows bi-directional replication between two (or more) clusters. Replication within each cluster is synchronous but between clusters it is asynchronous which means the following scenario is possible:

    Conflict with asynchronous replication
    Site A Replication Site B
    x == 10 x == 10
    x = 11 x = 20
    – x=11 –> x == 11
    x==20 <– x=20 –

     

    In this example a value (column for a row in a table) is set to 11 on site A and the change is queued for replication to site B. In the mean time, an application sets the value to 20 on site B and that change is queued for replication to site A. Once both sites have received and applied the replicated change from the other cluster site A contains the value 20 while site B contains 11 – in other words the databases are now inconsistent.

    How MySQL Cluster 7.2 implements eventual consistency

    There are two phases to establishing consistency between both clusters after an inconsistency has been introduced:

    1. Detect that a conflict has happened
    2. Resolve the inconsistency

    Detecting the conflict

    The following animation illustrates how MySQL Cluster 7.2 detects that an inconsistency has been introduced by the asynchronous, active-active replication:

    Detecting conflicts

    While we typically consider the 2 clusters in an active-active replication configuration to be peers, in this case we designate one to be the primary and the other the secondary. Reads and writes can still be sent to either cluster but it is the responsibility of the primary to identify that a conflict has arisen and then remove the inconsistency.

    A logical clock is used to identify (in relative terms) when a change is made on the primary – for those who know something of the MySQL Cluster internals, we use the index of the Global Checkpoint that the update is contained in. For all tables that have this feature turned on, an extra, hidden column is automatically added on the primary – this represents the value of the logical clock when the change was made.

    Once the change has been applied on the primary, there is a “window of conflict” for the effected row(s) during which if a different change is made to the same row(s) on the secondary then there will be an inconsistency. Once the slave on the secondary has applied the change from the primary, it will send a replication event back to the slave on the primary, containing the primary’s clock value associated with the changes that have just been applied on the secondary. (Remember that the clock is actually the Global Checkpoint Index and so this feature is sometimes referred to as Reflected GCI). Once the slave on the primary has received this event, it knows that all changes tagged with a clock value no later than the reflected GCI are now safe – the window of conflict has closed.

    If an application modifies this same row on the secondary before the replication event from the primary was applied then it will send an associated replication event to the slave on the primary before it reflects the new GCI. The slave on the primary will process this replication event and compare the clock value recorded with the effected rows with the latest reflected GCI; as the clock value for the conflicting row is higher the primary recognises that a conflict has occured and will launch the algorithm to resolve the inconsistency.

    Resolving the inconsistency

    In earlier releases of MySQL Cluster (or if choosing to use the original algorithm in MySQL Cluster 7.2) you had a choice of simply flagging the primary key of the conflicting rows or backing out one of the changes to the conflicting rows. Using the new NDB$EPOCH_TRANS function, the primary will overwrite the data in the secondary for the effected row(s) and any other rows that were updated in the same transaction (even if they are in tables for which conflict detection has not been enabled).

    In fact the algorithm goes a step further and if there were subsequent transactions on the secondary that wrote to the conflicting rows then all of the changes from those dependent transactions on the secondary will be backed-out as well.

    Worked example

    In this section, we step through how to setup the active-active replication, with the new conflict detection/resolution feature enabled and then test it out by manually introducing some conflicting transations.

    Set-up MySQL Clusters and basic active-acative replication

    Hosts used for active-active replication tests

    Hosts used for replication

    To keep things simple, just two hosts are used; “black” will contain all nodes for the primary cluster and “blue” will contain all nodes for the secondary. As an extra simplification a single MySQL Server in each cluster will act as both the master and the slave.

    This post will quickly show the configuration files and steps to get the 2 clusters up and running but for a better understanding of these steps you can refer to Deploying MySQL Cluster over multiple hosts.

    config.ini (black):

    [ndb_mgmd]
    hostname=localhost
    datadir=/home/billy/my_cluster/data
    nodeid=1
    
    [ndbd default]
    noofreplicas=2
    datadir=/home/billy/my_cluster/data
    
    [ndbd]
    hostname=localhost
    nodeid=3
    
    [ndbd]
    hostname=localhost
    nodeid=4
    
    [mysqld]
    nodeid=50

    config.ini (blue):

    [ndb_mgmd]
    hostname=localhost
    datadir=/home/billy/my_cluster/data
    nodeid=1
    
    [ndbd default]
    noofreplicas=2
    datadir=/home/billy/my_cluster/data
    
    [ndbd]
    hostname=localhost
    nodeid=3
    
    [ndbd]
    hostname=localhost
    nodeid=4
    
    [mysqld]
    nodeid=50

    my.cnf for primary cluster (black):

    [mysqld]
    ndbcluster
    datadir=/home/billy/my_cluster/data
    server-id=8
    log-bin=black-bin.log 
    ndb-log-transaction-id=1
    binlog-format=ROW
    ndb-log-update-as-write=0

    my.cnf for secondary cluster (blue):

    [mysqld]
    ndbcluster
    datadir=/home/billy/my_cluster/data
    server-id=9
    log-bin=blue-bin.log
    ndb-log-transaction-id=1
    binlog-format=ROW
    ndb-log-update-as-write=0
    ndb-log-apply-status=1

    Note that the options set in the my.cnf file are very important – if any of these are missing then things will not work as expected.

    Start up primary cluster (black):

    billy@black:~/my_cluster$ ndb_mgmd --initial
       -f conf/config.ini --configdir=/home/billy/my_cluster/conf/
    billy@black:~/my_cluster$ ndbd --initial
    billy@black:~/my_cluster$ ndbd --initial
    billy@black:~/my_cluster$ ndb_mgm -e show # wait for ndbds to finish starting
    Connected to Management Server at: localhost:1186
    Cluster Configuration
    ---------------------
    [ndbd(NDB)]     2 node(s)
    id=3    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1, Nodegroup: 0, Master)
    id=4    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1, Nodegroup: 0)
    
    [ndb_mgmd(MGM)] 1 node(s)
    id=1    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1)
    
    [mysqld(API)]   3 node(s)
    id=50 (not connected, accepting connect from any host)
    
    billy@black:~/my_cluster$ mysqld --defaults-file=conf/my.cnf &

    Start up secondary cluster (blue):

    billy@blue:~/my_cluster$ ndb_mgmd --initial
       -f conf/config.ini --configdir=/home/billy/my_cluster/conf/
    billy@blue:~/my_cluster$ ndbd --initial
    billy@blue:~/my_cluster$ ndbd --initial
    billy@blue:~/my_cluster$ ndb_mgm -e show # wait for ndbds to finish starting
    Connected to Management Server at: localhost:1186
    Cluster Configuration
    ---------------------
    [ndbd(NDB)]     2 node(s)
    id=3    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1, Nodegroup: 0, Master)
    id=4    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1, Nodegroup: 0)
    
    [ndb_mgmd(MGM)] 1 node(s)
    id=1    @127.0.0.1  (mysql-5.5.15 ndb-7.2.1)
    
    [mysqld(API)]   3 node(s)
    id=50 (not connected, accepting connect from any host)
    
    billy@blue:~/my_cluster$ mysqld --defaults-file=conf/my.cnf &

    Both clusters are now running and replication can be activated for both sites:

    billy@black:~/my_cluster$ mysql -u root --prompt="black-mysql> "
    black-mysql> CREATE USER repl_user@192.168.1.16;
    black-mysql> GRANT REPLICATION SLAVE ON *.* TO repl_user@192.168.1.16
                     IDENTIFIED BY 'billy';
    billy@blue:~/my_cluster$ mysql -u root --prompt="blue-mysql> "
    blue-mysql> CREATE USER repl_user@192.168.1.20;
    blue-mysql> GRANT REPLICATION SLAVE ON *.* TO repl_user@192.168.1.20
                     IDENTIFIED BY 'billy';
    blue-mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.20',
        -> MASTER_USER='repl_user',
        -> MASTER_PASSWORD='billy',
        -> MASTER_LOG_FILE='',
        -> MASTER_LOG_POS=4;
    blue-mysql> START SLAVE;
    black-mysql> CHANGE MASTER TO MASTER_HOST='192.168.1.16',
        -> MASTER_USER='repl_user',
        -> MASTER_PASSWORD='billy',
        -> MASTER_LOG_FILE='',
        -> MASTER_LOG_POS=4;
    black-mysql> START SLAVE;

    Set up enhanced conflict detection & resolution

    The first step is to identify the tables that need conflict detection enabling. Each of those tables then has to have an entry in the mysql.ndb_replication table where they’re tagged as using the new NDB$EPOCH_TRANS() function – you could also choose to use NDB$EPOCH(), in which case only the changes to conflicting rows will be backed-out rather than the full transactions. A few things to note:

    • This must be done before creating the application tables themselves
    • Should only be done on the primary
    • By default the table doesn’t exist and so the very first step is to create it
    black-mysql> 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);
    black-mysql> INSERT INTO mysql.ndb_replication VALUES ('clusterdb', 'simple1', 8, 0,
    'NDB$EPOCH_TRANS()');
    black-mysql> INSERT INTO mysql.ndb_replication VALUES ('clusterdb', 'simple2', 8, 0,
    'NDB$EPOCH_TRANS()');
    black-mysql> INSERT INTO mysql.ndb_replication VALUES ('clusterdb', 'simple3', 8, 0,
    'NDB$EPOCH_TRANS()');

    For each of these tables you should also create an exceptions table which will record any conflicts that have resulted in changes being rolled back; the format of these tables is rigidly defined and so take care to copy the types exactly; again this only needs doing on the primary:

    black-mysql> CREATE DATABASE clusterdb;USE clusterdb;
    black-mysql> CREATE TABLE simple1$EX (server_id INT UNSIGNED,
                   master_server_id INT UNSIGNED, master_epoch BIGINT UNSIGNED,
                   count INT UNSIGNED, id INT NOT NULL, PRIMARY KEY(server_id,
                   master_server_id, master_epoch, count)) ENGINE=NDB;
    black-mysql> CREATE TABLE simple2$EX (server_id INT UNSIGNED,
                   master_server_id INT UNSIGNED, master_epoch BIGINT UNSIGNED,
                   count INT UNSIGNED, id INT NOT NULL, PRIMARY KEY(server_id,
                   master_server_id, master_epoch, count)) ENGINE=NDB;
    black-mysql> CREATE TABLE simple3$EX (server_id INT UNSIGNED,
                   master_server_id INT UNSIGNED, master_epoch BIGINT UNSIGNED,
                   count INT UNSIGNED, id INT NOT NULL, PRIMARY KEY(server_id,
                   master_server_id, master_epoch, count)) ENGINE=NDB;

    Finally, the application tables themselves can be created (this only needs doing on the primary as they’ll be replicated to the secondary):

    black-mysql> CREATE TABLE simple1 (id INT NOT NULL PRIMARY KEY, value INT) ENGINE=ndb;
    black-mysql> CREATE TABLE simple2 (id INT NOT NULL PRIMARY KEY, value INT) ENGINE=ndb;
    black-mysql> CREATE TABLE simple3 (id INT NOT NULL PRIMARY KEY, value INT) ENGINE=ndb;

    Everything is now set up and the new configuration can be tested to ensure that conflicts are detected and the correct updates are rolled back.

    Testing enhanced active-active replication and conflict detection

    The first step is to add some data to our new tables (note that at this point replication is running and so they only need to be created on the primary) and then update 1 row to make sure that it is replicated to the secondary:

    black-mysql> INSERT INTO simple1 VALUES (1,10);
    black-mysql> INSERT INTO simple2 VALUES (1,10);
    black-mysql> INSERT INTO simple3 VALUES (1,10);
    black-mysql> UPDATE simple1 SET value=12 WHERE id=1;
    blue-mysql> USE clusterdb;
    blue-mysql> SELECT * FROM simple1;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    12 |
    +----+-------+

    It is important that the NDB$EPOCH_TRANS() function rolls back any transactions on the secondary that involve a conflict (as well as subsequent, dependent transactions that modify the same rows); to do this manually the simplest approach is to stop the slave IO thread on the secondary thread in order to increase the size of the window of conflict (which is otherwise very short). Once the slave IO thread has been stopped a change is made to table simple1 on the primary and then the secondary makes a (conflicting) change to the same row as well as making a change to table simple2 in the same transaction. A second transaction on the primary will change a row in simple3 – as it doesn’t touch any rows that have been involved in a conflict then that change should stand.

    blue-mysql> STOP SLAVE IO_THREAD;
    black-mysql> UPDATE simple1 SET value=13 WHERE id=1;
    blue-mysql> BEGIN; # conflicting transaction
    blue-mysql> UPDATE simple1 SET value=20 WHERE id=1;
    blue-mysql> UPDATE simple2 SET value=20 WHERE id=1;
    blue-mysql> COMMIT;
    blue-mysql> UPDATE simple3 SET value=20 WHERE id=1; # non conflicting
    blue-mysql> SELECT * FROM simple1;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    20 |
    +----+-------+
    blue-mysql> SELECT * FROM simple2;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    20 |
    +----+-------+
    blue-mysql> SELECT * FROM simple3;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    20 |
    +----+-------+

    If you now check the exception tables then you can see that the primary (black) has received the changes from the secondary (blue) and because the first transaction updated the same row in simple1 during its window of conflict it has recorded that the change needs to be rolled back – this will happen as soon as the replication thread is restarted on the secondary:

    black-mysql> SELECT * FROM simple1$EX;
    +-----------+------------------+---------------+-------+----+
    | server_id | master_server_id | master_epoch  | count | id |
    +-----------+------------------+---------------+-------+----+
    |         8 |                9 | 1494648619009 |     3 |  1 |
    +-----------+------------------+---------------+-------+----+
    
    black-mysql> SELECT * FROM simple2$EX;
    +-----------+------------------+---------------+-------+----+
    | server_id | master_server_id | master_epoch  | count | id |
    +-----------+------------------+---------------+-------+----+
    |         8 |                9 | 1494648619009 |     1 |  1 |
    +-----------+------------------+---------------+-------+----+
    
    black-mysql> SELECT * FROM simple3$EX;
    Empty set (0.05 sec)
    blue-mysql> START SLAVE IO_THREAD;
    blue-mysql> SELECT * FROM simple1;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    13 |
    +----+-------+
    
    blue-mysql> SELECT * FROM simple2;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    10 |
    +----+-------+
    
    blue-mysql> SELECT * FROM simple3;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    20 |
    +----+-------+

    These are the results we expect – simple1 has the value set by the primary with the subsequent change on the secondary rolled back; simple2 was not updated by the primary but the change on the secondary was rolled back as it was made in the same transaction as the conflicting update to simple1. The change on the secondary to simple3 has survived as it was made outside of any conflicting transaction and the change was not dependent on any conflicting changes. Finally just confirm that the data is identical on the primary:

    black-mysql> SELECT * FROM simple1;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    13 |
    +----+-------+
    
    black-mysql> SELECT * FROM simple2;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    10 |
    +----+-------+
    
    black-mysql> SELECT * FROM simple3;
    +----+-------+
    | id | value |
    +----+-------+
    |  1 |    20 |
    +----+-------+

    Statistics are provided on the primary that record that 1 conflict has been detected, effecting 1 transaction and that it resulted in 2 row changes being rolled back:

    black-mysql> SHOW STATUS LIKE 'ndb_conflict%';
    +------------------------------------------+-------+
    | Variable_name                            | Value |
    +------------------------------------------+-------+
    | Ndb_conflict_fn_max                      | 0     |
    | Ndb_conflict_fn_old                      | 0     |
    | Ndb_conflict_fn_max_del_win              | 0     |
    | Ndb_conflict_fn_epoch                    | 0     |
    | Ndb_conflict_fn_epoch_trans              | 1     |
    | Ndb_conflict_trans_row_conflict_count    | 1     |
    | Ndb_conflict_trans_row_reject_count      | 2     |
    | Ndb_conflict_trans_reject_count          | 1     |
    | Ndb_conflict_trans_detect_iter_count     | 1     |
    | Ndb_conflict_trans_conflict_commit_count | 1     |
    +------------------------------------------+-------+

    We’re anxious to get feedback on this feature and so please go ahead and download MySQL Cluster 7.2.1 and let us know how you get on through the comments for this post.

  • Further MySQL Cluster additions to MySQL Enterprise Monitor

    Posted on October 17th, 2011 admin No comments

    Data Node Restarted alert

    About 11 months ago I described the MySQL Cluster functionality that was added to MySQL Enterprise Monitor 2.3; this new post is intended to just bring this up to date – briefly describing the new graph and advisors which have been added since then (up to and including MEM 2.3.7).

    Cluster Data Node Has Been Restarted

    This new alert flags when a data node has been restarted (by default it alerts on any data node that has started in the last 10 minutes but you can change that interval if you wish). If you manually perform a restart (e.g. as part of a rolling upgrade) then you can safely ignore this alert (or you may even want to temporarily unschedule it first). However if the restart was spontaneous then this can be an early warning for you to take a look at the error logs and address any issues before the situation worsens.

    Cluster DiskPageBuffer Hit Ratio Is Low (& associated graph)

    The Disk Page Buffer is a cache on each data node which is used when using disk-based tables. Like any cache, the higher the hit rate the better the performance. Tuning the size of this cache can have a significant effect on your system – the new graph helps you see the results of your changes and the alert warns you when the ration falls below an acceptable level (this could happen for example temporarily after a data node restart or permanently when the active data set grows).

    The ndbinfo database has a new table “diskpagebuffer” which contains the raw information needed to calculate the cache hit ration and it is the source of the data for the new alert and graph. If you wanted to calculate the cache hit ratio for yourself directly from this table then you can use the following query:

    mysql> SELECT node_id, page_requests_direct_return AS hit, 
     page_requests_wait_io AS miss,  100*page_requests_direct_return/
     (page_requests_direct_return+page_requests_wait_io) AS hit_rate
      FROM ndbinfo.diskpagebuffer;
    
    +---------+------+------+----------+
    | node_id | hit  | miss | hit_rate |
    +---------+------+------+----------+
    | 3       | 6    | 3    | 66.6667  |
    | 4       | 10   | 3    | 76.9231  |
    +---------+------+------+----------+

    The alert is first raised (info level) when the hit rate falls bellow 97%, the warning level is raised at 90% and the critical level at 80%. Again, you can alter any of these thresholds.

    The new graph simply displays how the hit rate varies over time so that you can spot trends.

    As a reminder you can get more information on the original set of alerts and graphs here.

  • MySQL Cluster Webinar on Wednesday: What’s New in MySQL Cluster 7.2.1 Development Milestone Release

    Posted on October 17th, 2011 admin No comments

    There’s a webinar this Wednesday (9 am Pacific; 5 pm UK; 6 pm CET) that explains what’s new in the MySQL Cluster Development Milestone Release – register here for free access.

    Join this session to learn about the latest enhancements to the MySQL Cluster database, enabling even more of the latest generation of web, telecoms and embedded applications to take advantage of high write scalability, SQL and NoSQL interfaces and 99.999% availability.

    New capabilities include:

    •  70x higher JOIN performance for the latest generation of web applications using Adaptive Query Localization, enabling real-time analytics across live data sets
    • New NoSQL interface via memcached to further enhance developer flexibility and productivity
    • Simplified global scalability with multi-site clusters and enhanced Active/Active replication
    • Integration with the MySQL 5.5 release, enabling users to fully exploit the latest capabilities of both the InnoDB and MySQL Cluster storage engines within a single application
    • Streamlined cluster provisioning and maintenance

    The 2nd Development Milestone Release of MySQL Cluster 7.2.1 was announced at Oracle OpenWorld 2011. This release is now available for download and evaluation under the GPL license. This session will help to get you started with this latest release.

  • MySQL Cluster material from Oracle Open World 2011

    Posted on October 10th, 2011 admin No comments

    For those people that weren’t able to attend the MySQL Cluster demo or sessions at this year’s Oracle Open World (or even for those that did) and would like copies of the material, links are provided here.

  • My sessions at Oracle OpenWorld 2011

    Posted on September 5th, 2011 admin 1 comment

    Slight adjustment to some of the times + added the MySQL community reception (read  vodka!). Oracle OpenWorld (San Francisco) starts on Sunday 2nd October (including some MySQL community sessions) through Thursday 6th October. MySQL has a lot of sessions this year as well as 3 demo booths.

    This year I’m going to be involved in 3 public sessions – if you’re attending, please come along and say hello!

    • Getting the Most Out of MySQL on Windows – 13:15 on Tuesday (Marriott Marquis – Golden Gate C2)
    • Building Highly Available and Scalable Real-Time Services with MySQL Cluster – 10:15 on Wednesday (Marriott Marquis – Golden Gate C1)
    • NoSQL Access to MySQL: The Best of Both Worlds – 11:45 on Wednesday (Marriott Marquis – Golden Gate C1)
    • MySQL Community Reception – 19:00 on Wednesday (San Francisco Marriott Marquis – Foothill G)
    In addition I’ll be spending as much time as I can at the MySQL demo booths in the exhibition hall. Come and visit us for demos of MySQL Cluster, MySQL Enterprise Edition and MySQL WorkBench.
  • MySQL Cluster 7.1.15 released

    Posted on July 19th, 2011 admin 9 comments


    The binary version for MySQL Cluster 7.1.15 has now been made available at http://www.mysql.com/downloads/cluster/

    A description of all of the changes (fixes) that have gone into MySQL Cluster 7.1.15 (compared to 7.1.13) can be found in the official MySQL Cluster documentation for Cluster 7.1.14 & 7.1.15.

  • Direct access to MySQL Cluster through Memcached API – free webinar

    Posted on July 18th, 2011 admin No comments

    Memcached access to MySQL Cluster

    As described in an earlier post Memcached is an extremely popular caching layer used in most big web properties and we’re adding the ability to access MySQL Cluster directly using the familiar Memcached key-value/NoSQL API without needing to go through the MySQL Server. There is a huge amount of flexibility built into this solution – including:

    • Decide what data should be held only in the Memcached server; what should be written straight through to MySQL Cluster and then discarded  and what data should be cached in Memcached but persisted in MySQL Cluster
    • Where data is held both in Cluster and the Memcached server, they can automatically be kept in sync
    • By default it’s completely schema-less, all key-value pairs will be transparently stored in a single table within MySQL Cluster behind the scenes
    • Can map key-prefixes to columns in MySQL Cluster tables – allowing simultaneous access to the same data using SQL.
    Mat Keep along with JD Duncan (lead developer for this functionality) will be hosting a free webinar on this topic (and I’ll be helping with the Q&A) on Wednesday (20th July 2011) at 9:00 am Pacific (17:00 UK, 18:00 CET). As always, please register for the event even if you can’t make this time as you’ll be sent a link to the recording.
  • Webinar: MySQL Cluster, Scaling Web Databases with Auto-Partitioning and SQL/NoSQL Access

    Posted on June 6th, 2011 admin 3 comments

    Scale-out with MySQL Cluster

    Update: webinar replay is now available from http://event.on24.com/r.htm?e=311660&s=1&k=3DCFE1CB3E1CF3F0FD0969DC66D93989

    On Thursday 26th May Mat Keep and I will be presenting a webinar on how MySQL Cluster can deliver linear scalability – together with some tips on how to achieve it. As always the webinar is free but you need to register here.

     

    The session starts on Thu, May 26 at 17:00 UK time, 18:00 Central European Time, 09:00 Pacific.

    This webinar will discuss best practices in scaling services on-demand for high volumes of reads and writes, and provide insight on the range of NoSQL and SQL access methods available to developers, specifically covering:

    • Automatic partitioning (sharding) for high scalability
    • On-line scaling of the cluster across commodity hardware
    • SQL and NoSQL interfaces, and what should be used when
    • On-line updating of schema design to accommodate rapidly evolving applications
    • Resources to get started
  • Sharing user credentials between MySQL Servers with Cluster

    Posted on April 11th, 2011 admin 2 comments

    Fig. 1 User privileges stored in MyISAM

    The Developer Release for MySQL Cluster 7.2 includes a new feature that allows the system data required for checking user access to be shared amongst all of your MySQL Servers. By default all of the tables holding these credentials are stored in MyISAM and so are local to that MySQL Server.

    This can become painful to manage – every time you want to create a new user or change their permissions you need to repeat it on every server, miss one out and the user won’t be able to access that server (or will still be able to access it after you withdraw their privileges).

    This is illustrated in Fig.1 – The user “fred” is created on one MySQL Server but when Fred attempts to connect to one of the MySQL Servers they’re blocked. This maybe what you wanted to happen but probably not.

    In this post, we’ll see how to change this behaviour but first we’ll confirm the default behaviour.

    Obviously, it makes sense to try this out for yourself and you can download the source or binaries from http://dev.mysql.com/downloads/cluster/ (select the sub-tab for the Development Milestone Release).

    The first step is to run Cluster with multiple MySQL Servers – if you’re not comfortable with how to do this then refer to this post on how to distribute MySQL Cluster over multiple hosts.

    Four mysql client connections will be used – one for root to connect to server 1; one for Fred to connect to server 1; one for root to connect to server 2 and one for Fred to try connecting to server 2.

    So, let’s create Fred on server 1 and a table for him to access:

    $ mysql -h 192.168.1.7 -P3306 -u root --prompt 'server1-root> '
    server1-root> GRANT ALL ON *.* TO 'fred'@'192.168.1.7';
    server1-root> CREATE DATABASE clusterdb; USE clusterdb;
    server1-root> CREATE TABLE towns (id INT NOT NULL PRIMARY KEY,
      town VARCHAR(20)) ENGINE=NDBCLUSTER;
    server1-root> INSERT INTO towns VALUES (1,'Maidenhead'),(2, 'Reading');

    Next we confirm that Fred can access this data when connecting through server 1:

    $ mysql -h 192.168.1.7 -P3306 -u fred --prompt 'server1-fred> '
    server1-fred> SELECT * FROM clusterdb.towns;
    +----+------------+
    | id | town       |
    +----+------------+
    |  1 | Maidenhead |
    |  2 | Reading    |
    +----+------------+

    Now try the same thing from server 2:

    $ mysql -h 192.168.1.7 -P3307 -u fred --prompt 'server2> '
    server2-fred> SELECT * FROM clusterdb.towns;
    ERROR 1142 (42000): SELECT command denied to user ''@'ws2.localdomain'
     for table 'towns'

    What we need to do next is to run a script (as MySQL root) and then a stored procedure to convert 5 tables from the mysql database (“user”, “db”, “tables_priv”, “columns_priv” & “procs_priv”) from the MyISAM to the ndbcluster storage engine:

    server1-root> SOURCE /usr/local/mysql/share/mysql/ndb_dist_priv.sql;
    server1-root> CALL mysql.mysql_cluster_move_privileges();

    We can confirm that the storage engine has changed, for example:

    server1-root> SHOW CREATE TABLE mysql.user\G
    *************************** 1. row ***************************
          Table: userCreate Table: CREATE TABLE `user` (
      `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
    ....
    ....
     ) ENGINE=ndbcluster DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users
     and global privileges'

    Note that “ENGINE=ndbcluster”.

    Fig. 2 User Privilege Tables Stored in MySQL Cluster

    Now that these tables are stored in MySQL Cluster, they should be visible from all of the MySQL Servers. So now, whichever MySQL Server Fred attempts to connect through, that MySQL Server will fetch the privilege data from the shared data nodes rather than using local information and so Fred will get the same access rights. As our clusterdb.towns table was created using the ndbcluster storage engine as well, it is accessible from all servers and so Fred should now be able to see the contents of the table from server 2 as the access rights on server 2 now allow it. Note that the data already stored in those 5 mysql tables survived the migration from MyISAM to MySQL Cluster.

    So the final test is to confirm that Fred really is allowed to get to this data from server 2:

    $ mysql -h 192.168.1.7 -P3307 -u fred --prompt 'server2-fred>
    server2-fred> SELECT * FROM clusterdb.towns;
    +----+------------+
    | id | town       |
    +----+------------+
    |  1 | Maidenhead |
    |  2 | Reading    |
    +----+------------+
    

    Note that if “fred” were already connected to server2 then he would need to disconnect and reconnect.

    Once server1 has been set up in this way, changes to the user privileges data can be made from any one of the mysql servers in the Cluster (not just server1) and they will be enforced by all of the MySQL Servers.

    You can find the official documentation for this feature here.