Using memcached to run your sessions

by rynop
This tutorial is intended for cakers who intend to make a scalable web app. Being familiar with php.ini, memcached and sessions is recommended.
It's been my experience that disk and memory has always been my bottleneck when scaling a disk backed db app.

Its easy to fix the memory bottlenecks by adding more memory or making code improvements that consume less memory per-request. Its not so easy to cut down on disk I/O - and furthermore in today's shift towards virtual machines (linode, EC2 etc) - even if you don't realize it, disk i/o is constrained MUCH more then ever before. Throw a disk backed DB in there and u get in trouble fast.

So anything that you can do to cut down on I/O is huge (IMO of course).

Use php optcode cache

I use http://eaccelerator.net/. there are tons out there, but I use this one primarily cuz its maintained in the ubuntu server package repo's. If you use an optcode cache that is not maintained in your package management repo - every time there is an update to php (or other dependent libs) you have to recompile. May be better ones out there, but not worth the hassle for the little (if any) improvement.

Use memcached wherever possible

If you don't use cake's caching functions - start. When its time to scale, fronting every database query you can with memcached is very important. Go turn on caching, and use the memcached one http://book.cakephp.org/view/772/Cache-config. It is a shame that view caching cant be backed by memcached (it can in other web frameworks) - but its still a no-brainer. There is a reason that facebook is the #1 consumer of memcached. Good read if your interested: http://www.facebook.com/note.php?note_id=39391378919
anyways, I have been unable to find any good docs on there on how to use cakes Cache class in a real life app. Things can get complex when you need to maintain a mapping of what cache entries need to be cleared when stuff in related (or unrelated) models are changed. If anyone knows of a nice tutorial on this topic please post in the comments....

Use the memcached session support built into php5

Ok so you've put up with my babbling - now some real code. Lets dive right in, then I'll explain. This is your php.ini:

~$ cat /etc/php5/apache2/php.ini | grep -i session
[Session]
;session.save_handler = files
session.save_handler = memcache
session.save_path = "tcp://127.0.0.1:11211"

...

I've omitted lots of the php.ini, but the relevant lines are all here. Super simple, all we are doing here is telling the default php session handling to be backed by memcached. Comment out the files backed, and type up the next 2 lines. Slick/easy aint it?

Before doing this there are a few steps you have to setup first:
  • in /config/core.php: set Configure::write('Session.save', 'php'); This tells cake to let PHP handle sessions.
  • Setup a unique name for Session.cookie in core.php
  • Change the Security.salt to something unique
  • Install memcached. Use your package manager to install it (apt-get or whatever your distro's is)
  • Start memcached (sudo /etc/init.d/memcached start). Note: some distros make you edit some memcached config file in /etc to tell it to allow it to start - not sure why they do it, but they do...
  • Go make the php.ini changes above, then restart apache.


Things to watch out for

You never get something for nothing, so what are the drawbacks with memcache backed sessions? The two main ones as I see it are:
  1. Data persistence. Memcache is an in memory data store; so if your server crashes, the memcache daemon crashes or your memcache pool gets cleared all your sessions (and session data) is gone. If you are writing a webapp that can't afford to have these scenarios happen, stick with DB backed sessions. However, the risk of these happening is low IMO. Memcache is a proven product, so chances of it crashing are similar to another one of your services (like mysqld) crashing. If anyone knows of memcache redundancy techniques, please post in the comments.
  2. Memcache pools filling up. Memcached is a distributed object cache - and its fixed in size (configurable, but ultimately bound by the memory pool allocated to your cluster of memcached servers). If memcached pool gets filled up, new session data may not fit - or current data may be bumped out (depending on your config). This is one main reason why I leverage php's memcache session settings. This allows me to have separate pools for my session and object data.

Thats it. You are really almost getting something for nothing here. Everything is on memory, not hitting your db and not sucking up precious I/O. Plus, if you end up scaling, and have a cluster of machines serving your web app - you can share this session info across workhorse nodes (memcached lets you pool up memory over boxes that r networked together). This comes in handy in sharing other cached data across nodes - again, too bad cake doesn't store view cache to memcache - otherwise you could really take advantage of it here (think of trying to run commands on every node to delete view cache files when something changes - not fun).

I use all these techniques in my startup (http://www.leaguelogix.com) so they are proven to work in a production environment.

Hopefully I did not forget anything here - if you run into problems leave a comment and i'll try to help you out. Good luck.

Report

More on Tutorials

Advertising

Comments

  • mashpie posted on 09/11/10 04:26:03 PM
    You might consider using another aproach...
    Please check http://code.google.com/p/memcached/wiki/FAQ#Why_are_items_limited_to_1_megabyte_in_size?
    • rynop posted on 09/12/10 01:25:11 PM
      You might consider using another aproach...
      Please check http://code.google.com/p/memcached/wiki/FAQ#Why_are_items_limited_to_1_megabyte_in_size?

      If Mark was referring to the 1MB limit that exists for a given key's value - that is a soft limit as well. However if you need more then 1MB you are not using memcached correctly.

      memcached (and cakephp) support compression prior to writing the value for the key, so that helps this 1MB issue a bit - however the compression is in place to allow more entries, not to increase the size per entry.
  • euromark posted on 09/11/10 07:51:58 AM
    memcache has actually a very low max size limit of 1MB
    this is a huge pain in the ...
    i gets tons of error messages because of that - some cache files (thats why we want to cache em) just are a little bit bigger than 1MB.
    • rynop posted on 09/11/10 02:33:04 PM
      memcache has actually a very low max size limit of 1MB
      this is a huge pain in the ...
      i gets tons of error messages because of that - some cache files (thats why we want to cache em) just are a little bit bigger than 1MB.

      That is actually an incorrect statement. See the docs for how to change:
      http://code.google.com/p/memcached/wiki/NewConfiguringServer
      Memcached is used by some of the largest websites on the internet (Facebook included) - a 1MB limit would be unacceptable.

      On ubuntu, memcached defaults to 64megs. On Ubuntu, simply edit /etc/memcached.conf to allocate more memory, restart daemon and ur done.
      • T0aD posted on 12/04/10 06:34:29 AM
        [quote]memcache has actually a very low max size limit of 1MB
        this is a huge pain in the ...
        i gets tons of error messages because of that - some cache files (thats why we want to cache em) just are a little bit bigger than 1MB.

        That is actually an incorrect statement. See the docs for how to change:
        http://code.google.com/p/memcached/wiki/NewConfiguringServer
        Memcached is used by some of the largest websites on the internet (Facebook included) - a 1MB limit would be unacceptable.
        [end quote]
        You really wrote this article ? He meant memcached has a 'low' (well depends what you do) limit per OBJECT.

  • default007 posted on 09/01/10 09:00:52 AM
    Hi!

    What's the benefit of using memcached in the php.ini file as explained above, with

    session.save_handler = memcache

    instead of leaving that alone and putting

    Configure::write('Session.save', 'cache');

    in Cake's core.php?

    I'm having some trouble debugging an early expiration of my sessions, I don't know who is really responsible for that: cake, or php, or memcached...
    • rynop posted on 09/01/10 09:00:53 PM
      Hi!

      What's the benefit of using memcached in the php.ini file as explained above..

      Great Q JMVR. Good enough that I updated my article - I should have touched on this from the start.

      Short answer is to segment my session data and my object data into 2 separate memcache pools. That way I can allocate memory to just session data that will not get filled up by object cache data.

      Another reason may be that you run multiple webapps - all of which you want the performance improvement of memcache backed sessions, but not all of which have the ability to easily leverage memcache for object caching (think legacy php apps or simple ones that are not using Cake).
  • pcnalanda posted on 06/14/10 03:16:31 AM
    I have implemented memcache on session server and web server running on multple machines for load balancing. few times in a week, site's pages become blank, and whenever we change it's debug mode to 1 from 0. After that pages becomes fine. It seems like few bottleneck arise in memcache. Can suggest any solution?

    Thanks
    Prafull
    • rynop posted on 08/26/10 08:57:24 PM
      I have implemented memcache on session server and web server running on multple machines for load balancing. few times in a week, site's pages become blank, and whenever we change it's debug mode to 1 from 0. After that pages becomes fine. It seems like few bottleneck arise in memcache. Can suggest any solution?

      Thanks
      Prafull

      ^^Jakub Pas: your welcome :)

      ^Prafull: You need to be careful when using memcache for more then just sessions - I expect you have setup in app/config/core.php to use memcache for caching: this will use memcache to cache your models/controllers/other Cake persistent stuff.

      When you make a change to your code on your servers, you need to make sure to clear out the memcache (can simply restart memcached daemon). This will wipe out old cache that is probably conflicting with your new code. Careful here tho, cuz this will wipe out any current sessions (if your using memcache to back your sessions).

      This brings up an important point: and one i probably should have included in my original article. DONT use memcache to back sessions if you cant afford to lose sessions. EX: banking application. You don't get anything for free - memcache is an in memory beast. If it goes down or is cleared, anythign that relies on it is gone as well. I could probably write an entire article on this topic - but for now, if you cant afford to lose session data - back it with a database.
  • Amorphous posted on 02/12/10 03:51:49 PM
    This lowered my load avrage from 3 to 0.20;-) I did not exepected that cake sessions may have so much impact on filesystem and CPU. Thanks for article!
  • kiang posted on 01/10/10 07:07:44 AM
    Just found replied in wrong article. Sorry. ^^||
  • mashpie posted on 01/06/10 06:42:20 AM
    Hey thanks for these clear and advisable words!

    I just wanted to mention the possibility to also distribute the memcache over your server nodes.


    # configuration for php memcache module
    extension=memcache.so
    session.save_handler = memcache
    session.save_path = "tcp://192.168.1.1:11211?persistent=1,tcp://192.168.1.2:11211?persistent=1"

    the persistent parameter btw, force each apache instance to reuse the connection throughout a couple of requests.

    Thanks!
    Marcus
login to post a comment.