25

We are moving from a 1 webserver setup to a two webserver setup and I need to start sharing PHP sessions between the two load balanced machines. We already have memcached installed (and started) and so I was pleasantly surprized that I could accomplish sharing sessions between the new servers by changing only 3 lines in the php.ini file (the session.save_handler and session.save_path):

I replaced:

session.save_handler = files

with:

session.save_handler = memcache

Then on the master webserver I set the session.save_path to point to localhost:

session.save_path="tcp://localhost:11211"

and on the slave webserver I set the session.save_path to point to the master:

session.save_path="tcp://192.168.0.1:11211"

Job done, I tested it and it works. But...

Obviously using memcache means the sessions are in RAM and will be lost if a machine is rebooted or the memcache daemon crashes - I'm a little concerned by this but I am a bit more worried about the network traffic between the two webservers (especially as we scale up) because whenever someone is load balanced to the slave webserver their sessions will be fetched across the network from the master webserver. I was wondering if I could define two save_paths so the machines look in their own session storage before using the network. For example:

Master:

session.save_path="tcp://localhost:11211, tcp://192.168.0.2:11211"

Slave:

session.save_path="tcp://localhost:11211, tcp://192.168.0.1:11211"

Would this successfully share sessions across the servers AND help performance? i.e save network traffic 50% of the time. Or is this technique only for failovers (e.g. when one memcache daemon is unreachable)?

Note: I'm not really asking specifically about memcache replication - more about whether the PHP memcache client can peak inside each memcache daemon in a pool, return a session if it finds one and only create a new session if it doesn't find one in all the stores. As I'm writing this I'm thinking I'm asking a bit much from PHP, lol...

Assume: no sticky-sessions, round-robin load balancing, LAMP servers.

1

5 Answers 5

37

Disclaimer: You'd be mad to listen to me without doing a tonne of testing AND getting a 2nd opinion from someone qualified - I'm new to this game.

The efficiency improvement idea proposed in this question won't work. The main mistake that I made was to think that the order that the memcached stores are defined in the pool dictates some kind of priority. This is not the case. When you define a pool of memached daemons (e.g. using session.save_path="tcp://192.168.0.1:11211, tcp://192.168.0.2:11211") you can't know which store will be used. Data is distributed evenly, meaning that a item might be stored in the first, or it could be the last (or it could be both if the memcache client is configured to replicate - note it is the client that handles replication, the memcached server does not do it itself). Either way will mean that using localhost as the first in the pool won't improve performance - there is a 50% chance of hitting either store.

Having done a little bit of testing and research I have concluded that you CAN share sessions across servers using memcache BUT you probably don't want to - it doesn't seem to be popular because it doesn't scale as well as using a shared database at it is not as robust. I'd appreciate feedback on this so I can learn more...

Ignore the following unless you have a PHP app:


Tip 1: If you want to share sessions across 2 servers using memcache:

Ensure you answered Yes to "Enable memcache session handler support?" when you installed the PHP memcache client and add the following in your /etc/php.d/memcache.ini file:

session.save_handler = memcache

On webserver 1 (IP: 192.168.0.1):

session.save_path="tcp://192.168.0.1:11211"

On webserver 2 (IP: 192.168.0.2):

session.save_path="tcp://192.168.0.1:11211"

Tip 2: If you want to share sessions across 2 servers using memcache AND have failover support:

Add the following to your /etc/php.d/memcache.ini file:

memcache.hash_strategy = consistent
memcache.allow_failover = 1

On webserver 1 (IP: 192.168.0.1):

session.save_path="tcp://192.168.0.1:11211, tcp://192.168.0.2:11211"

On webserver 2 (IP: 192.168.0.2):

session.save_path="tcp://192.168.0.1:11211, tcp://192.168.0.2:11211"

Notes:

  • This highlights another mistake I made in the original question - I wasn't using an identical session.save_path on all servers.
  • In this case "failover" means that should one memcache daemon fail, the PHP memcache client will start using the other one. i.e. anyone who had their session in the store that failed will be logged out. It is not transparent failover.

Tip 3: If you want to share sessions using memcache AND have transparent failover support:

Same as tip 2 except you need to add the following to your /etc/php.d/memcache.ini file:

memcache.session_redundancy=2

Notes:

  • This makes the PHP memcache client write the sessions to 2 servers. You get redundancy (like RAID-1) so that writes are sent to n mirrors, and failed get's are retried on the mirrors. This will mean that users do not loose their session in the case of one memcache daemon failure.
  • Mirrored writes are done in parallel (using non-blocking-IO) so speed performance shouldn't go down much as the number of mirrors increases. However, network traffic will increase if your memcache mirrors are distributed on different machines. For example, there is no longer a 50% chance of using localhost and avoiding network access.
    • Apparently, the delay in write replication can cause old data to be retrieved instead of a cache miss. The question is whether this matters to your application? How often do you write session data?
  • memcache.session_redundancy is for session redundancy but there is also a memcache.redundancy ini option that can be used by your PHP application code if you want it to have a different level of redundancy.
  • You need a recent version (still in beta at this time) of the PHP memcache client - Version 3.0.3 from pecl worked for me.
3
  • Could you comment on "it doesn't scale as well as using a shared database"? I don't see how it is different from a typical master-slave DB setup. Thanks! Mar 6, 2012 at 16:02
  • This is a pretty cool breakdown, though there are rumours (aka bug reports) that this doesn't work as expected when you use ext/memcache version 3.x. We're playing with that option as well and I decided to loop through the server list and write to it myself.
    – Till
    Apr 19, 2012 at 15:51
  • in case of tip 3: what if one memcached host goes down and then it comes up, then seconds host goes down. as i understand - no session data will be restored and some of it will be lost, right?
    – GioMac
    Oct 20, 2014 at 20:51
28
+50

Re: Tip 3 above (for anyone else who happens to come across this via google), it seems that at least presently in order for this to work you must use memcache.session_redundancy = N+1 for N servers in your pool, at least that seems to be the minimum threshold value that works. (Tested with php 5.3.3 on debian stable, pecl memcache 3.0.6, two memcached servers. session_redundancy=2 would fail as soon as I turned off the first server in the save_path, session_redundancy=3 works fine.)

This seems to be captured in these bug reports:

4
  • 1
    Can't upvote you enough..
    – fest
    Jan 23, 2013 at 22:25
  • 1
    I'm glad I scrolled down. This was the problem. Jun 11, 2013 at 18:36
  • It isn't clear to me, is this feature only available in PECL memcache 3.x series? All of those are listed at Beta software on pecl.php.net/package/memcache, whereas on 2.2.7 if I kill the server that I see the leader on, everything dies.
    – Joe
    Aug 14, 2014 at 18:50
  • It's been years since I looked at this, to be honest. As I recall, it was a 3.x feature (icbw). We deployed many systems using the "beta" versions of that plugin (some of them quite high traffic) and didn't have any problems that seemed related to that. YMMV, test things before they go live, etc. :) I haven't been working in PHP for a few years now so some of the finer points of trivia are starting to fade. Aug 20, 2014 at 3:42
3

Along with the php.ini settings shown above ensure the following are set too:

memcache.allow_failover = 1  
memcache.hash_strategy = 'consistent'

Then you'll get full failover and client-side redundancy. The caveat with this approach is that if memcached is down on localhost there will always be a read miss before the php memcache client tries the next server in the pool specified in session.save_path

Just bear in mind that this affects the global settings for the php memcache client running on your web server.

1
  • Does using a consistent hashing strategy make sense considering that the session.save_path is different on each webserver?
    – Tom
    Jul 30, 2010 at 9:24
1

memcached doesn't work that way (please correct me if I'm wrong!)

If you want your application to have redundant session storage, you have to create something that alters/add/deletes entries to both memcached instances. memcached doesn't handle this, the only thing it provides is as key hash storage. So no replication, synchronization, nothing, nada.

I hope I am not wrong on this matter, but this is what I know of memcached, been a few years since I touched it.

2
  • It would be handy for me if you were wrong. :-) There is a article in phpslacker.com (phpslacker.com/2009/03/02/php-session-clustering-with-memcache) which suggests memcached can work as described in the question. Perhaps it depends how the memcache client implements the hashing strategy?
    – Tom
    Jul 27, 2010 at 10:58
  • 1
    memcache doesn't work like that, but it seems that php can work the way you want it to. You will have to change php.ini or change your app like described. From the blog: Where’s the clustering you ask Well, truth be told there isn’t any. What we have so far is a memcache pool consisting of 2 servers. PHP is configured to write to the pool. PHP reads/writes to the server pool in order specified by “session.save_path” ini directive. For reads PHP will request a cache object by key from the pool. Because “failover” is enabled PHP will query the pool of memcache servers one-by-one until the[...]
    – tore-
    Jul 28, 2010 at 12:38
1

memcached doesn't replicate out of the box, but repcached (a patched memcached) does. However if you're already using mysql then why not just use its replication functionality with master-master replication and get the benefit of full data replication.

C.

5
  • Thanks for the info. It's not really replication that I'm after. It's more a case of wanting to peak into each memcached in turn until the session is found. i.e. checking localhost first because it's fastest and then checking the other server next.
    – Tom
    Jul 27, 2010 at 10:10
  • 1
    In the name of all the gods WHY???? This is the totally the wrong solution to....well just about any problem I can think of. In addition to being very inefficient even with just 2 servers performance will get progressively worse very quickly if you ever add more servers. And that's not considering the fact that your solution makes outages twice as likely as they were with a single server when in practice adding servers to a cluster should reduce the probability of an outage. (BTW if you mean DNS based round-robin then session affinity is implicit!)
    – symcbean
    Jul 28, 2010 at 10:52
  • Thanks for the feedback, yes, I freely admit I'm a noob at session sharing! :-) However, I still haven't understood why my proposal is so ugly. I thought it'd be more efficient than using a shared DB and I also thought it'd make outages less likely.
    – Tom
    Jul 29, 2010 at 5:17
  • No, it makes them more likely. Federating the data like this makes sense when you've got a very large number of nodes because you reduce the amount of replication but one would typically do some replication withn a defined number of pools to preserve availability. You'd need to be very picky about performance to see a difference between repcached replication and mysqld replication.
    – symcbean
    Jul 29, 2010 at 11:17
  • I have tested and confirmed that as long as I am using the allow_failover=1, multiple mirrors does make outages LESS likely. I can shutdown one mirror, restart it and shutdown the other, restart it and shutdown the first again - all without being logged out. I guess the PHP memcache client is doing alot of trickery behind the scenes.
    – Tom
    Jul 30, 2010 at 12:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .