PHP sessions in a load balancing cluster - how?

60,353

Solution 1

You could set PHP to handle the sessions in the database, so all your servers share same session information as all servers use the same database for that.

A good tutorial for that can be found here.

Solution 2

The way we handle this is through memcached. All it takes is changing the php.ini similar to the following:

session.save_handler = memcache
session.save_path = "tcp://path.to.memcached.server:11211"

We use AWS ElastiCache, so the server path is a domain, but I'm sure it'd be similar for local memcached as well.

This method doesn't require any application code changes.

Solution 3

You don't mentioned what technology you are using for load balancing (software, hardware etc.); but in any case, the solution to your problem is to employ "sticky sessions" on the load balancer.

In summary, this means that when the first request from a "new" visitor comes in, they are assigned a specific server from the cluster: all future requests for the lifetime of their session are then directed to that server. In practice this means that applications written to work on a single server can be up-scaled to a balanced environment with zero/few code changes.

If you are using a hardware balancer, such as a Radware device, then the sticky sessions is configured as part of the cluster setup. Hardware devices usually give you more fine-grained control: such as which server a new user is assigned to (they can check for health status etc. and pick the most healthy / least utilised server), and more control of what happens when a server fails and drops out of the cluster. The drawback of hardware balancers is the cost - but they are worth it imho.

As for software balancers, it comes down to what you are using. For Apache there is the stickysession property on mod_proxy - and plenty of articles via google to get this working with the php session ( for example )


Edit: From other comments posted after the original question, it sounds like your "balancing" is done via Round Robin DNS, so the above probably won't apply. I'll refrain from commenting further and starting a flame against round robin dns.

Solution 4

If you have time and you still want to check more solutions, take a look at http://redis4you.com/articles.php?id=01..

Using redis you are fault tolerant. From my point of view, it could be better than memcache solutions because of this robustness.

Solution 5

The easiest thing to do is configure your load balancer to always send the same session to the same server.

If you still want to use session_set_save_handler then maybe take a look at auto_prepend.

Share:
60,353
Vilx-
Author by

Vilx-

Just your average everyday programmer. #SOreadytohelp

Updated on January 16, 2020

Comments

  • Vilx-
    Vilx- over 4 years

    OK, so I've got this totally rare an unique scenario of a load balanced PHP website. The bummer is - it didn't used to be load balanced. Now we're starting to get issues...

    Currently the only issue is with PHP sessions. Naturally nobody thought of this issue at first so the PHP session configuration was left at its defaults. Thus both servers have their own little stash of session files, and woe is the user who gets the next request thrown to the other server, because that doesn't have the session he created on the first one.

    Now, I've been reading PHP manual on how to solve this situation. There I found the nice function of session_set_save_handler(). (And, coincidentally, this topic on SO) Neat. Except I'll have to call this function in all the pages of the website. And developers of future pages would have to remember to call it all the time as well. Feels kinda clumsy, not to mention probably violating a dozen best coding practices. It would be much nicer if I could just flip some global configuration option and Voilà - the sessions all get magically stored in a DB or a memory cache or something.

    Any ideas on how to do this?


    Added: To clarify - I expect this to be a standard situation with a standard solution. FYI - I have a MySQL DB available. Surely there must be some ready-to-use code out there that solves this? I can, of course, write my own session saving stuff and auto_prepend option pointed out by Greg seems promising - but that would feel like reinventing the wheel. :P
    Added 2: The load balancing is DNS based. I'm not sure how this works, but I guess it should be something like this.
    Added 3: OK, I see that one solution is to use auto_prepend option to insert a call to session_set_save_handler() in every script and write my own DB persister, perhaps throwing in calls to memcached for better performance. Fair enough.

    Is there also some way that I could avoid coding all this myself? Like some famous and well-tested PHP plugin?

    Added much, much later: This is the way I went in the end: How to properly implement a custom session persister in PHP + MySQL?

    Also, I simply included the session handler manually in all pages.

  • Vilx-
    Vilx- almost 15 years
    The load balancing is somehow done with DNS entries. The hostname resolves to two different IP addresses and the browser picks one randomly. Or something like that - I don't really know the particulars. But AFAIK there is no load balancer. The "auto_prepend" looks promising.
  • Galen
    Galen almost 15 years
    +1 use auto_prepend to insert the session_set_save_handler function before every script
  • Ian
    Ian almost 15 years
    Sounds like you've got a "Round Robin DNS" on the go - en.wikipedia.org/wiki/Round_robin_DNS . I'll say that the least said about this "solution" to load balancing, the better.
  • Vilx-
    Vilx- almost 15 years
    I didn't choose this solution nor can I change it.
  • Vilx-
    Vilx- almost 15 years
    This is the current "quick workaround", but the admin doesn't like that. Something about security and stuff, I don't know the particulars.
  • Khriz
    Khriz almost 15 years
    Mmm, then you could use an external service like memcachedb using a hash of the key as a index for the sessions. The memcachedb service is very fast (especially writing) and easy to use, you can use a special and reduced set of the memcached functions from PHP.
  • Daniel
    Daniel over 12 years
    This is not the correct way. The issue is PHP sessions, forget about Databases, we're talking about PHP. This solution is merely a work around.
  • Ivan Hušnjak
    Ivan Hušnjak about 11 years
    memcached is a mixed blessing for storing sessions. Its fast, easy to setup but when it runs out of memory it will destroy old sessions, so permanent session storage will not work. Before using this, one should really think about if this data loss is fine or not for his application.
  • Ivan Hušnjak
    Ivan Hušnjak about 11 years
    NFS is not designed for high number of requests... remember, PHP loads session at session_start() and saves it when script execution ends (even if no session data changed!), so each PHP request will spawn two NFS requests.
  • Khriz
    Khriz about 11 years
    I don't manage sessions that way but it could be an option for people without access to other (better options) key-value storage engines. But yeah is not a very good option... :)
  • Darren Cook
    Darren Cook over 10 years
    More info here: php.net/manual/en/memcached.sessions.php Note: most of the documentation is actually in the comments there!
  • Matt Fletcher
    Matt Fletcher about 9 years
    I disagree. Storing PHP sessions in the database is a perfectly good solution to this problem.
  • r3wt
    r3wt about 8 years
    @MattFletcher its a poor solution to the problem. in memory storage should be used, like redis, memcached, or ramfs etc
  • sbrattla
    sbrattla over 7 years
    @r3wt in memory? Are you willing to accept that all sessions will disappear if the session storage (memcache etc) for some reason must be restarted?
  • Vilx-
    Vilx- over 7 years
    Well, without sticky sessions you get failover too. :) However, it the original question there's a different wrinkle - the load balancing is the "DNS round-robin" kind. So sticky sessions are out of the question anyway. :P
  • harigorana
    harigorana over 7 years
    @Vilx- We faced same issue for session in php with load balancer, and that worked for us. Only thing we did was asked our datacenter to enable the sticky session for the configured domain and request routing in round-robin only
  • wkw
    wkw about 7 years
    FWIW, we wasted a week trying to figure out why our AWS-hosted Magento setup with two backends and NFS share for cache dir was hopelessly slow. It was NFS. Don't do it, ever!
  • Khriz
    Khriz about 7 years
    Well it's an answer from 8 years ago, but sorry to hear that.
  • Josh Woodcock
    Josh Woodcock almost 7 years
    Are you going to change your application design because of physical architecture? That doesn't make any sense to me.
  • DOfficial
    DOfficial almost 7 years
    You could always use Redis
  • Kareem
    Kareem over 6 years
    A practical problem here is that when session cookie ends because user has closed the browser, the session will be active in the database. A hacker that has spoofed the session id can still access the user's session even after it expires.
  • That Realty Programmer Guy
    That Realty Programmer Guy over 5 years
    you can save and load to database, using push to cache on save and pull on no-session-found. best of both worlds. @DOfficial using Redis is a good way to accomplish this with pub/sub