EnterpriseDB

Previous PageTable Of ContentsNext Page

2.3.3 memcached

New to Postgres Plus Advanced Server 8.3 is the integration and distribution of memcached. This newly bundled functionality gives database administrators and developers the ability to utilize high-performance memory caching from within the database itself; providing additional options for meeting the diverse performance requirements of Web 2.0 applications.

2.3.3.1 What is memcached?

In short, memcached is a high-performance, distributed memory object caching system which is intended primarily for reducing database load in order to speedup dynamic web applications.

Initially, memcached was developed to enhance the speed of LiveJournal.com, a site which was already doing 20 million+ dynamic page views per day for 1 million users with a bunch of web servers and a bunch of database servers. After deployment, memcached dropped the database load to almost nothing, yielding faster page load times for users, better resource utilization, and faster access to the databases on a memcache miss.

2.3.3.2 How Does memcached Work?

Being a distributed memory cache, memcached works by utilizing two hashes; behaving simply as a giant hash table for looking up key/value pairs. When finding an object in memcached, the client first hashes the key against the entire array of servers. Once a server has been chosen, the client then issues its request to that server, and the server performs an internal hash key lookup for the actual item data. If the data is found, it is returned to the client.

2.3.3.3 How Does Postgres Plus Advanced Server and memcached Integrate With Each Other?

Because memcached is a generic and modular caching system, a project called pgmemcache was created to allow users to call memcached functions from within Postgres. EnterpriseDB has bundled pgmemcache in its distribution of Postgres Plus Advanced Server.

2.3.3.4 Limitations of memcached

Generally, the basic limitations you may encounter when using memcached are the key and item size limits. Currently, keys are restricted to 250 characters and stored data cannot exceed 1 megabyte in size.

2.3.3.5 Limitations of Postgres Plus Advanced Server and memcached

By default, there is no integration between Postgres Plus Advanced Server and memcached. It is up to the developer or database administrator to decide what objects to cache, and how to best integrate those objects into memcached.

2.3.3.6 Recommendations for Best Performance

When using memcached with Postgres Plus Advanced Server, the following tips generally yield the best performance:

Use 64-bit systems with a significant amount of RAM

If using 32-bit systems, only use < 4GB of RAM

If you’re using Linux, make sure to use /dev/epoll.

2.3.3.7 Postgres Plus and memcached Concepts

The following are the steps generally followed when using Postgres Plus Advanced Server with memcached:

1. Install memcached

2. Configure and start memcached

3. Install pgmemcache into a Postgres Plus Advanced Server database

4. Add objects to memcached using the pgmemcache API

5. Retrieve objects from memcached using the pgmemcache API

2.3.3.8 Installing memcached

By default, memcached is installed with Postgres Plus Advanced Server in /opt/PostgresPlus/8.3AS/memcached. You’ll just need to configure/start it and make sure pgmemcache is installed properly.

2.3.3.9 Configuring and Starting memcached

Unlike other systems, memcached does not require a configuration file. Instead, its configuration parameters are all passed-in on the command line.

enterprisedb@edb-jharris /opt/PostgresPlus/8.3AS/memcached $ ./memcached -help
memcached 1.2.2
-p <num>      TCP port number to listen on (default: 11211)
-U <num>      UDP port number to listen on (default: 0, off)
-s <file>     unix socket path to listen on (disables network support)
-l <ip_addr>  interface to listen on, default is INDRR_ANY
-d            run as a daemon
-r            maximize core file limit
-u <username> assume identity of <username> (only when run as root)
-m <num>      max memory to use for items in megabytes, default is 64 MB
-M            return error on memory exhausted (rather than removing items)
-c <num>      max simultaneous connections, default is 1024
-k            lock down all paged memory
-v            verbose (print errors/warnings while in event loop)
-vv           very verbose (also print client commands/reponses)
-h            print this help and exit
-i            print memcached and libevent license
-b            run a managed instanced (mnemonic: buckets)
-P <file>     save PID in <file>, only used with -d option
-f <factor>   chunk size growth factor, default 1.25
-n <bytes>    minimum space allocated for key+value+flags, default 48

So, to start memcached with a 128M cache, you would do the following:

$ export EDB_HOME=/opt/PostgresPlus/8.3AS
$ cd $EDB_HOME/memcached
$ ./memcached –d –m 128

2.3.3.10 Installing pgmemcache into Postgres Plus Advanced Server

In order to use memcached from within Postgres Plus Advanced Server, you must first install pgmemcache. While it is installed into the edb database by default, if you create a new database, or drop the edb database, you’ll need to install the pgmemcache functions using the example below. Note, the EDB_HOME environment variable should be set to the path you installed Postgres Plus Advanced Server into.

Installing pgmemcache with PSQL:

$ export EDB_HOME=/opt/PostgresPlus/8.3AS
$ edb-psql <connection info> -d dbname -f $EDB_HOME/dbserver/share/contrib/pgmemcache.sql

2.3.3.11 Exported memcached Functions Used in Postgres Plus Advanced Server

The following functions have been exported from the libmemcache library for use in Postgres Plus Advanced Server.

Table 2-1 memcached Functions

Function

Description

memcache_server_add

Adds a server to the list of available servers.

memcache_server_list

Returns a row describing each element of the server list.

memcache_server_remove

Disconnects from the specified server.

memcache_server_find

Returns a tuple containing the hostname and port of the server assigned to the specified hash value.

memcache_add

Adds a key to the cache cluster, if the key does not already exist.

memcache_decr

If key exists and is an integer, atomically decrements by the value specified (default decrement is one).

memcache_delete

Deletes a given key.

memcache_flush_all

Flushes all data on all servers in the memcache cluster.

memcache_flush

Flushes all keys from the backend that the given key maps to.

memcache_get

Fetches a key out of the cache.

memcache_hash

Returns the hash value for a given key.

memcache_incr

If key exists and is an integer, atomically increment by the value specified (the default increment is one).

memcache_replace

Replaces an existing key's value if the key already exists.

memcache_set

Regardless of whether the specified key already exists, set its current value to “value”, replacing the previous value if any.

memcache_stats

Returns a TEXT string with all of the stats from all servers in the server list.

2.3.3.12 Add a Server to the List of Available Servers (memcache_server_add)

This function adds a server to the list of available servers. If the port is not specified, the libmemcache default port (11211) is used. This function should only be done in one central place in the code (normally wrapped in an IF statement).

API Definition

memcache_server_add(/* hostname */ TEXT, /* port */ TEXT)
memcache_server_add(/* hostname */ TEXT)

Example

CREATE OR REPLACE FUNCTION mc_init()
  RETURNS VOID
AS $$
BEGIN
    PERFORM memcache_server_add('mc1.example.com', '11211');
    PERFORM memcache_server_add('mc2.example.com', '11211');
    RETURN;
END;
$$ LANGUAGE 'plpgsql';

2.3.3.13 Return Data Describing Each Element of the Server List (memcache_server_list)

This function returns a row describing each element of the server list such as the hostname, port, and current status.

API Definition

memcache_server_list() => SETOF (text, int4, text)

2.3.3.14 Disconnects from a Specific Server (memcache_server_remove)

This function disconnects from the server specified.

API Definition

memcache_server_remove(/* hostname */ TEXT, /* port */ TEXT)
memcache_server_remove(/* hostname */ TEXT)

2.3.3.15 Return a Tuple Containing the Hostname and Port of the Server Assigned to the Specified Hash Value (memcache_server_find)

The following function returns a tuple containing the hostname and port of the server assigned to the specified hash value.

API Definition

memcache_server_find(/* hash */ INT4) => (TEXT, INT4)
memcache_server_find(/* key */ TEXT) => (TEXT, INT4)

2.3.3.16 Add a Key to the Cache Cluster (memcache_add)

The following function adds a key to the cache.

API Definition

memcache_add(/* key */ TEXT, /* value */ TEXT, /* expire */
  TIMESTAMPTZ)
memcache_add(/* key */ TEXT, /* value */ TEXT, /* expire */
  INTERVAL)
memcache_add(/* key */ TEXT, /* value */ TEXT)

2.3.3.17 Atomically Decrement an Integer-Based Key Value (memcache_decr)

If the given key exists and is an integer, this function atomically decrements by the value specified (default decrement is one), and returns the integer value after decrement.

API Definition

newval = memcache_decr(/* key */ TEXT, /* decrement */ INT4)
newval = memcache_decr(/* key */ TEXT)

2.3.3.18 Delete a Given Key/Value Pair (memcache_delete)

This function deletes a given key. If a hold timer is specified, a key with the same name cannot be added until the hold timer expires.

API Definition

memcache_delete(/* key */ TEXT, /* hold timer */ INTERVAL)
memcache_delete(/* key */ TEXT)

Example

-- The above is not transaction safe, however.  A better approach is
-- to have pgmemcache invalidate the cached data, but not replace it.
CREATE OR REPLACE FUNCTION auth_passwd_trg_upd() RETURNS TRIGGER  AS $
BEGIN
    IF OLD.passwd != NEW.passwd THEN
        PERFORM mc_init();
        PERFORM memcache_delete('user_id_' || NEW.user_id || '_password');
    END IF;
    RETURN NEW;
END;$ LANGUAGE 'plpgsql';

-- Here's an example delete trigger
CREATE OR REPLACE FUNCTION auth_passwd_trg_del() RETURNS TRIGGER AS $
BEGIN
    PERFORM mc_init();
    PERFORM memcache_delete('user_id_' || NEW.user_id || '_password');
    RETURN OLD;
END;$ LANGUAGE 'plpgsql';

2.3.3.19 Flush All Data on All Servers in the memcache Cluster (memcache_flush_all)

The following function flushes all data on every server in a memcached cluster.

API Definition

memcache_flush_all()

2.3.3.20 Flushes All Keys from the Backend that a Given Key Maps to (memcache_flush)

The following function flushes a particular key from a memcached cluster.

API Definition

memcache_flush(/* key */ TEXT)

2.3.3.21 Fetches a Key from Cache (memcache_get)

The following function fetches a key out of the cache. Returns null if the key does not exist; otherwise, it returns the value of the key as TEXT. Zero-length values are allowed.

API Definition

value = memcache_get(/* key */ TEXT)

2.3.3.22 Return the Hash Value for a Given Key (memcache_hash)

The following function returns the hash value for a given key.

API Definition

hash = memcache_hash(/* key */ TEXT)

2.3.3.23 Atomically Increment an Integer-Based Key Value (memcache_incr)

If the given key exists and is an integer, this function atomically increments by the value specified (default increment is one), and returns the integer value after decrement.

API Definition

newval = memcache_incr(/* key */ TEXT, /* increment */ INT4)
newval = memcache_incr(/* key */ TEXT)

2.3.3.24 Replaces an Existing Key’s Value (memcache_replace)

The following function replaces an existing key’s value if the key already exists.

API Definition

memcache_replace(/* key */ TEXT, /* value */ TEXT,
  /* expire */ TIMESTAMPTZ)
memcache_replace(/* key */ TEXT, /* value */ TEXT,
  /* expire */ INTERVAL)
memcache_replace(/* key */ TEXT, /* value */ TEXT)

2.3.3.25 Set a Key’s Current Value (memcache_set)

The following function sets the current value of a key to “value”, replacing the previous value if any, regardless of whether the specified key already exists.

API Definition

memcache_set(/* key */ TEXT, /* value */ TEXT, /* expire */
  TIMESTAMPTZ)
memcache_set(/* key */ TEXT, /* value */ TEXT, /* expire */
  INTERVAL)
memcache_set(/* key */ TEXT, /* value */ TEXT)

2.3.3.26 Returns a TEXT String with All of the Stats from All Servers in the Server List (memcache_stats)

The following function returns a TEXT string with all of the stats from all servers in the server list. Statistics are derived from a summation of the statistics of all the servers in the server list.

API Definition

stats = memcache_stats()
stat = memcache_stats(/* statistic key */ TEXT)

2.3.3.27 Full Example

The following is a full example. Components of this have been used in previous examples.

-- Altered to put data into memcached
CREATE OR REPLACE PROCEDURE select_emp (
    p_empno         IN  NUMBER
)
IS
    v_ename         emp.ename%TYPE;
    v_hiredate      emp.hiredate%TYPE;
    v_sal           emp.sal%TYPE;
    v_comm          emp.comm%TYPE;
    v_dname         dept.dname%TYPE;
    v_disp_date     VARCHAR2(10);
BEGIN
    SELECT ename, hiredate, sal, NVL(comm, 0), dname
        INTO v_ename, v_hiredate, v_sal, v_comm, v_dname
        FROM emp e, dept d
        WHERE empno = p_empno
          AND e.deptno = d.deptno;
    v_disp_date := TO_CHAR(v_hiredate, 'MM/DD/YYYY');

    -- Add cache entry
    PERFORM memcache_set('emp_ename_' || p_empno, v_ename);
    PERFORM memcache_set('emp_disp_date_' || p_empno, v_disp_date);
    PERFORM memcache_set('emp_sal_' || p_empno, v_sal);
    PERFORM memcache_set('emp_comm_' || p_empno, v_comm);
    PERFORM memcache_set('emp_dname_' || p_empno, v_dname);

    -- Perform output
    DBMS_OUTPUT.PUT_LINE('Number    : ' || p_empno);
    DBMS_OUTPUT.PUT_LINE('Name      : ' || v_ename);
    DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_disp_date);
    DBMS_OUTPUT.PUT_LINE('Salary    : ' || v_sal);
    DBMS_OUTPUT.PUT_LINE('Commission: ' || v_comm);
    DBMS_OUTPUT.PUT_LINE('Department: ' || v_dname);
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno || ' not found');
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
        DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
        DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;
/

-- Retrieve data from memcached (if exists), otherwise revert to select_emp
CREATE OR REPLACE PROCEDURE select_emp_cached (
    p_empno         IN  NUMBER
)
IS
    v_ename         emp.ename%TYPE;
    v_hiredate      emp.hiredate%TYPE;
    v_sal           emp.sal%TYPE;
    v_comm          emp.comm%TYPE;
    v_dname         dept.dname%TYPE;
    v_disp_date     VARCHAR2(10);
BEGIN
    SELECT memcache_get('emp_ename_' || p_empno),
           memcache_get('emp_disp_date_' || p_empno),
           memcache_get('emp_sal_' || p_empno),
           memcache_get('emp_comm_' || p_empno),
           memcache_get('emp_dname_' || p_empno)
           INTO v_ename, v_disp_date, v_sal, v_comm, v_dname
      FROM dual;
    IF v_ename IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('From select_emp!');
        select_emp(p_empno);
    ELSE
        -- Perform output
        DBMS_OUTPUT.PUT_LINE('From select_emp_cached!');
        DBMS_OUTPUT.PUT_LINE('Number    : ' || p_empno);
        DBMS_OUTPUT.PUT_LINE('Name      : ' || v_ename);
        DBMS_OUTPUT.PUT_LINE('Hire Date : ' || v_disp_date);
        DBMS_OUTPUT.PUT_LINE('Salary    : ' || v_sal);
        DBMS_OUTPUT.PUT_LINE('Commission: ' || v_comm);
        DBMS_OUTPUT.PUT_LINE('Department: ' || v_dname);
    END IF;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        DBMS_OUTPUT.PUT_LINE('Employee ' || p_empno || ' not found');
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('The following is SQLERRM:');
        DBMS_OUTPUT.PUT_LINE(SQLERRM);
        DBMS_OUTPUT.PUT_LINE('The following is SQLCODE:');
        DBMS_OUTPUT.PUT_LINE(SQLCODE);
END;
/

-- Populate memcached (generally use a trigger)
SELECT memcache_server_add('localhost');

-- Demo using standard query (populating cache)
exec select_emp (7654);

-- Demo using cached data query
exec select_emp_cached (7654);

-- Demo populating cache from select_emp_cached
exec select_emp_cached (7900);
exec select_emp_cached (7900);

2.3.3.28 How Else Can I Use Postgres Plus Advanced Server and memcached?

In addition to the examples already given, it should be mentioned that because memcached is a separate server, many other clients can populate and change the data it stores. As such, you could have external clients populate user information, or other objects which are easily returned from within the database.

Previous PageTable Of ContentsNext Page

Powered by Transit