MySQL Cluster database & MySQL Replication
RSS icon Email icon Home icon
  • 1 Billion queries per minute and much more – free webinar on MySQL Cluster 7.2 GA

    Posted on February 15th, 2012 admin 1 comment
    1 Billion queries per minute with MySQL Cluster

    1 Billion queries per minute with MySQL Cluster

    Oracle announced the General Availability of MySQL Cluster 7.2 today. Join this live webinar to learn about what’s new in the production-ready, GA release of MySQL Cluster 7.2, enabling the latest generation of web and telecoms applications to take advantage of high write scalability, SQL and NoSQL interfaces and 99.999% availability, including:

    • Performance enhancements delivering 1 billion queries per minute, using just 8 data nodes
    • 70x higher JOIN performance with Adaptive Query Localization, enabling real-time analytics across live data sets
    • New NoSQL API via Memcached, creating a persistent, key-value datastore for schema and schemaless data
    • Auto-sharding across data centers with synchronous replication for scaling of highly available, global services
    • Simplified ease-of-use with new options for on-premise and cloud deployments
    • Integration with the latest MySQL 5.5 GA release

    The webinar takes place on Thursday 23rd February at 09:00 PST, 17:00 GMT, 18:00 CET. Mat Keep and I will be presenting.

    As always, the webinar is free but you’ll need to register here in advance - even if you can’t make the live event, this will make sure that you get emailed a link to the recording.

  • 1 Billion Queries Per Minute – MySQL Cluster 7.2 is GA!

    Posted on February 15th, 2012 admin 3 comments

    1 Billion queries per minute with MySQL Cluster

    1 Billion queries per minute with MySQL Cluster

    Oracle have just announced that MySQL Cluster 7.2 is now GA and available for production deployments.

    Amongst the highlights for the release are:

    • Performance enhancements delivering 1 billion queries per minute, using just 8 data nodes
    • 70x higher JOIN performance with Adaptive Query Localization, enabling real-time analytics across live data sets
    • New NoSQL API via Memcached, creating a persistent, key-value datastore for schema and schemaless data
    • Auto-sharding across data centers with synchronous replication for scaling of highly available, global services
    • Simplified ease-of-use with new options for on-premise and cloud deployments
    • Integration with the latest MySQL 5.5 GA release

    You can find more of the details on this release together with links to lots of resources from this MySQL Dev-Zone article – “MySQL Cluster 7.2 GA Released, Delivers 1 BILLION Queries per Minute”

  • MySQL Cluster Manager 1.1.4 Released – includes support for MySQL Cluster 7.2

    Posted on February 15th, 2012 admin No comments

    MySQL Cluster Manager 1.1. is now available to download and try from Oracle E-Delivery (select “MySQL Database” as the product pack).

    There’s lots of good stuff gone in under the covers as part of this release, with some of the highlights being:

    • Support for MySQL Cluster 7.2
    • Configuration of MySQL Server parameters
    • Verbose option added to commands for extra info on what’s going on
    • Faster Cluster rolling restarts – data nodes from different node groups will be restarted in parallel (still avoids an outage but cuts the end-to-end restart time)
    • Robustness enhancements to the configurator – especially important when managing large Clusters
    • Bug fixes (well we always need to include that one)

    More details on the changes can be found in the MySQL Cluster Manager documentation.

    Please give it a try and let me know what you think.

  • Scalable, persistent, HA NoSQL Memcache storage using MySQL Cluster

    Posted on February 15th, 2012 admin 20 comments

    Memcached API with Cluster Data Nodes

    The native Memcached API for MySQL Cluster is now GA as part of MySQL Cluster 7.2

    This post was first published in April 2011 when the first trial version of the Memcached API for MySQL Cluster was released; it was then up-versioned for the second MySQL Cluster 7.2 Development Milestone Release in October 2011. I’ve now refreshed the post based on the GA of MySQL Cluster 7.2 which includes the completed Memcache API.

    There are a number of attributes of MySQL Cluster that make it ideal for lots of applications that are considering NoSQL data stores. Scaling out capacity and performance on commodity hardware, in-memory real-time performance (especially for simple access patterns), flexible schemas… sound familiar? In addition, MySQL Cluster adds transactional consistency and durability. In case that’s not enough, you can also simultaneously combine various NoSQL APIs with full-featured SQL – all working on the same data set. This post focuses on a new Memcached API that is now available to download, try out and deploy. This post steps through setting up Cluster with the Memcached API and then demonstrates how to read and write the same data through both Memcached and SQL (including for existing MySQL Cluster tables).

    Download the community version from mysql.com or the commercial version from Oracle’s Software Delivery Cloud (note that there is not currently a Windows version).

    Traditional use of Memcached

    First of all a bit of background about Memcached. It has typically been used as a cache when the performance of the database of record (the persistent database) cannot keep up with application demand. When changing data, the application will push the change to the database, when reading data, the application first checks the Memached cache, if it is not there then the data is read from the database and copied into Memcached. If a Memcached instance fails or is restarted for maintenance reasons, the contents are lost and the application will need to start reading from the database again. Of course the database layer probably needs to be scaled as well so you send writes to the master and reads to the replication slaves.

    This has become a classic architecture for web and other applications and the simple Memcached attribute-value API has become extremely popular amongst developers.

    As an illustration of the simplicity of this API, the following example stores and then retrieves the string “Maidenhead” against the key “Test”:

    telnet localhost 11211
    set Test 0 0 10
    Maidenhead!
    END
    get Test
    VALUE Test 0 10
    Maidenhead!
    END

    Note that if we kill and restart the memcached server, the data is lost (as it was only held in RAM):

    get Test
    END

    New options for using Memcached API with MySQL Cluster

    Architecture for Memcached NDB API

    What we’re doing with MySQL Cluster is to offer a bunch of new ways of using this API but with the benefits of MySQL Cluster. The solution has been designed to be very flexible, allowing the application architect to find a configuration that best fits their needs.

    A quick diversion on how this is implemented. The application sends reads and writes to the memcached process (using the standard Memcached API). This in turn invokes the Memcached Driver for NDB (which is part of the same process) which in turn calls the NDB API for very quick access to the data held in MySQL Cluster’s data nodes (it’s the fastest way of accessing MySQL Cluster).

    Because the data is now stored in MySQL Cluster, it is persistent and you can transparently scale out by adding more data nodes (this is an on-line operation).

    Another important point is that the NDB API is already a commonly used, fully functional access method that the Memcached API can exploit. For example, if you make a change to a piece of data then the change will automatically be written to any MySQL Server that has its binary logging enabled which in turn means that the change can be replicated to a second site.

    Memcached API with Cluster Data Nodes

    So the first (and probably simplest) architecture is to co-locate the Memcached API with the data nodes.

    The applications can connect to any of the memcached API nodes – if one should fail just switch to another as it can access the exact same data instantly. As you add more data nodes you also add more memcached servers and so the data access/storage layer can scale out (until you hit the 48 data node limit).

    Memcached server with the Application

    Another simple option is to co-locate the Memcached API with the application. In this way, as you add more application nodes you also get more Memcached throughput. If you need more data storage capacity you can independently scale MySQL Cluster by adding more data nodes. One nice feature of this approach is that failures are handled very simply – if one App/Memcached machine should fail, all of the other applications just continue accessing their local Memcached API.

    Separate Memcached layer

    For maximum flexibility, you can have a separate Memcached layer so that the application, the Memcached API & MySQL Cluster can all be scaled independently.

    In all of the examples so far, there has been a single source for the data (it’s all held in MySQL Cluster).






    Local Cache in Memcached

    If you choose, you can still have all or some of the data cached within the memcached server (and specify whether that data should also be persisted in MySQL Cluster) – you choose how to treat different pieces of your data. If for example, you had some data that is written to and read from frequently then store it just in MySQL Cluster, if you have data that is written to rarely but read very often then you might choose to cache it in Memcached as well and if you have data that has a short lifetime and wouldn’t benefit from being stored in MySQL Cluster then only hold it in Memcached. The beauty is that you get to configure this on a per-key-prefix basis (through tables in MySQL Cluster) and that the application doesn’t have to care – it just uses the Memcached API and relies on the software to store data in the right place(s) and to keep everything in sync.

    Of course if you want to access the same data through SQL then you’d make sure that it was configured to be stored in MySQL Cluster.

    Enough of the theory, how to try it out…

    Installing & configuarying the software

    As this post is focused on API access to the data rather than testing High Availability, performance or scalability the Cluster can be kept extremely simple with all of the processes (nodes) running on a single server. The only thing to be careful of when you create your Cluster is to make sure that you define at least 5 API sections (e.g. [mysqld]) in your configuration file so you can access using SQL and 2 Memcached servers (each uses 2 connections) at the same time.

    For further information on how to set up a single-host Cluster, refer to this post or just follow the next few steps.

    Create a config.ini file for the Cluster configuration:

    [ndb_mgmd]
    hostname=localhost
    datadir=/home/billy/my_cluster/ndb_data
    NodeId=1
    
    [ndbd default]
    noofreplicas=2
    datadir=/home/billy/my_cluster/ndb_data
    
    [ndbd]
    hostname=localhost
    NodeId=3
    
    [ndbd]
    hostname=localhost
    NodeId=4
    
    [mysqld]
    NodeId=50
    
    [mysqld]
    NodeId=51
    
    [mysqld]
    NodeId=52
    
    [mysqld]
    NodeId=53
    
    [mysqld]
    NodeId=54

    and a my.cnf file for the MySQL server:

    [mysqld]
    ndbcluster
    datadir=/home/billy/my_cluster/mysqld_data

    Before starting the Cluster, install the standard databases for the MySQL Server (from wherever you have MySQL Cluster installed – typically /usr/local/mysql):

    [billy@ws2 mysql]$ ./scripts/mysql_install_db
      --basedir=/usr/local/mysql
      --datadir=/home/billy/my_cluster/mysqld_data
      --user=billy
    Start up the system

    We are now ready to start up the Cluster processes:

    [billy@ws2 my_cluster]$ ndb_mgmd -f conf/config.ini
      --initial --configdir=/home/billy/my_cluster/conf/
    [billy@ws2 my_cluster]$ ndbd
    [billy@ws2 my_cluster]$ ndbd
    [billy@ws2 my_cluster]$ ndb_mgm -e show # Wait for data nodes to start
    [billy@ws2 my_cluster]$ mysqld --defaults-file=conf/my.cnf &

    If your version doesn’t already have the ndbmemcache database installed then that should be your next step:

    [billy@ws2 ~]$ mysql -h 127.0.0.1 -P3306 -u root < /usr/local/mysql/share/memcache-api/ndb_memcache_metadata.sql

    After that, start the Memcached server (with the NDB driver activated):

    [billy@ws2 ~]$  memcached -E /usr/local/mysql/lib/ndb_engine.so -e "connectstring=localhost:1186;role=db-only" -vv -c 20

    Notice the “connectstring” – this allows the primary Cluster to be on a different machine to the Memcached API. Note that you can actually use the same Memcached server to access multiple Clusters – you configure this within the ndbmemcached database in the primary Cluster. In a production system you may want to include reconf=false amogst the -e parameters in order to stop configuration changes being applied to running Memcached servers (you’d need to restart those servers instead).

    Try it out!

    Next the fun bit – we can start testing it out:

    [billy@ws2 ~]$ telnet localhost 11211
    
    set maidenhead 0 0 3
    SL6 
    STORED 
    get maidenhead 
    VALUE maidenhead 0 3
    SL6
    END

    We can now check that the data really is stored in the database:

    mysql> SELECT * FROM ndbmemcache.demo_table;
       +------------------+------------+-----------------+--------------+
       | mkey             | math_value | cas_value       | string_value |
       +------------------+------------+-----------------+--------------+
       | maidenhead       |       NULL | 263827761397761 | SL6          |
       +------------------+------------+-----------------+--------------+

    Of course, you can also modify this data through SQL and immediately see the change through the Memcached API:

    mysql> UPDATE ndbmemcache.demo_table SET string_value='sl6 4' WHERE mkey='maidenhead';
    
    [billy@ws2 ~]$ telnet localhost 11211
    
    get maidenhead
    VALUE maidenhead 0 5
    SL6 4
    END

    By default, the normal limit of 14K per row still applies when using the Memcached API; however, the standard configuration treats any key-value pair with a key-pefix of “b:” differently and will allow the value to be up to 3 Mb (note the default limit imposed by the Memcached server is 1 Mb and so you’d also need to raise that). Internally the contents of this value will be split between 1 row in ndbmemcache.demo_table_large and one or more rows in ndbmemcache.external_values.

    Note that this is completely schema-less, the application can keep on adding new key/value pairs and they will all get added to the default table. This may well be fine for prototyping or modest sized databases. As you can see this data can be accessed through SQL but there’s a good chance that you’ll want a richer schema on the SQL side or you’ll need to have the data in multiple tables for other reasons (for example you want to replicate just some of the data to a second Cluster for geographic redundancy or to InnoDB for report generation).

    The next step is to create your own databases and tables (assuming that you don’t already have them) and then create the definitions for how the app can get at the data through the Memcached API. First let’s create a table that has a couple of columns that we’ll also want to make accessible through the Memcached API:

    mysql> CREATE DATABASE clusterdb; USE clusterdb;
    mysql> CREATE TABLE towns_tab (town VARCHAR(30) NOT NULL PRIMARY KEY,
      zip VARCHAR(10), population INT, county VARCHAR(10)) ENGINE=NDB;
    mysql> INSERT INTO towns_tab VALUES ('Marlow', 'SL7', 14004, 'Berkshire');

    Next we need to tell the NDB driver how to access this data through the Memcached API. Two ‘containers’ are created that identify the columns within our new table that will be exposed. We then define the key-prefixes that users of the Memcached API will use to indicate which piece of data (i.e. database/table/column) they are accessing:

    mysql> USE ndbmemcache;
    mysql> INSERT INTO containers VALUES ('towns_cnt', 'clusterdb',
    'towns_tab', 'town', 'zip', 0, NULL, NULL, NULL, NULL);
    mysql> INSERT INTO containers VALUES ('pop_cnt', 'clusterdb',
      'towns_tab', 'town', 'population', 0, NULL, NULL, NULL, NULL);
    mysql> SELECT * FROM containers;
       +------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+
       | name       | db_schema   | db_table         | key_columns | value_columns  | flags | increment_column | cas_column | expire_time_column | large_values_table          |
       +------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+
       | demo_ext   | ndbmemcache | demo_table_large | mkey        | string_value   | 0     | NULL             | cas_value  | NULL               | ndbmemcache.external_values |
       | towns_cnt  | clusterdb   | towns_tab        | town        | zip            | 0     | NULL             | NULL       | NULL               | NULL                        |
       | demo_table | ndbmemcache | demo_table       | mkey        | string_value   | 0     | math_value       | cas_value  | NULL               | NULL                        |
       | pop_cnt    | clusterdb   | towns_tab        | town        | population     | 0     | NULL             | NULL       | NULL               | NULL                        |
       | demo_tabs  | ndbmemcache | demo_table_tabs  | mkey        | val1,val2,val3 | flags | NULL             | NULL       | expire_time        | NULL                        |
       +------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+
    mysql> INSERT INTO key_prefixes VALUES (1, 'twn_pr:', 0,
      'ndb-only', 'towns_cnt');
    mysql> INSERT INTO key_prefixes VALUES (1, 'pop_pr:', 0,
      'ndb-only', 'pop_cnt');
    mysql> SELECT * FROM key_prefixes;
       +----------------+------------+------------+---------------+------------+
       | server_role_id | key_prefix | cluster_id | policy        | container  |
       +----------------+------------+------------+---------------+------------+
       |              1 | pop_pr:    |          0 | ndb-only      | pop_cnt    |
       |              0 | t:         |          0 | ndb-test      | demo_tabs  |
       |              3 |            |          0 | caching       | demo_table |
       |              0 |            |          0 | ndb-test      | demo_table |
       |              0 | mc:        |          0 | memcache-only | NULL       |
       |              1 | b:         |          0 | ndb-only      | demo_ext   |
       |              2 |            |          0 | memcache-only | NULL       |
       |              1 |            |          0 | ndb-only      | demo_table |
       |              0 | b:         |          0 | ndb-test      | demo_ext   |
       |              3 | t:         |          0 | caching       | demo_tabs  |
       |              1 | t:         |          0 | ndb-only      | demo_tabs  |
       |              4 |            |          0 | ndb-test      | demo_ext   |
       |              1 | twn_pr:    |          0 | ndb-only      | towns_cnt  |
       |              3 | b:         |          0 | caching       | demo_ext   |
       +----------------+------------+------------+---------------+------------+

    At present it is necessary to restart the Memcached server in order to pick up the new key_prefix (and so you’d want to run multiple instances in order to maintain service):

    
    [billy@ws2:~]$ memcached -E /usr/local/mysql/lib/ndb_engine.so -e "connectstring=localhost:1186;role=db-only" -vv -c 20
       07-Feb-2012 11:22:29 GMT NDB Memcache 5.5.19-ndb-7.2.4 started [NDB 7.2.4; MySQL 5.5.19]
       Contacting primary management server (localhost:1186) ...
       Connected to "localhost:1186" as node id 51.
       Retrieved 5 key prefixes for server role "db-only".
       The default behavior is that:
           GET uses NDB only
           SET uses NDB only
           DELETE uses NDB only.
       The 4 explicitly defined key prefixes are "b:" (demo_table_large), "pop_pr:" (towns_tab),
          "t:" (demo_table_tabs) and "twn_pr:" (towns_tab)

    Now these columns (and the data already added through SQL) are accessible through the Memcached API:

    [billy@ws2 ~]$ telnet localhost 11211
    
    get twn_pr:Marlow
    VALUE twn_pr:Marlow 0 3
    SL7
    END 
    set twn_pr:Maidenhead 0 0 3
    SL6 
    STORED 
    set pop_pr:Maidenhead 0 0 5
    42827 
    STORED

    and then we can check these changes through SQL:

    mysql> SELECT * FROM clusterdb.towns_tab;
       +------------+------+------------+-----------+
       | town       | zip  | population | county    |
       +------------+------+------------+-----------+
       | Maidenhead | SL6  |      42827 | NULL      |
       | Marlow     | SL7  |      14004 | Berkshire |
       +------------+------+------------+-----------+

    One final test is to start a second memcached server that will access the same data. As everything is running on the same host, we need to have the second server listen on a different port:

    [billy@ws2 ~]$ memcached -E /usr/local/mysql/lib/ndb_engine.so
       -e "connectstring=localhost:1186;role=db-only" -vv -c 20
       -p 11212 -U 11212
    [billy@ws2 ~]$ telnet localhost 11212
    
    get twn_pr:Marlow 
    VALUE twn_pr:Marlow 0 3
    SL7
    END

    Memcached alongside NoSQL & SQL APIs

    As mentioned before, there’s a wide range of ways of accessing the data in MySQL Cluster – both SQL and NoSQL. You’re free to mix and match these technologies – for example, a mission critical business application using SQL, a high-running web app using the Memcached API and a real-time application using the NDB API. And the best part is that they can all share the exact same data and they all provide the same HA infrastructure (for example synchronous replication and automatic failover within the Cluster and geographic replication to other clusters).

    Finally, a reminder – please try this out and let us know what you think (or if you don’t have time to try it then let us now what you think anyway) by adding a comment to this post.

  • 70x Faster Joins with AQL now GA with MySQL Cluster 7.2

    Posted on February 15th, 2012 admin 9 comments

    70x faster joins with AQL

    The new GA MySQL Cluster 7.2 Release (7.2.4) just announced by Oracle includes 2 new features which when combined can improve the performance of joins by a factor of 70x (or even higher). The first enhancement is that MySQL Cluster now provides the MySQL Server with better information on the available indexes which allows the MySQL optimizer to automatically produce better query execution plans. Previously it was up to the user to manually provide hints to the optimizer. The second new feature is Adaptive Query Localization which allows the work of the join to be distributed across the data nodes (local to the data it’s working with) rather than up in the MySQL Server; this allows more computing power to be applied to calculating the join as well as dramatically reducing the number of messages being passed around the system. The combined result is that your joins can now run MUCH faster and this post describes a test that results in a 70x speed-up for a real-world query.

    The Query

    11-Way Join used in Test

    The join used in this test is based on a real-world example used for an on-line store/Content Management System. The original query identified all of the media in the system which was appropriate to a particular device and for which a user is entitled to access. As this query is part of a customer’s application I’ve replaced all of the table and column names.

    The join runs across 11 tables (which contain 33.5K rows in total) and produces a result set of 2,060 rows, each with 19 columns. The figure to the right illustrates the join and the full join is included below.

    SELECT
            tab1.uniquekey,
            tab8.name,
            tab8.tab8id,
            tab11.name,
            tab11.tab11id,
            tab11.value,
            tab10.tab10id,
            tab10.name,
            tab2.name,
            tab2.tab2id,
            tab4.value + tab5.value + tab6.value,
            tab3.colx,
            tab3.tab3id,
            tab4.tab4id,
            tab4.name,
            tab5.tab5id,
            tab5.name,
            tab6.tab6id,
            tab6.name
    FROM
            tab1,tab2,tab3,tab4,tab5,tab6,tab7,tab8,tab9,tab10,tab11
    WHERE
            tab7.tab2id = tab2.tab2id	AND
            tab7.tab8id = tab8.tab8id	AND
            tab9.tab2id = tab2.tab2id	AND
    	tab9.tab10id = tab10.tab10id	AND
    	tab10.tab11id = tab11.tab11id	AND
            tab3.tab2id = tab2.tab2id	AND
    	tab3.tab4id = tab4.tab4id	AND
    	tab4.tab5id = tab5.tab5id	AND
    	tab4.colz =  'Y'		AND
    	tab5.tab6id = tab6.tab6id	AND
    	tab6.tab6id IN (6)		AND
    	(tab3.tab4id IN (66, 77, 88))	AND
    	tab1.tab2id = tab2.tab2id	AND
    	tab1.colx = 6;

    Enabling AQL

    First of all, make sure that you’re using the GA version of MySQL Cluster (7.2.4 or later); the Open Source version is available from http://dev.mysql.com/downloads/cluster/#downloads

    and the commercial version from the Oracle Software Delivery Cloud. You can double check that AQL is enabled:

    mysql> show variables like 'ndb_join_pushdown';
    
    | ndb_join_pushdown                   | ON |

    Running the Query & Results

    Test configuration

    To get the full benefit from AQL, you should run “ANALYZE TABLE;” once for each of the tables (no need to repeat for every query and it only needs running on one MySQL Server in the Cluster). This is very important and you should start doing this as a matter of course when you create or modify a table.

    For this test, 3 machines were used:

    1. Intel Core 2 Quad Core @2.83 GHz; 8 Gbytes RAM; single, multi-threaded data node (ndbmtd)
    2. Intel Core 2 Quad Core @2.83 GHz; 8 Gbytes RAM; single, multi-threaded data node (ndbmtd)
    3. 4 Core Fedora VM running on VirtualBox on Windows 7, single MySQL Server

    The query was then run and compared to MySQL CLuster 7.1.15a:

    MySQL Cluster 7.1.15a 1 minute 27.23 secs
    MySQL Cluster 7.2.1 (without having run ANALYZE TABLE) 1 minute 5.3 secs 1.33x Cluster 7.1
    MySQL Cluster 7.2.1 (having run ANALYZE TABLE) 1.26 secs 69.23x Cluster 7.1

    How it Works

    Classic Nested-Loop-Join

    Traditionally, joins have been implemented in the MySQL Server where the query was executed. This is implemented as a nested-loop join; for every row from the first part of the join, a request has to be sent to the data nodes in order to fetch the data for the next level of the join and for every row in that level…. This method can result in a lot of network messages which slows down the query (as well as wasting resources). When turned on, Adaptive Query Localization results in the hard work being pushed down to the data nodes where the data is locally accessible. As a bonus, the work is divided amongst the pool of data nodes and so you get parallel execution.

    NDB API

    I’ll leave the real deep and dirty details to others but cover the basic concepts here. All API nodes access the data nodes using the native C++ NDB API, the MySQL Server is one example of an API node (the new Memcached Cluster API is another). This API has been expanded to allow parameterised or linked queries where the input from one query is dependent on the previous one. To borrow an example from an excellent post by Frazer Clement on the topic, the classic way to implement a join would be…

    SQL > select t1.b, t2.c from t1,t2 where t1.pk=22 and t1.b=t2.pk;
      ndbapi > read column b from t1 where pk = 22;
                  [round trip]
               (b = 15)
      ndbapi > read column c from t2 where pk = 15;
                  [round trip]
               (c = 30)
               [ return b = 15, c = 30 ]

    Using the new functionality this can be performed with a single network round trip where the second read operation is dependent on the results of the first…

      ndbapi > read column @b:=b from t1 where pk = 22;
               read column c from t2 where pk=@b;
                  [round trip]
               (b = 15, c = 30)
               [ return b = 15, c = 30 ]

    You can check whether your query is fitting these rules using EXPLAIN, for example:

    mysql> set ndb_join_pushdown=on;
    mysql> EXPLAIN SELECT COUNT(*) FROM residents,postcodes WHERE residents.postcode=postcodes.postcode AND postcodes.town="MAIDENHEAD";
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+--------------------------------------------------------------------------+
    | id | select_type | table     | type   | possible_keys | key     | key_len | ref                          | rows   | Extra                                                                    |
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+--------------------------------------------------------------------------+
    | 1  | SIMPLE      | residents | ALL    | NULL          | NULL    | NULL    | NULL                         | 100000 | Parent of 2 pushed join@1                                                |
    | 1  | SIMPLE      | postcodes | eq_ref | PRIMARY       | PRIMARY | 22      | clusterdb.residents.postcode | 1      | Child of 'residents' in pushed join@1; Using where with pushed condition |
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+--------------------------------------------------------------------------+
    mysql> EXPLAIN EXTENDED SELECT COUNT(*) FROM residents,postcodes,towns
      WHERE residents.postcode=postcodes.postcode AND
      postcodes.town=towns.town AND towns.county="Berkshire";
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+----------+------------------------------------------------------------------------------------------------------------------------+
    | id | select_type | table     | type   | possible_keys | key     | key_len | ref                          | rows   | filtered | Extra                                                                                                                  |
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+----------+------------------------------------------------------------------------------------------------------------------------+
    | 1  | SIMPLE      | residents | ALL    | NULL          | NULL    | NULL    | NULL                         | 100000 | 100.00   | Parent of 3 pushed join@1                                                                                              |
    | 1  | SIMPLE      | postcodes | eq_ref | PRIMARY       | PRIMARY | 22      | clusterdb.residents.postcode | 1      | 100.00   | Child of 'residents' in pushed join@1                                                                                  |
    | 1  | SIMPLE      | towns     | eq_ref | PRIMARY       | PRIMARY | 22      | clusterdb.postcodes.town     | 1      | 100.00   | Child of 'postcodes' in pushed join@1; Using where with pushed condition: (`clusterdb`.`towns`.`county` = 'Berkshire') |
    +----+-------------+-----------+--------+---------------+---------+---------+------------------------------+--------+----------+------------------------------------------------------------------------------------------------------------------------+

    Note that if you want to check for more details why your join isn’t currently being pushed down to the data node then you can use “EXPLAIN EXTENDED” and then “SHOW WARNINGS” to get more hints. Hopefully that will allow you to tweak your queries to get the best improvements.

    PLEASE let us know your experiences and give us examples of queries that worked well and (just as importantly) those that didn’t so that we can improve the feature – just leave a comment on this Blog with your table schemas, your query and your before/after timings.

  • Chance to give your views on MySQL Cluster 7.2 content

    Posted on January 27th, 2012 admin No comments

    MySQL Cluster 7.2 Quick PollThe MySQL Cluster 7.2 Development Milestone Release has been out for a while now and we’d love to hear which are your favourite features – it takes just a few seconds to complete the Quick-Poll. It should literally take seconds to complete and will provide us with valuable feedback on the kind of features are most useful – so that we can build more of them in the future!

  • 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 2 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
    replicate-ignore-table=mysql.ndb_replication
    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

    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.