I have a very simple setup with a drupal site where I am the only one logging in and writing content. There is no anon user input in forms or any other complicating stuff. The anon users will only be reading.
My goal is to make the site as fast as possible for anon users and able to serve as many anon users as possible. The content I write does not change very often.
I am using nginx as a web server and PHP-FPM for PHP FastCGI. I am not using apache at all.
I also want nginx to leave PHP alone as much as possible. To cache the content of PHP.
As for as I understand I have to use the HttpFcgiModule with fastcgi_cache to achieve caching of PHP in this case and NOT the HttpProxyModule. Is this correct?
How do I make sure my login page at example.com/user/ is not cached (I need to login from there)?
How do I make sure that once I am logged in I get pages from PHP / Drupal and NOT from the nginx cache used for serving anon users?
I hope someone can give me some pointers. Thanks in advance,
Lennart
Comments
As for as I understand I have
Yes.
That is done transparently. Check
fastcgi_no_cache.Check this:
### Testing if we should be serving content from cache or not. This is
### needed for any Drupal setup that uses an external cache.
## Testing the request method. Only GET and HEAD are caching safe.
map $request_method $no_cache {
default 0;
POST 1; # POST requests aren't cached usually
}
## Testing for the session cookie being present. If there is then no
## caching is to be done.
map $http_cookie $no_cache {
default 0;
~SESS 1; # PHP session cookie
}
and this.
### Implementation of the microcache concept as presented here:
### http://fennb.com/microcaching-speed-your-app-up-250x-with-no-n
## The cache zone referenced.
fastcgi_cache microcache;
## The cache key.
fastcgi_cache_key $host$request_uri;
## For 200 and 301 make the cache valid for 1 second.
fastcgi_cache_valid 200 301 1s;
## For 302 make it valid for 1 minute.
fastcgi_cache_valid 302 1m;
## For 404 make it valid 1 minute.
fastcgi_cache_valid 404 1m;
## If there are any upstream errors or the item has expired use
## whatever it is available.
fastcgi_cache_use_stale error timeout invalid_header updating http_500;
## The Cache-Control and Expires headers should be delivered untouched
## from the upstream to the client.
fastcgi_ignore_headers Cache-Control Expires;
## If we have a cookie we should bypass the cache. The same if we have a
fastcgi_cache_bypass $no_cache;
fastcgi_no_cache $no_cache;
## Add a cache miss/hit status header.
add_header X-Micro-Cache $upstream_cache_status;
## To avoid any interaction with the cache control headers we expire
## everything on this location immediately.
expires epoch;
Tweak this to your liking. Note that this presupposes a caching concept based on being cheap to cache and expensive to deal with the expiration logic.
Check this thread for elaboration: http://groups.drupal.org/node/175644. In there is a reference to Brian's setup that is based on expiration logic. I'm working on the cache warmer module. It will use Nginx evented nature for maintaining the cache primed. Light on the PHP side of things. Apart from hitting the site, of course. Stay tuned.
Thanks a lot for the quick
Thanks a lot for the quick and elaborate reply.
I'll try to make the changes and report back here in a few days with some results.
Probably don't need the POST check
http://wiki.nginx.org/HttpFcgiModule#fastcgi_cache_methods
Yep
But that file is also used for supporting Boost caching, hence the method check. If using only fastcgi/proxy cache it can be dropped.
Good result
I made the changes. The results are very convincing.
Before:
Requests per second: 156.99 [#/sec] (mean)
Time per request: 955.453 [ms] (mean)
Time per request: 6.370 [ms] (mean, across all concurrent requests)
After:
Requests per second: 3951.13 [#/sec] (mean)
Time per request: 37.964 [ms] (mean)
Time per request: 0.253 [ms] (mean, across all concurrent requests)
Thanks a lot, Perusio :)
One more thing. I had to comment out this line:
fastcgi_cache_bypass $no_cache;
otherwise nginx would not start.
What version of nginx?
What version of nginx?
Version
nginx 0.7.67
Now that I logged out of my drupal site, I cannot login again from example.com/user. Could that be because I commented out that line?
I installed nginx as a package on Debian 6 like this:
apt-get install nginx
Update
I updated to nginx/1.0.11
I also uncommented the line. Now I can log in just fine :)
The performance seems to have gone down a bit since the upgrade, though:
Now.
Requests per second: 1177.59 [#/sec] (mean)
Time per request: 127.379 [ms] (mean)
Time per request: 0.849 [ms] (mean, across all concurrent requests)
but the upgrade also changed some other things on the server so the performance decrease is not necessarily nginx-related.
Are you running ab on the
Are you running ab on the same machine that hosts the server or across a private or public network of some sort?
Also perusio's config in this
Also perusio's config in this thread, based on that article, keeps responses in the cache for only 1 second, because it is designed to keep the content fresh. You say in the original topic that you don't change your content very often, so you can certainly switch to a 1 hour or 12 hour or 1 day cache time.
For example:
fastcgi_cache_valid 200 301 12h;and then clear the entire cache manually with rm -r /var/cache/nginx/[cache_name}/* after updating content if you needed to.
Some tips in case you haven't already:
What options are you using with ab? Are you using -k to keep the connection open and are you using -c 1 or testing a higher number of concurrent connections?
Have you installed devel and enabled the page timer so you can compare the time that php calculates as the time to build the page?
Have you installed firebug in Firefox and checked the net tab for the page so you can check the page time from that and also read the headers to make sure you're getting a "HIT" on your cache?
Thanks
I'm running ab on the same server as nginx so i guess the test is purely for testing different configurations and not indicative of "real" performance.
Here is the ab command I use:
ab -c 150 -n 1000 -k http://www.example.com/
I am no expert, but I guess since I use the same line every time I should at least be able to use the results for comparison of different setups.
I switched the cache op from one second to one minute. It seems to have made a big difference:
Requests per second: 3698.13 [#/sec] (mean)
Time per request: 40.561 [ms] (mean)
Time per request: 0.270 [ms] (mean, across all concurrent requests)
Yes, I have had devel enabled. nginx and mod_php does not seem to make a big difference in the time it takes to generate the php output. I enabled APC. That helped in that context.
The cache is "hitting" :)
All in all I'm very satisfied with the way things are running now. Thanks a lot for the help.
Sounds good. -c 150 is a
Sounds good.
-c 150 is a pretty harsh test for a site.
I advise against using ab
altogether. ab is CPU bound, it uses threads, since it's based on the Apache Portable Runtime. Here's some tools that take a different approach:
httpload: Usesselect()for file descriptor handling.htpress: Usesepollin Linux andkqueueon *BSD.weighttp: This is the tool that inspiredhtpress, which has some limitationsaccording to the later tool author.
Note also that you have to tweak your kernel parameters to get a truly high performance setup.
Thanks
Yes, I had the idea that ab was not completely "realistic" for testing. I am content with the way things are working now, though. It's just a "hobby" site, after all.
I am sure I could do many things to optimize further, but I think the site will withstand quite a heavy influx of anon users as it stands currently. I have about 10 thousand pageviews per day.
Thanks again gor the help :)