Check caching for speed

Discussion corner for Developers of Serendipity.
Post Reply
nealk
Regular
Posts: 26
Joined: Sun Sep 20, 2009 1:09 am

Check caching for speed

Post by nealk » Thu Apr 09, 2015 6:58 pm

I've noticed that two URLs on my blog comprise the majority of DB queries (> 90%). They are accesses to "/blog/" (and /blog/index.php without any "?" parameters), and accesses to my rss2 feed (that's the only RSS feed I enabled).

I just modified index.php to cache results for 5 minutes, just to make results faster. (This works on my system because I don't typically update entries faster than once a week, and one every 5 minutes is good enough for the seldom-changing content.)

This cheap change requires four steps:

1. Create a cache directory under your blog. I used mkdir 'blog/fastcache/'

2. Add in code that checks the cache for already generated content. If it is less than 5 minutes, then return the content. Otherwise, generate the output into a buffer. Put this at the start of index.php:

Code: Select all

  global $NAKCache;
  $NAKCache=false;
  if ($_SERVER['REQUEST_METHOD']=='GET')
    {
    if ($_SERVER['REQUEST_URI']=="/blog/index.php?/feeds/index.rss2") { $NAKCache="fastcache/feeds_index.rss2"; }
    elseif ($_SERVER['REQUEST_URI']=="/blog/index.php") { $NAKCache="fastcache/index.php"; }
    elseif ($_SERVER['REQUEST_URI']=="/blog/") { $NAKCache="fastcache/index.php"; }
    }
  if ($NAKCache) // If using hacked cache
    {
    if (is_file($NAKCache) && (time()-filemtime($NAKCache) < 5*60))
      {
      readfile($NAKCache);
      return;
      }
    ob_start();
    }
The "NAK" prefix are my initials. Feel free to change those variable names. Also, the 5 minute timeout (5*60) should probably be configurable.

3. At the end of index.php, add the closing/write-cache code:

Code: Select all

NAKexit:
  if ($NAKCache) // Save to hacked cache
    {
    $Out=ob_get_clean();
    if (substr_count($Out,"\n") > 20) { file_put_contents($NAKCache,$Out,LOCK_EX); }
    elseif (is_file($NAKCache)) { $Out = file_get_contents($NAKCache); }
    echo $Out;
    }
Yes: I use a goto tag...
Also, if the output is shorter than 20 lines, then I assume there was a bug somewhere. This won't cache bugs.

4. index.php has a couple of 'exit;' calls. That's bad because RSS code won't reach my cache write code. Change every 'exit;' to 'goto NAKexit;'.

That's it. This little code change dramatically sped up the server since it isn't doing a database query each time. And it will auto-refresh within 5 minutes.

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Thu Apr 09, 2015 7:05 pm

That is a nice idea. I tried a caching scheme before (to the db though, but that still should help), and Garvin had a powercache-branch. I really would like to have soemthing like that in s9y.

User avatar
Don Chambers
Regular
Posts: 3614
Joined: Mon Feb 13, 2006 3:40 am
Location: Chicago, IL, USA
Contact:

Re: Check caching for speed

Post by Don Chambers » Thu Apr 09, 2015 11:59 pm

onli wrote:I really would like to have soemthing like that in s9y.
X2 !!!!!

User avatar
mattsches
Regular
Posts: 435
Joined: Sat Nov 05, 2005 10:35 pm
Location: Wiesbaden, Germany
Contact:

Re: Check caching for speed

Post by mattsches » Sun Apr 12, 2015 5:18 pm

There are also some plugins which implement their own caching. Maybe we can think of a way to create a global cache class that can be utilized by the core as well as any plugin that wants to.

(Yes, index.php is quite a mess - and not easy to clean up :cry: )

nealk
Regular
Posts: 26
Joined: Sun Sep 20, 2009 1:09 am

Re: Check caching for speed

Post by nealk » Tue Apr 14, 2015 6:21 pm

One more hack for my temp cache...

When a user post/edits an entry, the cache should be flushed.
File: include/functions_entries.inc.php
Function: serendipity_updertEntry
At the end (right before the final return), I added:

Code: Select all

    // NAKcache
    touch(S9Y_INCLUDE_PATH . "cache/flush"); // ensure rm -f works
    exec("rm -f " . S9Y_INCLUDE_PATH . "cache/*");
This way, any edits will flush the cache. (Without this, you have to wait 5 minutes for that spelling error to vanish.)

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Tue Apr 14, 2015 8:07 pm

Yes, that would be necessary. Good idea.

Do you maybe want to send something like that in a push-request, as a feature branch based on master? I can't promise we will merge it, and I think it should use something the cachesimple helper instead of doing the file management manually, but to be able to test it easily should certainly help with modifications like that.

I can imagine we could merge it as an option, not on by default. And maybe enhance it to cache forever till something changes on disk?

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Sun May 24, 2015 2:25 pm

I now tested this a bit more with a benchmark of the cache options we have. That benchmark was siege, s9y ran on localhost on the same PC (so not too professional). My PC has a SSD and should be more powerful than a shared hoster, but less so than a professional server. 15 entries on the frontpage, fresh s9y with sqlite. This is the result: https://docs.google.com/spreadsheets/d/ ... sp=sharing

Here is the chart extracted:
Image

My conclusion is that nealks approach is great. By circumventing s9y completely, the cpu stays without load even at the highest user level I can benchmark with siege. The response time is immediately.

When not having any cache enabled, s9y can hold up on my pc only till 200 concurrent users. At 300, there is a massive spike in response times. No failed transactions yet, which is good. But in total not good.

The entryproperties plugin helps quite a bit, but the load is still heavy

My printEntries-cache might be a good compromise. Not as nice results as the total cache, but nearer to that than to the entryporperties cache. What is missing in the chart and data is the cpu load, and that is still signifcant higher than with nealks apprach.


Let's discuss that. Maybe you want to do your own tests as well? I'd like to pick one of the two approaches and add them to github, either as feature branch or to master, so we can start implementing it properly:
  • The printEntries-cache needs further cache-invaldiation points, and we maybe want to use something other than cache_lite.
  • nealks code is just a prototype and needs a complete and proper implementation, and maybe cache invalidation points as well? That proper implementation could mean that we lose some of its advantage, since we need to get the proper paths, which means autodetection and database hits (for the config).
It might be even possible to have the two caches: One as an internal faster cached codepath, the other as an optional interval cache, converting s9y for that interval in something like a static webpage.

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Sun May 31, 2015 2:32 pm

Github-Issue, for the printEntries Cache I commited since: https://github.com/s9y/Serendipity/issues/345

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Sun Jul 26, 2015 5:33 pm

A gem in the index.php:

Code: Select all

if (isset($serendipity['pregenerate']) && $serendipity['pregenerate']) {
    $fp = fopen($serendipity['serendipityPath'] . PATH_ARCHIVES.'/' . $id, 'w');
    fwrite($fp, $data);
    fclose($fp);
}
If I see that right, there is already some code in the core to cache entries, to have them as a textfile under /archive and serve them via s9y without hitting the database. It seems broken though, as I can only find the code that would write those files, but none that would read it. Maybe that was not meant as a cache, but as a textfile mirror? Or it was how the entryproperties-cache worked once? Garvin?

User avatar
garvinhicking
Core Developer
Posts: 30015
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Re: Check caching for speed

Post by garvinhicking » Mon Jul 27, 2015 4:04 pm

Hey,

this is code from Serendipity 0.3 or 0.4 I think, that never was used and it was added before I joined the project, and I never analyzed what or if good it could do.

Best regards,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/

User avatar
onli
Regular
Posts: 2163
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Check caching for speed

Post by onli » Mon Jul 27, 2015 5:58 pm

Thanks for the response Garvin. I removed it in https://github.com/s9y/Serendipity/comm ... 8dd8458d34.

Post Reply