Caching PHP HTTP Sessions in Coherence

Coherence already provides HTTP Session caching support for ASP.NET and J2EE applications without any application changes. Coherence for .NET includes a custom SessionStateStoreProvider implementation that uses a Coherence cache to store session state. This makes Coherence for .NET the best solution for any large ASP.NET application running within a web farm. The HTTP session state of J2EE Web Applications is managed using Coherence*Web. Coherence*Web is an HTTP session management module dedicated to managing session state in clustered environments. Built on top of Oracle Coherence, it has a wide range of features and supports a wide range of J2EE containers. With WebLogic Suite Coherence*Web is built in, but for other containers a Coherence utility modifies the necessary settings in the Web Applications web.xml file to transfer management of the HTTP Session state from the container to Coherence. With PHP there is no “out-of-the-box” Coherence support for HTTP Session state management, until now. The rest of this article outlines how using a standard PHP extension Coherence can be used as a clustered, reliable HTTP session handler for PHP.

Like ASP.NET and J2EE application containers, PHP makes it quite easy to plug-in your own HTTP session handler and lots of different flavours exist already, from in-memory stores using tools like memcached to file and database persistent session mechanisms using products like MySQL.  Coherence is an ideal persistence store for HTTP sessions because it is:

  • Very fast, enabling dynamic web pages to be quickly displayed
  • Resilient and fault-tolerant, ensuring that process or server failures do not impact users – logging them off etc.
  • Scalable, to support and ever increasing number of online users/customers
  • Simple to integrate and manage, so the overhead of introducing Coherence does not burden either web development of operational staff

So can Coherence be used with PHP?. Well using the native Coherence C++ client to create a PHP extension that can then be wrapped using a PHP session_set_save_handler to setup some user defined session storage functions. A diagram to illustrate the relationship between the PHP runtime, Coherence C++ extension and the Coherence cache is shown below:

 

image

To include the PHP custom session handlers in your PHP page add the following to the top of your PHP page:

<?php
require 'coherence_session.php';
$s = new CoherencePHPSessionHandler();
.
.
?>

This basically enables a new session to be started using the custom session save handler. The custom session save handler looks like this:

<?php
class CoherencePHPSessionHandler
{
    private static $debug = False;

    /**
     * A reference to a Coherence named cache
     * @var resource
     */
    private $cache;

    /**
     * Session lifetime
     * @var resource
     */
    private $lifeTime;

    private static function Log($msg)
    {
      if(CoherencePHPSessionHandler::$debug)
      {
        echo "<br>DEBUG PHP: " . $msg . "\n";
      }
    }

    function __construct()
    {
        // get session-lifetime
        $this->lifeTime = get_cfg_var("session.gc_maxlifetime");

        CoherencePHPSessionHandler::Log("Lifetime: " . $this->lifeTime);
        $this->cache = new Cache("dist-php-sessions");

        if ($this->cache == null)
        {
            return false;
        }

        CoherencePHPSessionHandler::Log("Got cache handle");

        session_set_save_handler(array(&$this, 'open'),
                                array(&$this, 'close'),
                                array(&$this, 'read'),
                                array(&$this, 'write'),
                                array(&$this, 'destroy'),
                                array(&$this, 'gc'));
        register_shutdown_function('session_write_close');
        session_start();

        CoherencePHPSessionHandler::Log("Started session");
        return true;
    }

    /**
     * Open the session
     * @return bool
     */
    function open($savePath, $sessName)
    {
        // get session-lifetime
        $this->lifeTime = get_cfg_var("session.gc_maxlifetime");
        CoherencePHPSessionHandler::Log("Opening session");
        return true;
    }

    /**
     * Close the session
     * @return bool
     */
    public function close()
    {
        // ToDo: need to release Coherence resources
        return true;
    }

    /**
     * Read the session
     * @param int session id
     * @return string string of the session
     */
    public function read($id)
    {
        $result = $this->cache->get($id);

        if($result != null)
        {
          CoherencePHPSessionHandler::Log("Read session, id: " . $id . ", value: " . $result);
          return $result;
        }
        return '';
    }

    /**
     * Write the session
     * @param int session id
     * @param string data of the session
     */
    public function write($id, $data)
    {
        CoherencePHPSessionHandler::Log("Session value: " . serialize($data));

        $this->cache->put($id, $data, $this->lifeTime);
        CoherencePHPSessionHandler::Log("Written session, id: " . $id . ", value: " . $data);
        return true;
    }

    /**
     * Destoroy the session
     * @param int session id
     * @return bool
     */
    public function destroy($id)
    {
        $this->cache->remove($id);
        return true;
    }

    /**
     * Garbage Collector
     * @param int life time (sec.)
     * @return bool
     * @see session.gc_divisor      100
     * @see session.gc_maxlifetime 1440
     * @see session.gc_probability    1
     * @usage execution rate 1/100
     *        (session.gc_probability/session.gc_divisor)
     */
    public function gc($max)
    {
        return true;
    }
}
?>

As for the Coherence PHP extension there is too much to show here, though in total it does not amount to a lot of code. The C++ client class that wraps the Coherence client API is also very simple and the class functions are shown below:

#include "cache.h"

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include "php.h"
}

static char * copyString(const char *str)
{
    char *s;

    if(str != NULL && (s = (char *)emalloc(sizeof(char) * (strlen(str)  + 1))) == NULL)
    {
        return NULL;
    }
    else
    {
        if(strncpy(s, str, strlen(str) + 1) == NULL)
        {
            efree(s);
            return NULL;
        }
        return s;
    }
}

Cache::Cache(const char *name)
{
    // Get handle to a Named Cache
    String::View vsCacheName = String::create(name);
    hCache = CacheFactory::getCache(vsCacheName);
}

const char *Cache::getCacheName()
{
    String::View name = cast<String::View>(hCache->getCacheName());

    return copyString(name->getCString());
}

char* Cache::put(const char *key, const char *value, long ttl)
{
    if(key == NULL || value == NULL)
    {
        throw std::invalid_argument("Key or value for put() NULL");
    }
    String::View vKey = String::create(key);
    String::View vValue = String::create(value);
    String::View vOldValue = cast<String::View>(hCache->put(vKey, vValue, ttl));

    return (vOldValue == NULL ? NULL : copyString(vOldValue->getCString()));
}

char* Cache::remove(const char *key)
{
    String::View vKey = String::create(key);
    String::View vOldValue = cast<String::View>(hCache->remove(vKey));

    return (vOldValue == NULL ? NULL : copyString(vOldValue->getCString()));
}

char* Cache::get(const char *key)
{
    String::View vKey = String::create(key);
    String::View vOldValue = cast<String::View>(hCache->get(vKey));

    return (vOldValue == NULL ? NULL : copyString(vOldValue->getCString()));
}

int Cache::size()
{
    return (int)hCache->size();
}

The Coherence PHP extension can also be used for simply caching PHP values, as well as PHP session information. The above example was tested on Oracle Enterprise Linux 4, but can easily be compiled on Windows. You can download the whole example from here to try it out for yourself. Instructions are included which should hopefully be easy to follow. A couple of outstanding issues still remain with the Coherence PHP extension which I have not been able to resolve. Although simple PHP types as well as objects and arrays can be cached – both as keys and values – I could not get objects with private or protected variables to serialize. If anyone more experienced in the internals of PHP can help here it would be much appreciated, as I drew a blank.

Comments:

This is a really cool example, i liked it very much. Lets hope that module gets into pecl some day : ) Very good tutorial integration of PHP integration. Thanks art

Posted by Artur Ejsmont on March 16, 2010 at 02:10 AM GMT #

Hi Artur, Thanks for the feedback, I'm gad you found it useful. I noticed on your blog that you compare MySQL vs Memcached for session persistence with PHP and conclude its scalability + resilience vs speed. With Coherence as a session persistence layer you can have both, as its fast, resilient and can scale. The size of most session data is relatively small - usually <100k - so even with 10k concurrent sessions you are only talking about 1GB of data. There are a number of Coherence clusters holding 100 GB+ of data. If you have any feedback, comments or advice on how to improve the PHP plugin I'd be keen to hear it. Dave

Posted by David Felcey on March 16, 2010 at 02:32 AM GMT #

Hi Dave, possibly you could also write about how to do PHP clustering on Quercus inside Resin with Coherence. BR, Robert

Posted by Robert Varga on March 25, 2010 at 06:48 PM GMT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Views and ideas about Oracle Coherence and other software

Search

Categories
Archives
« September 2015
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today