We have a problem with PHP session when APC is enabled on our server.
The app works great without APC. However, since we enabled APC, the sessions seems to be getting mixed up when the server experiences heavy load, i.e. users are randomly logging on as another. Everything reverts back to normal once we disabled APC. We can't seem to find anyone with the same problem, except a related problem with these guys (set-cookie was being cached in MS ASP): http://msdn.microsoft.com/en-us/magazine/cc163577.aspx#S2
Anyone else has similar experience? Can you recommend any suggestions?
PS: We have all our sessions handled by files in php.ini. We are also running apache2.
We're having a similar issue here. APC is only a primary suspect at this point because it's been difficult to reproduce.
We're using Zend Framework w/ session management and the theory is that Zend's code is cached in APC and when the system is under severe load the code is using a previously cached SID instead of the current one.
Our safeguard is to save the session ID inside the session data and compare the values when the session is retrieved. If the IDs are different we destroy the session and exit.
well please verify that apc really mixes up data...
the only possible i can think of when this could happen is when it gets full and does a stackoverflow.
please check the usage and maby increase the cache size.
There is a problem that crops up with APC where custom session handling objects get destroyed before the session data is saved. It could be unrelated to your problem, but an explicit call to session_write_close before the regular PHP shutdown fixes that one.
Your problem sounds a bit different though, but I can confirm that issues do exist.
Just to complete the post, we had success in reducing this problem with three things:
1) We made extra checks to make sure that the IP is matched to the session ID, and logout the user otherwise. We could then use this to track how often the problem occurs.
2) We switched to XCache and immediately saw lower number of confused session IDs. However, under very heavy load the problem rears its ugly head again.
3) We then double the memory for Xcache in the php config (xcache.size and xcache.var_size) and now the problem is gone.
So we suspect either APC or Xcache running out of memory was the problem. We're still waiting to see if this is a permanent solution.
Related
I'm working on a website, using PHP and Codeigniter, configured to use Memcache for session storage. I'm using this library to replace Codeigniter's built-in session storage in order to use PHP's native sessions, and then I configured PHP to use Memcache to store session data. (I originally had the library connecting to Memcache directly, but I couldn't get the cookie to persist the way I wanted.) So it's all set up and working. But there's a problem, obviously. For some reason, the site will, at unpredictable intervals, drop user sessions. It's very erratic and hard to duplicate, and I'm not sure if it's losing the session entirely or just losing all the userdata - for my application, there's no difference visible to the user. It's definitely not related to inactivity - I've seen it happen overnight, but I've had reports of it occurring after sitting at one page for only a couple of minutes, too.
Now, I know what you're thinking. Read this before you answer. My first thought was, oh, Memcache is running out of space and it's doing its eviction thing. So I checked, and that doesn't seem to be the problem. Memcache is sitting pretty with tons of free space, and evictions are holding steady at zero. Unfortunately, that leaves me with no idea what's going on. Has anyone experienced this kind of problem?
I've been trying to track down some annoying session issues since my webhost upgrade to PHP 5.3.3 awhile back. I've determined that if there is an active session, calling session_start() from a subdirectory kills the existing session. As an example, I start a session and a user logs in to domain.com/index.php then the user navigates to domain.com/members/ which fires start_session() ... the user's session is lost.
I've dug around for this and can't find anything similar. Is there a PHP configuration that would account for this behavior?
Calling session_start() multiple times with that version of PHP shouldn't cause any problems, however there are other possible causes.
One possible explanation is that the client's browser isn't sending the session id back to the server. You can test this out by comparing the session id that both pages produce. Assuming that you have a controlled environment where you can test this properly, you can use session_id() to get the session.
It might also be that the user is hitting a different webserver. Since (by default) PHP stores sessions to disk, there is no way for multiple servers to share the session information. If this is a shared host, it's probably quite unlikely this is the cause. You can test this out however by using phpinfo(). It should give you enough information to determine if it's the same server or not. For multi-server systems, I'd look at storing sessions in memcache or mysql.
if your sessions works all right within the same directory (it is unclear from your question), there is the only possible reason for such a behavior, a pretty obvious one: "directory" cookie parameter.
It seems it is set to somewhat unusual value, other than default "/" for the session cookie parameter.
You have to check it out.
Anyway, it is almost useless to try ANY session/cookie related problem without an HTTP interchange log.
You have to use some HTTP sniffer, like LiveHTTPHeaders Firefox addon to see what cookie header was sent by the server and which one was returned by client.
Otherwise it's all going to be shooting in the dark.
Okay, as it seems from your yonder comment, the session id remains the same, so, no HTTP issue can be a reason. The issue become a kinda tricky to spot.
Could you please post your test script here?
I've spent quite a long time searching, trying, testing for what looked like the same problem. As google kept sending me here, I think sharing the solution might help others (though I feel strange posting on a 2011 question):
Session variables set in /bar.php were not set in /foo/foobar.php.
It realised that the issue had nothing to do with folder/subfolder when I finally found out that the link in http://www.example.com/bar.php was pointing to http://example.com/foo/foobar.php (missing www).
Correcting the URL in the html link solved the problem. Having no time to dig deeper, what I can figure out is that (in my config) Apache makes no difference and serves pages indifferently with and without www, whereas PHP doesn't share the session between what it considers being two different domains, example.com and www.example.com.
Is there a PHP configuration that would account for this behavior?
Yes, if the storage for the session data differs between those calls, the $_SESSION content will differ as well. The storage can be configured, see http://php.net/manual/en/session.configuration.php for all configuration options you have with sessions.
Next to that if PHP is unable to read the session store, you will get an empty array as well.
I can't tell you if this is the issue with your problem, but probably it's helpful.
BTW, calling session_start() and than having an empty $_SESSION is commonly a sign that a new session has been created. You can verify this if you use cookies for your sessions and you output headers_listDocs:
echo '<pre>', var_dump(headers_list());
If it contains a new cookie for the session, the session has been created with this request.
Lots of good suggestions here. Thanks everyone. I spent a good chunk of the weekend digging into this and wasn't able to directly resolve it. I ended up demonstrating to my webhost that this problem happens on two of his hosted sites and doesn't happen in a default install of PHP. To work around the problem, I ended up moving all of my login and session logic into a single class.
Wanted to share another answer, found in this SO: Session variables not accessible in subdirectory answered by clayRay.
My answer was that I had a custom "php.ini" file saved in the root directory, and moving those directives into ini_set() calls solved it. You could also shove those over to .htaccess if your host allows.
I had some thoughts back ago about using memcached for session storage, but came to the conclusion that it wouldn't be sufficient in the event of one or more of the servers in the memcached pool were about to go down.
A hybrid version is to save the main database (mySQL) from load caused by reads would be to work out a function that tries to fetch the data from the cache pool, and if that fails gets it from the database.
After putting some more thought into it, I started to think about using APC cache for session related data. If our web server would go down, sessions would be lost either way, so storing them in a local APC or a localhost memcached server maybe isn't that bad?
What's your experiences?
Generally, session data is something which should be treated as volatile in any situation. The user can always choose to eliminate the cookie themselves at any point (if you are using cookies, of course). For this reason, I see no problem with using memcached for session data.
For me, I'd just keep it simple - no need for a DB fallback unless you absolutely must never lose the user's session in the event of a memcached server failure. As I said at the beginning, I always treat sessions as purely volatile in any case and don't really store anything of any significance in them.
That's my two cents anyways.
Totally confused by this one...
We have a WAMPServer installation set up, running a number of virtual hosts from various document roots.
Just recently, one particular domain has started hanging the server. We traced it down to session_start(). If we comment it out, there are no problems (except, of course, for the fact that we can't do anything with the session). With it uncommented, it will hang the page load and, with enough reloads, will hang the entire server.
All of the other sites still work perfectly with their sessions. As far as I know, there is nothing different with the way sessions are being worked with. I am looking further into it (in case someone changed something) but right now I'm hoping for some direction :)
So, any thoughts?
So, I'm guessing that it's an application layer problem because the other sites' sessions are working properly. However, this assumes that they have their sessions configured the same way - save yourself some time by double checking that your site isn't doing some "unique" in its configuration compared to the other sites.
I would next examine the other session related code that is running in your application. It could be that by calling session_start() you're putting your application into a state where it will run other code. For example, maybe there's a block of code that says "only run this function if this session variable is set" and by starting the session you're exposing that variable, where it wouldn't have been exposed and therefore not run the offending function if the session wasn't started.
Good luck.
My first guess would be file permissions if you are using file based sessions. If you are using database sessions, then I would check to make sure a table isn't corrupt. Also, is it Apache, PHP or something else that's locked up?
It's possible that you hit a bug in your underlying infrastructure that you won't be able to resolve. You should at least clear all existing sessions before moving forward with trying to diagnose this.
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.
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.
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.
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.
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.
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.
If you are using php sessions you could share with NFS the /tmp directory, where I think the sessions are stored, between all the servers in the cluster. That way you don't need database.
Edited: You can also use an external service like memcachedb (persistent and fast) and store the session info in the memcachedb index and indentify it with a hash of the content or even the session ID.
When we had this situation we implemented some code that lives in a common header.
Essentially for each page we check if we know the session Id. If we dont we check if we're in the situation whehich you describe, by checking if we have stored sesion data in the DB.Otherwise we just start a new session.
Obviously this requires all relevant data to be copied to the DB, but if you encapsulate your session data in a seperate class then it works OK.
you could also try using memcache as session handler
Might be too late, but check this out: http://www.pureftpd.org/project/sharedance
Sharedance is a high-performance server to centralize ephemeral key/data
pairs on remote hosts, without the overhead and the complexity of an SQL
database.
It was mainly designed to share caches and sessions between a pool of web
servers. Access to a sharedance server is trivial through a simple PHP API and
it is compatible with the expectations of PHP 4 and PHP 5 session handlers.
When it comes to php session handling in the Load Balancing Cluster, it's best to have Sticky Sessions. For that ask the network of datacenter who is maintaining the load balancer to enable the sticky session. Once that is enabled you'll don't need worry about sessions at php end