14.21 InnoDB memcached Plugin

The 'InnoDB' 'memcached' plugin ('daemon_memcached') provides an integrated 'memcached' daemon that automatically stores and retrieves data from 'InnoDB' tables, turning the MySQL server into a fast 'key-value store'. Instead of formulating queries in SQL, you can use simple 'get', 'set', and 'incr' operations that avoid the performance overhead associated with SQL parsing and constructing a query optimization plan. You can also access the same 'InnoDB' tables through SQL for convenience, complex queries, bulk operations, and other strengths of traditional database software.

This 'NoSQL-style' interface uses the 'memcached' API to speed up database operations, letting 'InnoDB' handle memory caching using its buffer pool mechanism. Data modified through 'memcached' operations such as 'add', 'set', and 'incr' are stored to disk, in 'InnoDB' tables. The combination of 'memcached' simplicity and 'InnoDB' reliability and consistency provides users with the best of both worlds, as explained in note innodb-memcached-benefits::. For an architectural overview, see note innodb-memcached-intro::.

 File: manual.info.tmp, Node: innodb-memcached-benefits, Next: innodb-memcached-intro, Prev: innodb-memcached, Up: innodb-memcached

14.21.1 Benefits of the InnoDB memcached Plugin

This section outlines advantages the 'daemon_memcached' plugin. The combination of 'InnoDB' tables and 'memcached' offers advantages over using either by themselves.

 File: manual.info.tmp, Node: innodb-memcached-intro, Next: innodb-memcached-setup, Prev: innodb-memcached-benefits, Up: innodb-memcached

14.21.2 InnoDB memcached Architecture

The 'InnoDB' 'memcached' plugin implements 'memcached' as a MySQL plugin daemon that accesses the 'InnoDB' storage engine directly, bypassing the MySQL SQL layer.

The following diagram illustrates how an application accesses data through the 'daemon_memcached' plugin, compared with SQL.

FIGURE GOES HERE: MySQL Server with Integrated 'memcached' Server

Features of the 'daemon_memcached' plugin:

 File: manual.info.tmp, Node: innodb-memcached-setup, Next: innodb-memcached-security, Prev: innodb-memcached-intro, Up: innodb-memcached

14.21.3 Setting Up the InnoDB memcached Plugin

This section describes how to set up the 'daemon_memcached' plugin on a MySQL server. Because the 'memcached' daemon is tightly integrated with the MySQL server to avoid network traffic and minimize latency, you perform this process on each MySQL instance that uses this feature.

Note:

Before setting up the 'daemon_memcached' plugin, consult *note innodb-memcached-security:: to understand the security procedures required to prevent unauthorized access.

Prerequisites

Installing and Configuring the InnoDB memcached Plugin

  1. Configure the 'daemon_memcached' plugin so it can interact with 'InnoDB' tables by running the 'innodb_memcached_config.sql' configuration script, which is located in 'MYSQL_HOME/share'. This script installs the 'innodb_memcache' database with three required tables ('cache_policies', 'config_options', and 'containers'). It also installs the 'demo_test' sample table in the 'test' database.

      mysql> source MYSQL_HOME/share/innodb_memcached_config.sql

    Running the 'innodb_memcached_config.sql' script is a one-time operation. The tables remain in place if you later uninstall and re-install the 'daemon_memcached' plugin.

      mysql> USE innodb_memcache;
      mysql> SHOW TABLES;
      +---------------------------+
      | Tables_in_innodb_memcache |
      +---------------------------+
      | cache_policies            |
      | config_options            |
      | containers                |
      +---------------------------+
    
      mysql> USE test;
      mysql> SHOW TABLES;
      +----------------+
      | Tables_in_test |
      +----------------+
      | demo_test      |
      +----------------+

    Of these tables, the 'innodb_memcache.containers' table is the most important. Entries in the 'containers' table provide a mapping to 'InnoDB' table columns. Each 'InnoDB' table used with the 'daemon_memcached' plugin requires an entry in the 'containers' table.

    The 'innodb_memcached_config.sql' script inserts a single entry in the 'containers' table that provides a mapping for the 'demo_test' table. It also inserts a single row of data into the 'demo_test' table. This data allows you to immediately verify the installation after the setup is completed.

      mysql> SELECT * FROM innodb_memcache.containers\G
      *************************** 1. row ***************************
                        name: aaa
                   db_schema: test
                    db_table: demo_test
                 key_columns: c1
               value_columns: c2
                       flags: c3
                  cas_column: c4
          expire_time_column: c5
      unique_idx_name_on_key: PRIMARY
    
      mysql> SELECT * FROM test.demo_test;
      +----+------------------+------+------+------+
      | c1 | c2               | c3   | c4   | c5   |
      +----+------------------+------+------+------+
      | AA | HELLO, HELLO     |    8 |    0 |    0 |
      +----+------------------+------+------+------+

    For more information about 'innodb_memcache' tables and the 'demo_test' sample table, see *note innodb-memcached-internals::.

  2. Activate the 'daemon_memcached' plugin by running the *note 'INSTALL PLUGIN': install-plugin. statement:

      mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

    Once the plugin is installed, it is automatically activated each time the MySQL server is restarted.

Verifying the InnoDB and memcached Setup

To verify the 'daemon_memcached' plugin setup, use a 'telnet' session to issue 'memcached' commands. By default, the 'memcached' daemon listens on port 11211.

  1. Retrieve data from the 'test.demo_test' table. The single row of data in the 'demo_test' table has a key value of 'AA'.

      telnet localhost 11211
      Trying 127.0.0.1...
      Connected to localhost.
      Escape character is '^]'.
      get AA
      VALUE AA 8 12
      HELLO, HELLO
      END
  2. Insert data using a 'set' command.

      set BB 10 0 16
      GOODBYE, GOODBYE
      STORED

    where:

    * 'set' is the command to store a value
    
    * 'BB' is the key
    
    * '10' is a flag for the operation; ignored by 'memcached' but
      may be used by the client to indicate any type of information;
      specify '0' if unused
    
    * '0' is the expiration time (TTL); specify '0' if unused
    
    * '16' is the length of the supplied value block in bytes
    
    * 'GOODBYE, GOODBYE' is the value that is stored
  3. Verify that the data inserted is stored in MySQL by connecting to the MySQL server and querying the 'test.demo_test' table.

      mysql> SELECT * FROM test.demo_test;
      +----+------------------+------+------+------+
      | c1 | c2               | c3   | c4   | c5   |
      +----+------------------+------+------+------+
      | AA | HELLO, HELLO     |    8 |    0 |    0 |
      | BB | GOODBYE, GOODBYE |   10 |    1 |    0 |
      +----+------------------+------+------+------+
  4. Return to the telnet session and retrieve the data that you inserted earlier using key 'BB'.

      get BB
      VALUE BB 10 16
      GOODBYE, GOODBYE
      END
      quit

If you shut down the MySQL server, which also shuts off the integrated 'memcached' server, further attempts to access the 'memcached' data fail with a connection error. Normally, the 'memcached' data also disappears at this point, and you would require application logic to load the data back into memory when 'memcached' is restarted. However, the 'InnoDB' 'memcached' plugin automates this process for you.

When you restart MySQL, 'get' operations once again return the key-value pairs you stored in the earlier 'memcached' session. When a key is requested and the associated value is not already in the memory cache, the value is automatically queried from the MySQL 'test.demo_test' table.

Creating a New Table and Column Mapping

This example shows how to setup your own 'InnoDB' table with the 'daemon_memcached' plugin.

  1. Create an 'InnoDB' table. The table must have a key column with a unique index. The key column of the city table is 'city_id', which is defined as the primary key. The table must also include columns for 'flags', 'cas', and 'expiry' values. There may be one or more value columns. The 'city' table has three value columns ('name', 'state', 'country').

    Note:

    There is no special requirement with respect to column names as along as a valid mapping is added to the 'innodb_memcache.containers' table.

      mysql> CREATE TABLE city (
             city_id VARCHAR(32),
             name VARCHAR(1024),
             state VARCHAR(1024),
             country VARCHAR(1024),
             flags INT,
             cas BIGINT UNSIGNED,
             expiry INT,
             primary key(city_id)
             ) ENGINE=InnoDB;
  2. Add an entry to the 'innodb_memcache.containers' table so that the 'daemon_memcached' plugin knows how to access the 'InnoDB' table. The entry must satisfy the 'innodb_memcache.containers' table definition. For a description of each field, see *note innodb-memcached-internals::.

      mysql> DESCRIBE innodb_memcache.containers;
      +------------------------+--------------+------+-----+---------+-------+
      | Field                  | Type         | Null | Key | Default | Extra |
      +------------------------+--------------+------+-----+---------+-------+
      | name                   | varchar(50)  | NO   | PRI | NULL    |       |
      | db_schema              | varchar(250) | NO   |     | NULL    |       |
      | db_table               | varchar(250) | NO   |     | NULL    |       |
      | key_columns            | varchar(250) | NO   |     | NULL    |       |
      | value_columns          | varchar(250) | YES  |     | NULL    |       |
      | flags                  | varchar(250) | NO   |     | 0       |       |
      | cas_column             | varchar(250) | YES  |     | NULL    |       |
      | expire_time_column     | varchar(250) | YES  |     | NULL    |       |
      | unique_idx_name_on_key | varchar(250) | NO   |     | NULL    |       |
      +------------------------+--------------+------+-----+---------+-------+

    The 'innodb_memcache.containers' table entry for the city table is defined as:

      mysql> INSERT INTO `innodb_memcache`.`containers` (
             `name`, `db_schema`, `db_table`, `key_columns`, `value_columns`,
             `flags`, `cas_column`, `expire_time_column`, `unique_idx_name_on_key`)
             VALUES ('default', 'test', 'city', 'city_id', 'name|state|country',
             'flags','cas','expiry','PRIMARY');
    
    * 'default' is specified for the 'containers.name' column to
      configure the 'city' table as the default 'InnoDB' table to be
      used with the 'daemon_memcached' plugin.
    
    * Multiple 'InnoDB' table columns ('name', 'state', 'country')
      are mapped to 'containers.value_columns' using a '|'
      delimiter.
    
    * The 'flags', 'cas_column', and 'expire_time_column' fields of
      the 'innodb_memcache.containers' table are typically not
      significant in applications using the 'daemon_memcached'
      plugin.  However, a designated 'InnoDB' table column is
      required for each.  When inserting data, specify '0' for these
      columns if they are unused.
  3. After updating the 'innodb_memcache.containers' table, restart the 'daemon_memcache' plugin to apply the changes.

      mysql> UNINSTALL PLUGIN daemon_memcached;
    
      mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
  4. Using telnet, insert data into the 'city' table using a 'memcached' 'set' command.

      telnet localhost 11211
      Trying 127.0.0.1...
      Connected to localhost.
      Escape character is '^]'.
      set B 0 0 22
      BANGALORE|BANGALORE|IN
      STORED
  5. Using MySQL, query the 'test.city' table to verify that the data you inserted was stored.

      mysql> SELECT * FROM test.city;
      +---------+-----------+-----------+---------+-------+------+--------+
      | city_id | name      | state     | country | flags | cas  | expiry |
      +---------+-----------+-----------+---------+-------+------+--------+
      | B       | BANGALORE | BANGALORE | IN      |     0 |    3 |      0 |
      +---------+-----------+-----------+---------+-------+------+--------+
  6. Using MySQL, insert additional data into the 'test.city' table.

      mysql> INSERT INTO city VALUES ('C','CHENNAI','TAMIL NADU','IN', 0, 0 ,0);
      mysql> INSERT INTO city VALUES ('D','DELHI','DELHI','IN', 0, 0, 0);
      mysql> INSERT INTO city VALUES ('H','HYDERABAD','TELANGANA','IN', 0, 0, 0);
      mysql> INSERT INTO city VALUES ('M','MUMBAI','MAHARASHTRA','IN', 0, 0, 0);

    Note:

    It is recommended that you specify a value of '0' for the 'flags', 'cas_column', and 'expire_time_column' fields if they are unused.

  7. Using telnet, issue a 'memcached' 'get' command to retrieve data you inserted using MySQL.

      get H
      VALUE H 0 22
      HYDERABAD|TELANGANA|IN
      END

Configuring the InnoDB memcached Plugin

Traditional 'memcached' configuration options may be specified in a MySQL configuration file or a *note 'mysqld': mysqld. startup string, encoded in the argument of the 'daemon_memcached_option' configuration parameter. 'memcached' configuration options take effect when the plugin is loaded, which occurs each time the MySQL server is started.

For example, to make 'memcached' listen on port 11222 instead of the default port 11211, specify '-p11222' as an argument of the 'daemon_memcached_option' configuration option:

 mysqld .... --daemon_memcached_option="-p11222"

Other 'memcached' options can be encoded in the 'daemon_memcached_option' string. For example, you can specify options to reduce the maximum number of simultaneous connections, change the maximum memory size for a key-value pair, or enable debugging messages for the error log, and so on.

There are also configuration options specific to the 'daemon_memcached' plugin. These include:

By default, you do not need to modify 'daemon_memcached_engine_lib_name' or 'daemon_memcached_engine_lib_path'. You might configure these options if, for example, you want to use a different storage engine for 'memcached' (such as the NDB 'memcached' engine).

'daemon_memcached' plugin configuration parameters may be specified in the MySQL configuration file or in a *note 'mysqld': mysqld. startup string. They take effect when you load the 'daemon_memcached' plugin.

When making changes to 'daemon_memcached' plugin configuration, reload the plugin to apply the changes. To do so, issue the following statements:

 mysql> UNINSTALL PLUGIN daemon_memcached;

 mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

Configuration settings, required tables, and data are preserved when the plugin is restarted.

For additional information about enabling and disabling plugins, see *note plugin-loading::.

 File: manual.info.tmp, Node: innodb-memcached-security, Next: innodb-memcached-developing, Prev: innodb-memcached-setup, Up: innodb-memcached

14.21.4 Security Considerations for the InnoDB memcached Plugin

Caution:

Consult this section before deploying the 'daemon_memcached' plugin on a production server, or even on a test server if the MySQL instance contains sensitive data.

Because 'memcached' does not use an authentication mechanism by default, and the optional SASL authentication is not as strong as traditional DBMS security measures, only keep non-sensitive data in the MySQL instance that uses the 'daemon_memcached' plugin, and wall off any servers that use this configuration from potential intruders. Do not allow 'memcached' access to these servers from the Internet; only allow access from within a firewalled intranet, ideally from a subnet whose membership you can restrict.

Password-Protecting memcached Using SASL

SASL support provides the capability to protect your MySQL database from unauthenticated access through 'memcached' clients. This section explains how to enable SASL with the 'daemon_memcached' plugin. The steps are almost identical to those performed to enabled SASL for a traditional 'memcached' server.

SASL stands for 'Simple Authentication and Security Layer', a standard for adding authentication support to connection-based protocols. 'memcached' added SASL support in version 1.4.3.

SASL authentication is only supported with the binary protocol.

'memcached' clients are only able to access 'InnoDB' tables that are registered in the 'innodb_memcache.containers' table. Even though a DBA can place access restrictions on such tables, access through 'memcached' applications cannot be controlled. For this reason, SASL support is provided to control access to 'InnoDB' tables associated with the 'daemon_memcached' plugin.

The following section shows how to build, enable, and test an SASL-enabled 'daemon_memcached' plugin.

Building and Enabling SASL with the InnoDB memcached Plugin

By default, an SASL-enabled 'daemon_memcached' plugin is not included in MySQL release packages, since an SASL-enabled 'daemon_memcached' plugin requires building 'memcached' with SASL libraries. To enable SASL support, download the MySQL source and rebuild the 'daemon_memcached' plugin after downloading the SASL libraries:

  1. Install the SASL development and utility libraries. For example, on Ubuntu, use 'apt-get' to obtain the libraries:

      sudo apt-get -f install libsasl2-2 sasl2-bin libsasl2-2 libsasl2-dev libsasl2-modules
  2. Build the 'daemon_memcached' plugin shared libraries with SASL capability by adding 'ENABLE_MEMCACHED_SASL=1' to your 'cmake' options. 'memcached' also provides simple cleartext password support, which facilitates testing. To enable simple cleartext password support, specify the 'ENABLE_MEMCACHED_SASL_PWDB=1' 'cmake' option.

    In summary, add following three 'cmake' options:

      cmake ... -DWITH_INNODB_MEMCACHED=1 -DENABLE_MEMCACHED_SASL=1 -DENABLE_MEMCACHED_SASL_PWDB=1
  3. Install the 'daemon_memcached' plugin, as described in *note innodb-memcached-setup::.

  4. Configure a user name and password file. (This example uses 'memcached' simple cleartext password support.)

    1. In a file, create a user named 'testname' and define the password as 'testpasswd':

         echo "testname:testpasswd:::::::" >/home/jy/memcached-sasl-db
    2. Configure the 'MEMCACHED_SASL_PWDB' environment variable to inform 'memcached' of the user name and password file:

         export MEMCACHED_SASL_PWDB=/home/jy/memcached-sasl-db
    3. Inform 'memcached' that a cleartext password is used:

         echo "mech_list: plain" > /home/jy/work2/msasl/clients/memcached.conf
         export SASL_CONF_PATH=/home/jy/work2/msasl/clients
  5. Enable SASL by restarting the MySQL server with the 'memcached' '-S' option encoded in the 'daemon_memcached_option' configuration parameter:

      mysqld ... --daemon_memcached_option="-S"
  6. To test the setup, use an SASL-enabled client such as SASL-enabled libmemcached (https://code.launchpad.net/~trond-norbye/libmemcached/sasl).

      memcp --servers=localhost:11211 --binary  --username=testname
        --password=PASSWORD myfile.txt
    
      memcat --servers=localhost:11211 --binary --username=testname
        --password=PASSWORD myfile.txt

    If you specify an incorrect user name or password, the operation is rejected with a 'memcache error AUTHENTICATION FAILURE' message. In this case, examine the cleartext password set in the 'memcached-sasl-db' file to verify that the credentials you supplied are correct.

There are other methods to test SASL authentication with 'memcached', but the method described above is the most straightforward.

 File: manual.info.tmp, Node: innodb-memcached-developing, Next: innodb-memcached-replication, Prev: innodb-memcached-security, Up: innodb-memcached

14.21.5 Writing Applications for the InnoDB memcached Plugin

Typically, writing an application for the 'InnoDB' 'memcached' plugin involves some degree of rewriting or adapting existing code that uses MySQL or the 'memcached' API.

The following sections explore these points in more detail.

 File: manual.info.tmp, Node: innodb-memcached-porting-mysql, Next: innodb-memcached-porting-memcached, Prev: innodb-memcached-developing, Up: innodb-memcached-developing

14.21.5.1 Adapting an Existing MySQL Schema for the InnoDB memcached Plugin ...........................................................................

Consider these aspects of 'memcached' applications when adapting an existing MySQL schema or application to use the 'daemon_memcached' plugin:

This example shows how to use your own table with a sample Python application that uses 'memcached' for data manipulation.

The example assumes that the 'daemon_memcached' plugin is installed as described in *note innodb-memcached-setup::. It also assumes that your system is configured to run a Python script that uses the 'python-memcache' module.

  1. Create the 'multicol' table which stores country information including population, area, and driver side data (''R'' for right and ''L'' for left).

      mysql> USE test;
    
      mysql> CREATE TABLE `multicol` (
              `country` varchar(128) NOT NULL DEFAULT '',
              `population` varchar(10) DEFAULT NULL,
              `area_sq_km` varchar(9) DEFAULT NULL,
              `drive_side` varchar(1) DEFAULT NULL,
              `c3` int(11) DEFAULT NULL,
              `c4` bigint(20) unsigned DEFAULT NULL,
              `c5` int(11) DEFAULT NULL,
              PRIMARY KEY (`country`)
              ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
  2. Insert a record into the 'innodb_memcache.containers' table so that the 'daemon_memcached' plugin can access the 'multicol' table.

      mysql> INSERT INTO innodb_memcache.containers
             (name,db_schema,db_table,key_columns,value_columns,flags,cas_column,
             expire_time_column,unique_idx_name_on_key)
             VALUES
             ('bbb','test','multicol','country','population,area_sq_km,drive_side',
             'c3','c4','c5','PRIMARY');
    
      mysql> COMMIT;
    
    * The 'innodb_memcache.containers' record for the 'multicol'
      table specifies a 'name' value of ''bbb'', which is the table
      identifier.
    
      *Note*:
    
      If a single 'InnoDB' table is used for all 'memcached'
      applications, the 'name' value can be set to 'default' to
      avoid using '@@' notation to switch tables.
    
    * The 'db_schema' column is set to 'test', which is the name of
      the database where the 'multicol' table resides.
    
    * The 'db_table' column is set to 'multicol', which is the name
      of the 'InnoDB' table.
    
    * 'key_columns' is set to the unique 'country' column.  The
      'country' column is defined as the primary key in the
      'multicol' table definition.
    
    * Rather than a single 'InnoDB' table column to hold a composite
      data value, data is divided among three table columns
      ('population', 'area_sq_km', and 'drive_side').  To
      accommodate multiple value columns, a comma-separated list of
      columns is specified in the 'value_columns' field.  The
      columns defined in the 'value_columns' field are the columns
      used when storing or retrieving values.
    
    * Values for the 'flags', 'expire_time', and 'cas_column' fields
      are based on values used in the 'demo.test' sample table.
      These fields are typically not significant in applications
      that use the 'daemon_memcached' plugin because MySQL keeps
      data synchronized, and there is no need to worry about data
      expiring or becoming stale.
    
    * The 'unique_idx_name_on_key' field is set to 'PRIMARY', which
      refers to the primary index defined on the unique 'country'
      column in the 'multicol' table.
  3. Copy the sample Python application into a file. In this example, the sample script is copied to a file named 'multicol.py'.

    The sample Python application inserts data into the 'multicol' table and retrieves data for all keys, demonstrating how to access an 'InnoDB' table through the 'daemon_memcached' plugin.

      import sys, os
      import memcache
    
      def connect_to_memcached():
        memc = memcache.Client(['127.0.0.1:11211'], debug=0);
        print "Connected to memcached."
        return memc
    
      def banner(message):
        print
        print "=" * len(message)
        print message
        print "=" * len(message)
    
      country_data = [
      ("Canada","34820000","9984670","R"),
      ("USA","314242000","9826675","R"),
      ("Ireland","6399152","84421","L"),
      ("UK","62262000","243610","L"),
      ("Mexico","113910608","1972550","R"),
      ("Denmark","5543453","43094","R"),
      ("Norway","5002942","385252","R"),
      ("UAE","8264070","83600","R"),
      ("India","1210193422","3287263","L"),
      ("China","1347350000","9640821","R"),
      ]
    
      def switch_table(memc,table):
        key = "@@" + table
        print "Switching default table to '" + table + "' by issuing GET for '" + key + "'."
        result = memc.get(key)
    
      def insert_country_data(memc):
        banner("Inserting initial data via memcached interface")
        for item in country_data:
          country = item[0]
          population = item[1]
          area = item[2]
          drive_side = item[3]
    
          key = country
          value = "|".join([population,area,drive_side])
          print "Key = " + key
          print "Value = " + value
    
          if memc.add(key,value):
            print "Added new key, value pair."
          else:
            print "Updating value for existing key."
            memc.set(key,value)
    
      def query_country_data(memc):
        banner("Retrieving data for all keys (country names)")
        for item in country_data:
          key = item[0]
          result = memc.get(key)
          print "Here is the result retrieved from the database for key " + key + ":"
          print result
          (m_population, m_area, m_drive_side) = result.split("|")
          print "Unpacked population value: " + m_population
          print "Unpacked area value      : " + m_area
          print "Unpacked drive side value: " + m_drive_side
    
      if __name__ == '__main__':
    
        memc = connect_to_memcached()
        switch_table(memc,"bbb")
        insert_country_data(memc)
        query_country_data(memc)
    
        sys.exit(0)

    Sample Python application notes:

    * No database authorization is required to run the application,
      since data manipulation is performed through the 'memcached'
      interface.  The only required information is the port number
      on the local system where the 'memcached' daemon listens.
    
    * To make sure the application uses the 'multicol' table, the
      'switch_table()' function is called, which performs a dummy
      'get' or 'set' request using '@@' notation.  The 'name' value
      in the request is 'bbb', which is the 'multicol' table
      identifier defined in the 'innodb_memcache.containers.name'
      field.
    
      A more descriptive 'name' value might be used in a real-world
      application.  This example simply illustrates that a table
      identifier is specified rather than the table name in 'get
      @@...' requests.
    
    * The utility functions used to insert and query data
      demonstrate how to turn a Python data structure into
      pipe-separated values for sending data to MySQL with 'add' or
      'set' requests, and how to unpack the pipe-separated values
      returned by 'get' requests.  This extra processing is only
      required when mapping a single 'memcached' value to multiple
      MySQL table columns.
  4. Run the sample Python application.

      $> python multicol.py

    If successful, the sample application returns this output:

      Connected to memcached.
      Switching default table to 'bbb' by issuing GET for '@@bbb'.
    
      ==============================================
      Inserting initial data via memcached interface
      ==============================================
      Key = Canada
      Value = 34820000|9984670|R
      Added new key, value pair.
      Key = USA
      Value = 314242000|9826675|R
      Added new key, value pair.
      Key = Ireland
      Value = 6399152|84421|L
      Added new key, value pair.
      Key = UK
      Value = 62262000|243610|L
      Added new key, value pair.
      Key = Mexico
      Value = 113910608|1972550|R
      Added new key, value pair.
      Key = Denmark
      Value = 5543453|43094|R
      Added new key, value pair.
      Key = Norway
      Value = 5002942|385252|R
      Added new key, value pair.
      Key = UAE
      Value = 8264070|83600|R
      Added new key, value pair.
      Key = India
      Value = 1210193422|3287263|L
      Added new key, value pair.
      Key = China
      Value = 1347350000|9640821|R
      Added new key, value pair.
    
      ============================================
      Retrieving data for all keys (country names)
      ============================================
      Here is the result retrieved from the database for key Canada:
      34820000|9984670|R
      Unpacked population value: 34820000
      Unpacked area value      : 9984670
      Unpacked drive side value: R
      Here is the result retrieved from the database for key USA:
      314242000|9826675|R
      Unpacked population value: 314242000
      Unpacked area value      : 9826675
      Unpacked drive side value: R
      Here is the result retrieved from the database for key Ireland:
      6399152|84421|L
      Unpacked population value: 6399152
      Unpacked area value      : 84421
      Unpacked drive side value: L
      Here is the result retrieved from the database for key UK:
      62262000|243610|L
      Unpacked population value: 62262000
      Unpacked area value      : 243610
      Unpacked drive side value: L
      Here is the result retrieved from the database for key Mexico:
      113910608|1972550|R
      Unpacked population value: 113910608
      Unpacked area value      : 1972550
      Unpacked drive side value: R
      Here is the result retrieved from the database for key Denmark:
      5543453|43094|R
      Unpacked population value: 5543453
      Unpacked area value      : 43094
      Unpacked drive side value: R
      Here is the result retrieved from the database for key Norway:
      5002942|385252|R
      Unpacked population value: 5002942
      Unpacked area value      : 385252
      Unpacked drive side value: R
      Here is the result retrieved from the database for key UAE:
      8264070|83600|R
      Unpacked population value: 8264070
      Unpacked area value      : 83600
      Unpacked drive side value: R
      Here is the result retrieved from the database for key India:
      1210193422|3287263|L
      Unpacked population value: 1210193422
      Unpacked area value      : 3287263
      Unpacked drive side value: L
      Here is the result retrieved from the database for key China:
      1347350000|9640821|R
      Unpacked population value: 1347350000
      Unpacked area value      : 9640821
      Unpacked drive side value: R
  5. Query the 'innodb_memcache.containers' table to view the record you inserted earlier for the 'multicol' table. The first record is the sample entry for the 'demo_test' table that is created during the initial 'daemon_memcached' plugin setup. The second record is the entry you inserted for the 'multicol' table.

      mysql> SELECT * FROM innodb_memcache.containers\G
      *************************** 1. row ***************************
                        name: aaa
                   db_schema: test
                    db_table: demo_test
                 key_columns: c1
               value_columns: c2
                       flags: c3
                  cas_column: c4
          expire_time_column: c5
      unique_idx_name_on_key: PRIMARY
      *************************** 2. row ***************************
                        name: bbb
                   db_schema: test
                    db_table: multicol
                 key_columns: country
               value_columns: population,area_sq_km,drive_side
                       flags: c3
                  cas_column: c4
          expire_time_column: c5
      unique_idx_name_on_key: PRIMARY
  6. Query the 'multicol' table to view data inserted by the sample Python application. The data is available for MySQL queries, which demonstrates how the same data can be accessed using SQL or through applications (using the appropriate *note MySQL Connector or API: connectors-apis.).

      mysql> SELECT * FROM test.multicol;
      +---------+------------+------------+------------+------+------+------+
      | country | population | area_sq_km | drive_side | c3   | c4   | c5   |
      +---------+------------+------------+------------+------+------+------+
      | Canada  | 34820000   | 9984670    | R          |    0 |   11 |    0 |
      | China   | 1347350000 | 9640821    | R          |    0 |   20 |    0 |
      | Denmark | 5543453    | 43094      | R          |    0 |   16 |    0 |
      | India   | 1210193422 | 3287263    | L          |    0 |   19 |    0 |
      | Ireland | 6399152    | 84421      | L          |    0 |   13 |    0 |
      | Mexico  | 113910608  | 1972550    | R          |    0 |   15 |    0 |
      | Norway  | 5002942    | 385252     | R          |    0 |   17 |    0 |
      | UAE     | 8264070    | 83600      | R          |    0 |   18 |    0 |
      | UK      | 62262000   | 243610     | L          |    0 |   14 |    0 |
      | USA     | 314242000  | 9826675    | R          |    0 |   12 |    0 |
      +---------+------------+------------+------------+------+------+------+

    Note:

    Always allow sufficient size to hold necessary digits, decimal points, sign characters, leading zeros, and so on when defining the length for columns that are treated as numbers. Too-long values in a string column such as a 'VARCHAR' are truncated by removing some characters, which could produce nonsensical numeric values.

  7. Optionally, run report-type queries on the 'InnoDB' table that stores the 'memcached' data.

    You can produce reports through SQL queries, performing calculations and tests across any columns, not just the 'country' key column. (Because the following examples use data from only a few countries, the numbers are for illustration purposes only.) The following queries return the average population of countries where people drive on the right, and the average size of countries whose names start with 'U':

      mysql> SELECT AVG(population) FROM multicol WHERE drive_side = 'R';
      +-------------------+
      | avg(population)   |
      +-------------------+
      | 261304724.7142857 |
      +-------------------+
    
      mysql> SELECT SUM(area_sq_km) FROM multicol WHERE country LIKE 'U%';
      +-----------------+
      | sum(area_sq_km) |
      +-----------------+
      |        10153885 |
      +-----------------+

    Because the 'population' and 'area_sq_km' columns store character data rather than strongly typed numeric data, functions such as 'AVG()' and 'SUM()' work by converting each value to a number first. This approach does not work for operators such as '<' or '>', for example, when comparing character-based values, '9 > 1000', which is not expected from a clause such as 'ORDER BY population DESC'. For the most accurate type treatment, perform queries against views that cast numeric columns to the appropriate types. This technique lets you issue simple 'SELECT *' queries from database applications, while ensuring that casting, filtering, and ordering is correct. The following example shows a view that can be queried to find the top three countries in descending order of population, with the results reflecting the latest data in the 'multicol' table, and with population and area figures treated as numbers:

      mysql> CREATE VIEW populous_countries AS
             SELECT
             country,
             cast(population as unsigned integer) population,
             cast(area_sq_km as unsigned integer) area_sq_km,
             drive_side FROM multicol
             ORDER BY CAST(population as unsigned integer) DESC
             LIMIT 3;
    
      mysql> SELECT * FROM populous_countries;
      +---------+------------+------------+------------+
      | country | population | area_sq_km | drive_side |
      +---------+------------+------------+------------+
      | China   | 1347350000 |    9640821 | R          |
      | India   | 1210193422 |    3287263 | L          |
      | USA     |  314242000 |    9826675 | R          |
      +---------+------------+------------+------------+
    
      mysql> DESC populous_countries;
      +------------+---------------------+------+-----+---------+-------+
      | Field      | Type                | Null | Key | Default | Extra |
      +------------+---------------------+------+-----+---------+-------+
      | country    | varchar(128)        | NO   |     |         |       |
      | population | bigint(10) unsigned | YES  |     | NULL    |       |
      | area_sq_km | int(9) unsigned     | YES  |     | NULL    |       |
      | drive_side | varchar(1)          | YES  |     | NULL    |       |
      +------------+---------------------+------+-----+---------+-------+

 File: manual.info.tmp, Node: innodb-memcached-porting-memcached, Next: innodb-memcached-tuning, Prev: innodb-memcached-porting-mysql, Up: innodb-memcached-developing

14.21.5.2 Adapting a memcached Application for the InnoDB memcached Plugin ..........................................................................

Consider these aspects of MySQL and 'InnoDB' tables when adapting existing 'memcached' applications to use the 'daemon_memcached' plugin:

 File: manual.info.tmp, Node: innodb-memcached-tuning, Next: innodb-memcached-txn, Prev: innodb-memcached-porting-memcached, Up: innodb-memcached-developing

14.21.5.3 Tuning InnoDB memcached Plugin Performance ....................................................

Because using 'InnoDB' in combination with 'memcached' involves writing all data to disk, whether immediately or sometime later, raw performance is expected to be somewhat slower than using 'memcached' by itself. When using the 'InnoDB' 'memcached' plugin, focus tuning goals for 'memcached' operations on achieving better performance than equivalent SQL operations.

Benchmarks suggest that queries and DML operations (inserts, updates, and deletes) that use the 'memcached' interface are faster than traditional SQL. DML operations typically see a larger improvements. Therefore, consider adapting write-intensive applications to use the 'memcached' interface first. Also consider prioritizing adaptation of write-intensive applications that use fast, lightweight mechanisms that lack reliability.

Adapting SQL Queries

The types of queries that are most suited to simple 'GET' requests are those with a single clause or a set of 'AND' conditions in the 'WHERE' clause:

 SQL:
 SELECT col FROM tbl WHERE key = 'key_value';

 memcached:
 get key_value

 SQL:
 SELECT col FROM tbl WHERE col1 = val1 and col2 = val2 and col3 = val3;

 memcached:
 # Since you must always know these 3 values to look up the key,
 # combine them into a unique string and use that as the key
 # for all ADD, SET, and GET operations.
 key_value = val1 + ":" + val2 + ":" + val3
 get key_value

 SQL:
 SELECT 'key exists!' FROM tbl
   WHERE EXISTS (SELECT col1 FROM tbl WHERE KEY = 'key_value') LIMIT 1;

 memcached:
 # Test for existence of key by asking for its value and checking if the call succeeds,
 # ignoring the value itself. For existence checking, you typically only store a very
 # short value such as "1".
 get key_value

Using System Memory

For best performance, deploy the 'daemon_memcached' plugin on machines that are configured as typical database servers, where the majority of system RAM is devoted to the 'InnoDB' buffer pool, through the 'innodb_buffer_pool_size' configuration option. For systems with multi-gigabyte buffer pools, consider raising the value of 'innodb_buffer_pool_instances' for maximum throughput when most operations involve data that is already cached in memory.

Reducing Redundant I/O

'InnoDB' has a number of settings that let you choose the balance between high reliability, in case of a crash, and the amount of I/O overhead during high write workloads. For example, consider setting the 'innodb_doublewrite' to '0' and 'innodb_flush_log_at_trx_commit' to '2'. Measure performance with different 'innodb_flush_method' settings.

Note:

'innodb_support_xa' is deprecated; expect it to be removed in a future release. As of MySQL 5.7.10, 'InnoDB' support for two-phase commit in XA transactions is always enabled and disabling 'innodb_support_xa' is no longer permitted.

For other ways to reduce or tune I/O for table operations, see *note optimizing-innodb-diskio::.

Reducing Transactional Overhead

A default value of 1 for 'daemon_memcached_r_batch_size' and 'daemon_memcached_w_batch_size' is intended for maximum reliability of results and safety of stored or updated data.

Depending on the type of application, you might increase one or both of these settings to reduce the overhead of frequent commit operations. On a busy system, you might increase 'daemon_memcached_r_batch_size', knowing that changes to data made through SQL may not become visible to 'memcached' immediately (that is, until N more 'get' operations are processed). When processing data where every write operation must be reliably stored, leave 'daemon_memcached_w_batch_size' set to '1'. Increase the setting when processing large numbers of updates intended only for statistical analysis, where losing the last N updates in an unexpected exit is an acceptable risk.

For example, imagine a system that monitors traffic crossing a busy bridge, recording data for approximately 100,000 vehicles each day. If the application counts different types of vehicles to analyze traffic patterns, changing 'daemon_memcached_w_batch_size' from '1' to '100' reduces I/O overhead for commit operations by 99%. In case of an outage, a maximum of 100 records are lost, which may be an acceptable margin of error. If instead the application performed automated toll collection for each car, you would set 'daemon_memcached_w_batch_size' to '1' to ensure that each toll record is immediately saved to disk.

Because of the way 'InnoDB' organizes 'memcached' key values on disk, if you have a large number of keys to create, it may be faster to sort the data items by key value in the application and 'add' them in sorted order, rather than create keys in arbitrary order.

The 'memslap' command, which is part of the regular 'memcached' distribution but not included with the 'daemon_memcached' plugin, can be useful for benchmarking different configurations. It can also be used to generate sample key-value pairs to use in your own benchmarks.

 File: manual.info.tmp, Node: innodb-memcached-txn, Next: innodb-memcached-dml, Prev: innodb-memcached-tuning, Up: innodb-memcached-developing

14.21.5.4 Controlling Transactional Behavior of the InnoDB memcached Plugin ...........................................................................

Unlike traditional 'memcached', the 'daemon_memcached' plugin allows you to control durability of data values produced through calls to 'add', 'set', 'incr', and so on. By default, data written through the 'memcached' interface is stored to disk, and calls to 'get' return the most recent value from disk. Although the default behavior does not offer the best possible raw performance, it is still fast compared to the SQL interface for 'InnoDB' tables.

As you gain experience using the 'daemon_memcached' plugin, you can consider relaxing durability settings for non-critical classes of data, at the risk of losing some updated values in the event of an outage, or returning data that is slightly out-of-date.

Frequency of Commits

One tradeoff between durability and raw performance is how frequently new and changed data is committed. If data is critical, is should be committed immediately so that it is safe in case of an unexpected exit or outage. If data is less critical, such as counters that are reset after an unexpected exit or logging data that you can afford to lose, you might prefer higher raw throughput that is available with less frequent commits.

When a 'memcached' operation inserts, updates, or deletes data in the underlying 'InnoDB' table, the change might be committed to the 'InnoDB' table instantly (if 'daemon_memcached_w_batch_size=1') or some time later (if the 'daemon_memcached_w_batch_size' value is greater than 1). In either case, the change cannot be rolled back. If you increase the value of 'daemon_memcached_w_batch_size' to avoid high I/O overhead during busy times, commits could become infrequent when the workload decreases. As a safety measure, a background thread automatically commits changes made through the 'memcached' API at regular intervals. The interval is controlled by the 'innodb_api_bk_commit_interval' configuration option, which has a default setting of '5' seconds.

When a 'memcached' operation inserts or updates data in the underlying 'InnoDB' table, the changed data is immediately visible to other 'memcached' requests because the new value remains in the memory cache, even if it is not yet committed on the MySQL side.

Transaction Isolation

When a 'memcached' operation such as 'get' or 'incr' causes a query or DML operation on the underlying 'InnoDB' table, you can control whether the operation sees the very latest data written to the table, only data that has been committed, or other variations of transaction isolation level. Use the 'innodb_api_trx_level' configuration option to control this feature. The numeric values specified for this option correspond to isolation levels such as 'REPEATABLE READ'. See the description of the 'innodb_api_trx_level' option for information about other settings.

A strict isolation level ensures that data you retrieve is not rolled back or changed suddenly causing subsequent queries to return different values. However, strict isolation levels require greater locking overhead, which can cause waits. For a NoSQL-style application that does not use long-running transactions, you can typically use the default isolation level or switch to a less strict isolation level.

Disabling Row Locks for memcached DML Operations

The 'innodb_api_disable_rowlock' option can be used to disable row locks when 'memcached' requests through the 'daemon_memcached' plugin cause DML operations. By default, 'innodb_api_disable_rowlock' is set to 'OFF' which means that 'memcached' requests row locks for 'get' and 'set' operations. When 'innodb_api_disable_rowlock' is set to 'ON', 'memcached' requests a table lock instead of row locks.

The 'innodb_api_disable_rowlock' option is not dynamic. It must be specified at startup on the *note 'mysqld': mysqld. command line or entered in a MySQL configuration file.

Allowing or Disallowing DDL

By default, you can perform DDL operations such as note 'ALTER TABLE': alter-table. on tables used by the 'daemon_memcached' plugin. To avoid potential slowdowns when these tables are used for high-throughput applications, disable DDL operations on these tables by enabling 'innodb_api_enable_mdl' at startup. This option is less appropriate when accessing the same tables through both 'memcached' and SQL, because it blocks note 'CREATE INDEX': create-index. statements on the tables, which could be important for running reporting queries.

Storing Data on Disk, in Memory, or Both

The 'innodb_memcache.cache_policies' table specifies whether to store data written through the 'memcached' interface to disk ('innodb_only', the default); in memory only, as with traditional 'memcached' ('cache_only'); or both ('caching').

With the 'caching' setting, if 'memcached' cannot find a key in memory, it searches for the value in an 'InnoDB' table. Values returned from 'get' calls under the 'caching' setting could be out-of-date if the values were updated on disk in the 'InnoDB' table but are not yet expired from the memory cache.

The caching policy can be set independently for 'get', 'set' (including 'incr' and 'decr'), 'delete', and 'flush' operations.

For example, you might allow 'get' and 'set' operations to query or update a table and the 'memcached' memory cache at the same time (using the 'caching' setting), while making 'delete', 'flush', or both operate only on the in-memory copy (using the 'cache_only' setting). That way, deleting or flushing an item only expires the item from the cache, and the latest value is returned from the 'InnoDB' table the next time the item is requested.

 mysql> SELECT * FROM innodb_memcache.cache_policies;
 +--------------+-------------+-------------+---------------+--------------+
 | policy_name  | get_policy  | set_policy  | delete_policy | flush_policy |
 +--------------+-------------+-------------+---------------+--------------+
 | cache_policy | innodb_only | innodb_only | innodb_only   | innodb_only  |
 +--------------+-------------+-------------+---------------+--------------+

 mysql> UPDATE innodb_memcache.cache_policies SET set_policy = 'caching'
        WHERE policy_name = 'cache_policy';

'innodb_memcache.cache_policies' values are only read at startup. After changing values in this table, uninstall and reinstall the 'daemon_memcached' plugin to ensure that changes take effect.

 mysql> UNINSTALL PLUGIN daemon_memcached;

 mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

 File: manual.info.tmp, Node: innodb-memcached-dml, Next: innodb-memcached-ddl, Prev: innodb-memcached-txn, Up: innodb-memcached-developing

14.21.5.5 Adapting DML Statements to memcached Operations .........................................................

Benchmarks suggest that the 'daemon_memcached' plugin speeds up DML operations (inserts, updates, and deletes) more than it speeds up queries. Therefore, consider focussing initial development efforts on write-intensive applications that are I/O-bound, and look for opportunities to use MySQL with the 'daemon_memcached' plugin for new write-intensive applications.

Single-row DML statements are the easiest types of statements to turn into 'memcached' operations. 'INSERT' becomes 'add', 'UPDATE' becomes 'set', 'incr' or 'decr', and 'DELETE' becomes 'delete'. These operations are guaranteed to only affect one row when issued through the 'memcached' interface, because the KEY is unique within the table.

In the following SQL examples, 't1' refers to the table used for 'memcached' operations, based on the configuration in the 'innodb_memcache.containers' table. 'key' refers to the column listed under 'key_columns', and 'val' refers to the column listed under 'value_columns'.

 INSERT INTO t1 (key,val) VALUES (SOME_KEY,SOME_VALUE);
 SELECT val FROM t1 WHERE key = SOME_KEY;
 UPDATE t1 SET val = NEW_VALUE WHERE key = SOME_KEY;
 UPDATE t1 SET val = val + x WHERE key = SOME_KEY;
 DELETE FROM t1 WHERE key = SOME_KEY;

The following note 'TRUNCATE TABLE': truncate-table. and note 'DELETE': delete. statements, which remove all rows from the table, correspond to the 'flush_all' operation, where 't1' is configured as the table for 'memcached' operations, as in the previous example.

 TRUNCATE TABLE t1;
 DELETE FROM t1;

 File: manual.info.tmp, Node: innodb-memcached-ddl, Prev: innodb-memcached-dml, Up: innodb-memcached-developing

14.21.5.6 Performing DML and DDL Statements on the Underlying InnoDB Table ..........................................................................

You can access the underlying 'InnoDB' table (which is 'test.demo_test' by default) through standard SQL interfaces. However, there are some restrictions:

 File: manual.info.tmp, Node: innodb-memcached-replication, Next: innodb-memcached-internals, Prev: innodb-memcached-developing, Up: innodb-memcached

14.21.6 The InnoDB memcached Plugin and Replication

Because the 'daemon_memcached' plugin supports the MySQL binary log, updates made on a source server through the 'memcached' interface can be replicated for backup, balancing intensive read workloads, and high availability. All 'memcached' commands are supported with binary logging.

You do not need to set up the 'daemon_memcached' plugin on replica servers. The primary advantage of this configuration is increased write throughput on the source. The speed of the replication mechanism is not affected.

The following sections show how to use the binary log capability when using the 'daemon_memcached' plugin with MySQL replication. It is assumed that you have completed the setup described in *note innodb-memcached-setup::.

Enabling the InnoDB memcached Binary Log

  1. To use the 'daemon_memcached' plugin with the MySQL binary log, enable the 'innodb_api_enable_binlog' configuration option on the source server. This option can only be set at server startup. You must also enable the MySQL binary log on the source server using the '--log-bin' option. You can add these options to the MySQL configuration file, or on the *note 'mysqld': mysqld. command line.

      mysqld ... --log-bin --innodb_api_enable_binlog=1
  2. Configure the source and replica server, as described in *note replication-howto::.

  3. Use *note 'mysqldump': mysqldump. to create a source data snapshot, and sync the snapshot to the replica server.

      source $> mysqldump --all-databases --lock-all-tables > dbdump.db
      replica $> mysql < dbdump.db
  4. On the source server, issue *note 'SHOW MASTER STATUS': show-master-status. to obtain the source binary log coordinates.

      mysql> SHOW MASTER STATUS;
  5. On the replica server, use a *note 'CHANGE MASTER TO': change-master-to. statement to set up a replica server using the source binary log coordinates.

      mysql> CHANGE MASTER TO
             MASTER_HOST='localhost',
             MASTER_USER='root',
             MASTER_PASSWORD='',
             MASTER_PORT = 13000,
             MASTER_LOG_FILE='0.000001,
             MASTER_LOG_POS=114;
  6. Start the replica.

      mysql> START SLAVE;

    If the error log prints output similar to the following, the replica is ready for replication.

      2013-09-24T13:04:38.639684Z 49 [Note] Slave I/O thread: connected to
      master 'root@localhost:13000', replication started in log '0.000001'
      at position 114

Testing the InnoDB memcached Replication Configuration

This example demonstrates how to test the 'InnoDB' 'memcached' replication configuration using the 'memcached' and telnet to insert, update, and delete data. A MySQL client is used to verify results on the source and replica servers.

The example uses the 'demo_test' table, which was created by the 'innodb_memcached_config.sql' configuration script during the initial setup of the 'daemon_memcached' plugin. The 'demo_test' table contains a single example record.

  1. Use the 'set' command to insert a record with a key of 'test1', a flag value of '10', an expiration value of '0', a cas value of 1, and a value of 't1'.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'.
      set test1 10 0 1
      t1
      STORED
  2. On the source server, check that the record was inserted into the 'demo_test' table. Assuming the 'demo_test' table was not previously modified, there should be two records. The example record with a key of 'AA', and the record you just inserted, with a key of 'test1'. The 'c1' column maps to the key, the 'c2' column to the value, the 'c3' column to the flag value, the 'c4' column to the cas value, and the 'c5' column to the expiration time. The expiration time was set to 0, since it is unused.

      mysql> SELECT * FROM test.demo_test;
      +-------+--------------+------+------+------+
      | c1    | c2           | c3   | c4   | c5   |
      +-------+--------------+------+------+------+
      | AA    | HELLO, HELLO |    8 |    0 |    0 |
      | test1 | t1           |   10 |    1 |    0 |
      +-------+--------------+------+------+------+
  3. Check to verify that the same record was replicated to the replica server.

      mysql> SELECT * FROM test.demo_test;
      +-------+--------------+------+------+------+
      | c1    | c2           | c3   | c4   | c5   |
      +-------+--------------+------+------+------+
      | AA    | HELLO, HELLO |    8 |    0 |    0 |
      | test1 | t1           |   10 |    1 |    0 |
      +-------+--------------+------+------+------+
  4. Use the 'set' command to update the key to a value of 'new'.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'.
      set test1 10 0 2
      new
      STORED

    The update is replicated to the replica server (notice that the 'cas' value is also updated).

      mysql> SELECT * FROM test.demo_test;
      +-------+--------------+------+------+------+
      | c1    | c2           | c3   | c4   | c5   |
      +-------+--------------+------+------+------+
      | AA    | HELLO, HELLO |    8 |    0 |    0 |
      | test1 | new          |   10 |    2 |    0 |
      +-------+--------------+------+------+------+
  5. Delete the 'test1' record using a 'delete' command.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'.
      delete test1
      DELETED

    When the 'delete' operation is replicated to the replica, the 'test1' record on the replica is also deleted.

      mysql> SELECT * FROM test.demo_test;
      +----+--------------+------+------+------+
      | c1 | c2           | c3   | c4   | c5   |
      +----+--------------+------+------+------+
      | AA | HELLO, HELLO |    8 |    0 |    0 |
      +----+--------------+------+------+------+
  6. Remove all rows from the table using the 'flush_all' command.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'.
      flush_all
      OK
    
      mysql> SELECT * FROM test.demo_test;
      Empty set (0.00 sec)
  7. Telnet to the source server and enter two new records.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'
      set test2 10 0 4
      again
      STORED
      set test3 10 0 5
      again1
      STORED
  8. Confirm that the two records were replicated to the replica server.

      mysql> SELECT * FROM test.demo_test;
      +-------+--------------+------+------+------+
      | c1    | c2           | c3   | c4   | c5   |
      +-------+--------------+------+------+------+
      | test2 | again        |   10 |    4 |    0 |
      | test3 | again1       |   10 |    5 |    0 |
      +-------+--------------+------+------+------+
  9. Remove all rows from the table using the 'flush_all' command.

      telnet 127.0.0.1 11211
      Trying 127.0.0.1...
      Connected to 127.0.0.1.
      Escape character is '^]'.
      flush_all
      OK
  10. Check to ensure that the 'flush_all' operation was replicated on the replica server.

      mysql> SELECT * FROM test.demo_test;
      Empty set (0.00 sec)

InnoDB memcached Binary Log Notes

Binary Log Format:

Transactions:

 File: manual.info.tmp, Node: innodb-memcached-internals, Next: innodb-memcached-troubleshoot, Prev: innodb-memcached-replication, Up: innodb-memcached

14.21.7 InnoDB memcached Plugin Internals

InnoDB API for the InnoDB memcached Plugin

The 'InnoDB' 'memcached' engine accesses 'InnoDB' through 'InnoDB' APIs, most of which are directly adopted from embedded 'InnoDB'. 'InnoDB' API functions are passed to the 'InnoDB' 'memcached' engine as callback functions. 'InnoDB' API functions access the 'InnoDB' tables directly, and are mostly DML operations with the exception of *note 'TRUNCATE TABLE': truncate-table.

'memcached' commands are implemented through the 'InnoDB' 'memcached' API. The following table outlines how 'memcached' commands are mapped to DML or DDL operations.

memcached Commands and Associated DML or DDL Operations

memcached DML or DDL Operations Command

'get' a read/fetch command

'set' a search followed by an 'INSERT' or 'UPDATE' (depending on whether or not a key exists)

'add' a search followed by an 'INSERT' or 'UPDATE'

'replace' a search followed by an 'UPDATE'

'append' a search followed by an 'UPDATE' (appends data to the result before 'UPDATE')

'prepend' a search followed by an 'UPDATE' (prepends data to the result before 'UPDATE')

'incr' a search followed by an 'UPDATE'

'decr' a search followed by an 'UPDATE'

'delete' a search followed by a 'DELETE'

'flush_all' 'TRUNCATE TABLE' (DDL)

InnoDB memcached Plugin Configuration Tables

This section describes configuration tables used by the 'daemon_memcached' plugin. The 'cache_policies' table, 'config_options' table, and 'containers' table are created by the 'innodb_memcached_config.sql' configuration script in the 'innodb_memcache' database.

 mysql> USE innodb_memcache;
 Database changed
 mysql> SHOW TABLES;
 +---------------------------+
 | Tables_in_innodb_memcache |
 +---------------------------+
 | cache_policies            |
 | config_options            |
 | containers                |
 +---------------------------+

cache_policies Table

The 'cache_policies' table defines a cache policy for the 'InnoDB' 'memcached' installation. You can specify individual policies for 'get', 'set', 'delete', and 'flush' operations, within a single cache policy. The default setting for all operations is 'innodb_only'.

cache_policies Columns

Column Description

'policy_name' Name of the cache policy. The default cache policy name is 'cache_policy'.

'get_policy' The cache policy for get operations. Valid values are 'innodb_only', 'cache_only', 'caching', or 'disabled'. The default setting is 'innodb_only'.

'set_policy' The cache policy for set operations. Valid values are 'innodb_only', 'cache_only', 'caching', or 'disabled'. The default setting is 'innodb_only'.

'delete_policy' The cache policy for delete operations. Valid values are 'innodb_only', 'cache_only', 'caching', or 'disabled'. The default setting is 'innodb_only'.

'flush_policy' The cache policy for flush operations. Valid values are 'innodb_only', 'cache_only', 'caching', or 'disabled'. The default setting is 'innodb_only'.

config_options Table

The 'config_options' table stores 'memcached'-related settings that can be changed at runtime using SQL. Supported configuration options are 'separator' and 'table_map_delimiter'.

config_options Columns

Column Description

'Name' Name of the 'memcached'-related configuration option. The following configuration options are supported by the 'config_options' table:

              * 'separator': Used to separate values of a long
                string into separate values when there are multiple
                'value_columns' defined.  By default, the
                'separator' is a '|' character.  For example, if
                you define 'col1, col2' as value columns, and you
                define '|' as the separator, you can issue the
                following 'memcached' command to insert values into
                'col1' and 'col2', respectively:
           
                     set keyx 10 0 19
                     valuecolx|valuecoly
           
                'valuecol1x' is stored in 'col1' and 'valuecoly' is
                stored in 'col2'.
           
              * 'table_map_delimiter': The character separating the
                schema name and the table name when you use the
                '@@' notation in a key name to access a key in a
                specific table.  For example, '@@t1.some_key' and
                '@@t2.some_key' have the same key value, but are
                stored in different tables.
           

'Value' The value assigned to the 'memcached'-related configuration option.

containers Table

The 'containers' table is the most important of the three configuration tables. Each 'InnoDB' table that is used to store 'memcached' values must have an entry in the 'containers' table. The entry provides a mapping between 'InnoDB' table columns and container table columns, which is required for 'memcached' to work with 'InnoDB' tables.

The 'containers' table contains a default entry for the 'test.demo_test' table, which is created by the 'innodb_memcached_config.sql' configuration script. To use the 'daemon_memcached' plugin with your own 'InnoDB' table, you must create an entry in the 'containers' table.

containers Columns

Column Description

'name' The name given to the container. If an 'InnoDB' table is not requested by name using '@@' notation, the 'daemon_memcached' plugin uses the 'InnoDB' table with a 'containers.name' value of 'default'. If there is no such entry, the first entry in the 'containers' table, ordered alphabetically by 'name' (ascending), determines the default 'InnoDB' table.

'db_schema' The name of the database where the 'InnoDB' table resides. This is a required value.

'db_table' The name of the 'InnoDB' table that stores 'memcached' values. This is a required value.

'key_columns' The column in the 'InnoDB' table that contains lookup key values for 'memcached' operations. This is a required value.

'value_columns' The 'InnoDB' table columns (one or more) that store 'memcached' data. Multiple columns can be specified using the separator character specified in the 'innodb_memcached.config_options' table. By default, the separator is a pipe character ('|'). To specify multiple columns, separate them with the defined separator character. For example: 'col1|col2|col3'. This is a required value.

'flags' The 'InnoDB' table columns that are used as flags (a user-defined numeric value that is stored and retrieved along with the main value) for 'memcached'. A flag value can be used as a column specifier for some operations (such as 'incr', 'prepend') if a 'memcached' value is mapped to multiple columns, so that an operation is performed on a specified column. For example, if you have mapped a 'value_columns' to three 'InnoDB' table columns, and only want the increment operation performed on one columns, use the 'flags' column to specify the column. If you do not use the 'flags' column, set a value of '0' to indicate that it is unused.

'cas_column' The 'InnoDB' table column that stores compare-and-swap (cas) values. The 'cas_column' value is related to the way 'memcached' hashes requests to different servers and caches data in memory. Because the 'InnoDB' 'memcached' plugin is tightly integrated with a single 'memcached' daemon, and the in-memory caching mechanism is handled by MySQL and the InnoDB buffer pool, this column is rarely needed. If you do not use this column, set a value of '0' to indicate that it is unused.

'expire_time_column' The 'InnoDB' table column that stores expiration values. The 'expire_time_column' value is related to the way 'memcached' hashes requests to different servers and caches data in memory. Because the 'InnoDB' 'memcached' plugin is tightly integrated with a single 'memcached' daemon, and the in-memory caching mechanism is handled by MySQL and the InnoDB buffer pool, this column is rarely needed. If you do not use this column, set a value of '0' to indicate that the column is unused. The maximum expire time is defined as 'INT_MAX32' or 2147483647 seconds (approximately 68 years).

'unique_idx_name_on_key'The name of the index on the key column. It must be a unique index. It can be the primary key or a secondary index. Preferably, use the primary key of the 'InnoDB' table. Using the primary key avoids a lookup that is performed when using a secondary index. You cannot make a covering index for 'memcached' lookups; 'InnoDB' returns an error if you try to define a composite secondary index over both the key and value columns.

containers Table Column Constraints

A pre-check is performed at plugin load time to enforce column constraints. If mismatches are found, the plugin is not loaded.

Multiple Value Column Mapping

The demo_test Example Table

The 'innodb_memcached_config.sql' configuration script creates a 'demo_test' table in the 'test' database, which can be used to verify 'InnoDB' 'memcached' plugin installation immediately after setup.

The 'innodb_memcached_config.sql' configuration script also creates an entry for the 'demo_test' table in the 'innodb_memcache.containers' table.

 mysql> SELECT * FROM innodb_memcache.containers\G
 *************************** 1. row ***************************
                   name: aaa
              db_schema: test
               db_table: demo_test
            key_columns: c1
          value_columns: c2
                  flags: c3
             cas_column: c4
     expire_time_column: c5
 unique_idx_name_on_key: PRIMARY

 mysql> SELECT * FROM test.demo_test;
 +----+------------------+------+------+------+
 | c1 | c2               | c3   | c4   | c5   |
 +----+------------------+------+------+------+
 | AA | HELLO, HELLO     |    8 |    0 |    0 |
 +----+------------------+------+------+------+

 File: manual.info.tmp, Node: innodb-memcached-troubleshoot, Prev: innodb-memcached-internals, Up: innodb-memcached

14.21.8 Troubleshooting the InnoDB memcached Plugin

This section describes issues that you may encounter when using the 'InnoDB' 'memcached' plugin.

 File: manual.info.tmp, Node: innodb-troubleshooting, Next: innodb-limits, Prev: innodb-memcached, Up: innodb-storage-engine