7 ms·
12,000 Requests per second with Nginx, PHP and Memcached
- 51Cards 16y agoJust about enough to sell tickets to Comic-Con.
- jacques_chester 16y agoA core issue for modern websites is one of cache invalidation. The linked article essentially sidesteps the issue, with the in-memory speed of memcache obscuring the problem. For traditional LAMP-style document-producing engines, cache invalidation strategies rely either on TTL (leading, as he says, to stale data) or on polling the source data (leading to an unavoidable performance hit, amortised over the improved speed of the cache). Leaving aside TTLs, the key issue is that cache invalidation is driven by GET and not POST requests. I wrote a thesis proposal where part of the concept was to drive all cache invalidation from POSTs. New comment added to a story? A regeneration is queued up. New post on front page? A regeneration is queued up. Firstly, you can improve both staleness by only regenerating when new data is added, and you improve performance by not needing to poll the source data for currency every time you touch the cache. In an ideal situation you could come close to raw HTTP serving speed. You also allow some degree of dynamic responses to load. Under high rates of POSTs you can batch up regeneration events to prioritise the GETs. However, I won't be pursuing that project -- I've been accepted for one I was more interested in.
- jonah 16y agoI've been thinking along similar lines for my project and the issue i'm running into conceptually is tracking WHICH cache records to invalidate upon POST. Say an HTML list, an HTML detail page, and a full composite object all contain references to the particular item you updated. Single items - the detail page and object are fairly easy to know about, but what about a list view and a grid view that also contain that item. What are your thoughts?
- jacques_chester 16y agoMy thoughts were to borrow a page from wikis and make links between documents a part of the model. For actual documents (blog posts, comments etc) I'd place them on disk. Metadata, including links between pages, would be in the database. With Postgres triggers + NOTIFY you can cause invalidation based on INSERTs and UPDATEs.
- roel_v 16y agoA dependency graph between database tables and pages, no? How to define 'page' depends on the rest of the application, I guess in most frameworks it would be 'module' + 'action'.
- mnutt 16y agoI think the reason that cache invalidation scheme is not in wider use is that it's not very generalizable, and as data model complexity increases things get out of control. If someone adds a new post, you may end up having to regenerate the post page, the pages before it and after it, an authors page, any number of tags pages, etc. So I think it works sometimes in specific instances, but not as a general caching strategy. If it worked though, it would seem to be the most beneficial. Is anybody working on it?
- mikeytown2 16y agoFor those interested in full page caching, smart cache invalidation & and a built in crawler. Check out Drupal's boost module. http://drupal.org/project/boost http://drupal.org/project/boost I'm the guy who has shaped this into the monster it has now become. The apache htaccess rules are still getting refined & it comes with lighttpd and nginx rules as well. I've been working on taking this full circle; taking the monster that was created, keeping the core parts that work and spiting the other parts into separate Drupal modules. http://drupal.org/project/expire http://drupal.org/project/expire will contain the cache invalidation logic and I'll create a crawler once I come up with a better multi process crawler http://groups.drupal.org/node/126624 http://groups.drupal.org/node/126624
- roel_v 16y agoYes, this is what I thought he was saying, but I was thrown off by his 'I think this is entirely new' comment in the beginning. Pre-generating pages when the data changes is not new, we did it in 2000. Maybe I didn't fully understand and there is some aspect of it that is new (for example we used disk-based caches, not memory, but that doesn't really change the idea imo).
- antihero 16y agoSeeing as nginx requests can be done by their URI, you could have a /write prefix to anything that handles user input, which wouldn't be cached? Especially on sites that don't have masses of user writing (in which case you'd use some sort of intermediary queueing daemon that nginx could shove things to, and could slowly feed the things into your backend). Writing the /write prefix would immediately invalidate the cache for the changed pages and thus they could be easily regenerated a single time and placed into the cache until the next time (or perhaps the pages could simply be invalidated once every 10 seconds or so - very little has to be truly realtime).
- rkalla 16y agoFor 4 years I tried to run my WordPress site off of Apache + PHP. For the first 3 years it was Apache+Prefork+mod_php+WordPress (default setup for any on RedHat-based or Debian-based setups for the longest time). Any time I would get a story on Slashdot or Digg the site would die for at least half a day... god I hate it. I went from a 1GB RAM VPS to a 12GB dedicated machine in 3.5 years trying to get it to stop crashing whenever I would get a flood of traffic and was never able to. I pushed back on the idea of being a Linux sys admin for so long because I didn't want that hassle, but alas, I had to bother with it. Finally at about the year 4 mark I decided no REAL site on the planet was running with this configuration since it didn't seem to matter the hardware you threw at it (yes I tweaked the Apache setup/mod-list tirelessly to scale with the improved hardware). I finally started digging into how real human beings setup Apache and came across the argument for using the "MPM worker" as opposed to the default pre-fork worker. Made sense to me; less 30+ MB processes running around answering questions. After that change, it helped a little... I have no hard numbers on hand, but it felt like a small improvement. I kept digging and soon ran across the one-hacky-but-now-officially-supported method of using Apache + a family of PHP VM threads pre-launched and called via FastCGI to execute the .php pages from my WordPress site, the computer-science part of my brain loved this idea... the Java-trained side of me suddenly made me realize that prior to this with Prefork and mod_php, every time someone was connecting I was spinning up a new Apache thread and a new PHP VM every single time (please correct this if wrong... this is how I understood it). With FastCGI I could have a family of say 20-some PHP VM threads living in harmony and responding to Apache constantly asking them questions. After rolling that change out at about year 4, I noticed a big improvement; maybe about 50%. At my next Slashdotting the server got REALLY slow, but hung in there; no crashes. I thought it was odd that all that hardware still couldn't host things snappy... it seemed like every other day I was clicking a link off of Hacker News or Reddit front page to some dude's personal blog that was responding very quickly to me and I was positive these people weren't spending $300/mo like I was on dedicated hardware to run their blog. So I kept digging. As you guys probably know, when you start searching for what sucks about Apache two things come up more than any other: "use nginx" or "use lighttpd" -- I had read that early versions of lighttpd had some memory leak issues (I think long-since fixed) and had a handful of Ruby friends that loved nginx... so I decided to stay up all night one night and port the site over. 25mins later I was done. Yea so that was a lot easier than I expected. The only painful part was using some heavy handed redirect logic to convert my WP-SuperCache rules over to nginx (the author wasn't supporting nginx yet, but I think he does not). I would point out that the server load with nginx running with NO CACHING (WP-SuperCache disabled, all queries execute PHP and perform a MySQL query) was something like 1/4 what my Apache/MPM/FastCGI/PHP/WP-SuperCache-enabled setup was using. Once I got WP-SuperCache up and running on nginx, the different was stupid-big. The nginx/WP-SuperCache setup was using 1/8th or 1/10th the system resources that the Apache setup had been using. Soon there after I got Slashdotted with a peak of roughly 400 users on at a time and the server load barely crawled beyond a 1 (screenshot): http://www.thebuzzmedia.com/wp-content/uploads/2010/12/slashdot-story-400-users-nginx-performance.png http://www.thebuzzmedia.com/wp-content/uploads/2010/12/slash... Overall I couldn't be happier with nginx. I think there are probably people that live in oxygen-rich test chambers inside of military bunkers who were bread to tweak Apache that can optimize it to have comparable performance, but that wasn't me. Out of the box nginx has been fantastic thus far. And that is my little story related to this subject... for what it's worth.
- ck2 16y agoThe real bottleneck in any apache setup is apache. For those that need hassle-free backwards htaccess compatibility, try litespeed. But there a few nice alternative to apache these days.
- jjoe 16y agoI had created a post here regarding a Varnish plugin we wrote for cPanel over a weekend codeathon (http://www.unixy.net/varnish http://www.unixy.net/varnish). Based on benchmarks, Varnish+Apache came out ahead of Litespeed. But benchmarks are not always conclusive since user traffic patterns are difficult to reproduce in a benchmark environments. The feedback we've gotten so far on the plugin is very positive (google if interested). Nginx can do caching but not with the same flexibility as Varnish. Regards
- ck2 16y agoUm, but varnish is just a cache and so of course it's faster for static content? Or am I missing something? Litespeed can work with php several times faster than apache+php while serving dynamic content (and so can nginx).
- sunkencity 16y agoThe article is about full page caching. How's that different than static content?
- jjoe 16y agoVarnish is good for caching any object; static or dynamic. The plugin we wrote uses Varnish to do a lot of dynamic page caching. Varnish is better at dynamic page caching than Nginx. Litespeed has a caching mechanism too (introduced recently). But I think it requires an enterprise licesense of 2+ CPU. Here are some benchmarks of Apache+Varnish vs Litespeed: http://unixy.net/apache-vs-litespeed http://unixy.net/apache-vs-litespeed Regards
- zepolen 16y ago
- ertug 16y agoI am also experimenting with full-page caching and cache invalidation. Here are my prototypes: https://github.com/ertug/dynasta https://github.com/ertug/dynasta https://github.com/ertug/jphpserv https://github.com/ertug/jphpserv
- edanm 16y agoA question I hope someone here can answer: I'm now working on my first major webapp, so I've been learning how to be a sysadmin, pretty much from scratch (almost no previous experience with running webapps, lots of experience with other things though). Anyway, I've been trying to find resources to help learn, but it's been extremely difficult. These are the questions that are still bugging me, hopefully someone here can point me to some good reading about them. Note that my stack is Python/Django over Apache (mod_wsgi) right now. Also note that my site has a "ping" system, where each client connected continuously pings the server every few seconds to see if any new info arrived, making me have to handle a larger amount of requests per second, I believe. The questions: 1. What kind of load do I need to handle? Is 12,000 requests per second terrible/good/great performance? How do I go about figuring out how many people are online at once for most sites? How do I even estimate it? 2. How can I test the performance of my application? I've learned that Apache Bench is used a lot, but are there better tools? 3. What are the best tools to help me monitor and understand the load on my server? 4. How do I go about understanding the bottlenecks in my application? Right now, my Apache process is taking most of the cpu. What does that imply about where I should optimize? Sorry to braindump, but I've been looking for answers to these questions online and haven't found any clear help.
- jacques_chester 16y agoAs a "meta-answer", you might consider breaking these questions up and asking them on one of the stackexchange sites. However: 1. "What kind of load" depends on your anticipated visits to the site. There's no substitute for real traffic, but simulation can do in a pinch. Likewise there's no substitute for simulation, but capacity planning tools can do in a pinch. Look at The Art of Capacity Planning, The Art of Application Performance Testing and Guerilla Capacity Planning. 2. There are many tools, some quite sophisticated. Look at siege, httperf and others like them. Consider also using automatic UAT tools (like Cucumber) as the basis for performance and stress tests. 3. Look into monit, zenoss or nagios. There are others. 4. Profiling, profiling, profiling. And ditch Apache, it's a memory hog. Consider lighttpd or nginx.
- edanm 16y ago
- to 16y agowe started using apache and fastcgi php in feb 2001. since memcache didnt existed yet or at least we didnt knew about it, we used ram disks to temp store things like logs and had logrotate get rid of it and in addition shared mem within php. we hand compiled apache with every available cpu flag we could find to get it down to a 400kb bin. we adjusted everything we could on the network settings. two servers, 2gb ram, dual core amd64. answering 12k static req/sec and around 3000 dyn req/sec. it took most of the internet another 5 years to understand this. since that time i feel kinda like a guru. we also were first to adapt lighttpd in 2006/2007 on a large scale ad server. and im working on implementing node.js at the moment. you just have to stay cutting edge. saves you a lot of money too. (fyi: he's not mentioning if keep-alive is on or off. most likely its on, means the benchmark is kinda off because he gets served straight from system cache after the first request)
- antihero 16y agoWith nginx+PHP script that just echoes "hi", I get a mere ~2000req/sec. What am I doing wrong? What are the specs of his server?
- ovi256 16y agoHe's using the nginx full-page cache mechanism, backed into memcached. This way nginx does not touch PHP at all. It goes straight to memcached, which keeps data in RAM, so it serves pages in 7 ms.
- antihero 16y agoFair enough. Surely this would be mostly useless for anything other than static sites though?
- ovi256 16y agoJust wanted to say thanks for the great comments on this topic. I'm just working on optimizing page speed for a client, and there's a wealth of suggestions on this page.
- cagenut 16y agoHere is the secret to getting the whole nginx/fastcgi vs. apache/mod_php thing to click in your head. The trick is to think of it in two layers. The "spoonfeeding" layer and the "worker" layer. In nginx/fastcgi, nginx is the spoonfeeding layer and the fastcgi worker procceses are, you guessed it, the workers. Nginx effectively acts as a proxy, holding open the thousands of connections users have made but only a small fraction of them are actually being worked on by the worker processes at any given moment. With apache/mod_php there is no spoonfeeding layer. Every single apache child has the php interpreter loaded and acts as a worker process. When you look at your nginx vs. your apache setups think of apache children as the fascgi workers not as nginx. Most of the time people switch to nginx and claim amazing results what got them that was the addition of a spoonfeeding layer. Technically, you could have done that several other ways. Most higher end sites who've had to care about this stuff for years let the loadbalancer handle the spoonfeeder layer, that way the (web)appservers can focus on being appservers. Doesn't matter if its a $120K Netscaler or a $0 copy of varnish or ha-proxy bound to localhost, the point is you never want a 1:1 relationship between "active but idle user connections" and "worker processes".
- hackernewz 16y agoWP is trash. You can speed it up about 10 times with just a couple query fixes and removing the 100 extra calls to stripslashes you get when you pull a get var 100 times.
- andrewthornton 16y agoIs using nginx with memcached support a good alternative to using varnish? Has anyone compared both on a system that gets real traffic?
- Mikushi 16y agoInteresting, but let's be honest for a second, in 99.99% of the cases, a classic Apache+mod_php will be well suited. You could count on your hands the number of sites that require a setup that needs to handle 12,000req/sec and more. If you need to speed things up, reduce the memory footprint, i'd recommend using APC or eAccelerator, and put something like Varnish or Squid in front. As well as ditch stuff like WP or Drupal, might be nice and easy to use, but the code behind it is just a disaster if you want something fast and optimized. Use extensions like XHProf or Xdebug to profile your code, and find the bottlenecks and memory eating functions. Stop blaming Apache/PHP, they both have defaults, but in most of the case, the default is in the code.