Sharing Sessions Across Multiple Servers With Memcache

These last few days have been full of quickly implementing things I’ve only read about, but hadn’t done for myself.

One situation was looking at splitting web traffic across multiple servers. In our case, we had only 2% of our website that would spike and increase our load by %1000 percent (I’m not joking) for a short period of time. So instead of doing traditional load balancing, we opted for routing specific functions to a custom subdomain that would run on another server. That way if the thousands of crazy video game players (you know who you are), slam the servers trying to get a cool skin for their online avatar, it would only take down that one section.

Well, we were using PHP Sessions, and as you might know, they are file based. The problem is that when it’s file based, server A by default won’t have access to server B’s session files. This makes having a user stay logged in between servers a real pain.

After researching all sorts of possibilities, we decided to take the shortest route. You can write your own PHP Session Handlers, but dealing with race conditions and other pitfalls are left to the developer.

So, we decided to use the built in memcache session handler that has all the extra tricky stuff built in. All it takes is installing the php memcache module, and a few php.ini changes outlined here. I’ve copied the text here to keep a record of it.

The first thing is to install the memcached server on your Debian server :

apt-get install memcached

Then, since the memcache PECL extension now provides its own session handler, it’s easy to plug PHP and memcached servers. Just install the appropriate extension (from Dotdeb) :

apt-get install php5-memcache

and change some of your PHP settings :

session.save_handler = files
; session.save_path = “N;/path”

to :

session.save_handler = memcache
; change server:port to fit your needs…
session.save_path=”tcp://server:port?persistent=1&weight=1&timeout=1&retry_interval=15″

That’s all! After relaunching your Apache2 server, your PHP sessions will be stored on the memcached server.

Now, you’ll need to have memcached, the service, running somewhere that all your php web servers can access. In presentations I’ve given about memcached, I talk about how memcached as zero built in security (well, maybe 0.1% security, close enough to zero). So you need to secure it with iptables so that only the web servers can access your memcached service.

Tomorrow if I have time I might quickly document my experience of getting a Ubuntu 10.04 server running nginx + php. I was surprised at how easy it was, and even figuring out some more advanced configs were not bad.

8 thoughts on “Sharing Sessions Across Multiple Servers With Memcache

  1. Thanks for the write up this is really some great stuff here! Sharing Sessions Across Multiple Servers With Memcache | Justin Carmony’s Blog was a wonderful read.

    Like

  2. Any concerns about the non-persistent nature of memcached?

    Like

  3. There is some, but their durability is about as durable as tmp files. Also, having the memcached server on its own VM, it is probably the very last thing to go down if we have any issues. So pending any serious hardware issues, it met our needs and our budget for time spent on the project.

    Like

  4. It does not work in my case.

    SERVER X:
    ini_set(‘session.save_handler’, “memcache”);
    ini_set(‘session.save_path’, “tcp://memcache_server_ip:11211?persistent=1&weight=1&timeout=1&retry_interval=15”);
    session_start();
    $_SESSION[‘username’] = ‘foobar’;
    print_r($_SESSION); //Prints above defined session array

    SERVER Y:
    ini_set(‘session.save_handler’, “memcache”);
    ini_set(‘session.save_path’, “tcp://memcache_server_ip:11211?persistent=1&weight=1&timeout=1&retry_interval=15”);
    session_start();
    print_r($_SESSION); //Does not print session array defined on SERVER X

    Is there any problem?

    Like

  5. @codef0rmer

    Are Server X and Server Y using the same domain name? Are they different sub domains? If so you’ll need to set the session cookie to be across the entire main domain:

    Like

  6. I have installed memcache on server 192.168.0.1 to store sessions.

    In firefox, i accessed 192.168.0.2/index.php:
    ini_set(‘session.save_handler’, “memcache”);
    ini_set(‘session.save_path’, “tcp://192.168.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15″);
    session_start();
    $_SESSION[‘username’] = ‘foobar’;
    print_r($_SESSION); //Prints above defined session array

    Again in firefox in new tab, i accessed 192.168.0.3/index.php:
    ini_set(‘session.save_handler’, “memcache”);
    ini_set(‘session.save_path’, “tcp://192.168.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15″);
    session_start();
    print_r($_SESSION); //It should print above defined session array

    But it does not work in my case.

    Like

  7. @codef0rmer

    That is because Server 1’s “domain name” is 192.168.0.2, and Server 2’s domain name is 192.168.0.3. Your browser will not pass the same php session cookie to two separate domains for security reasons. Checkout http://www.jontodd.com/2006/08/10/php-session-cookie-multiple-domains/ for more information.

    So until you have a common “domain” for both servers 1 and 2, you won’t be able to get it to work.

    Like

  8. To overcome race conditions and have more deep control for stored session data I suggest to try SCache at http://scache.nanona.fi

    It encourages to stop using $_SESSION altogether and split data to small parts that are accessed separately.

    While it does not completely solve race conditions, it reduces races to influence just single variables instead of having rival threads overwriting whole $_SESSION data of each others.

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.