The drupal caching problem

Events happening in the community are now at Drupal community events on www.drupal.org.
joostpluijmers's picture

My name is Joost Pluijmers and working currently in order of Dynamic Solutions. I have been devoloping with and in Drupal for the past 4 years and never really got involved, thats something I would like to change.

Before we start I would like to set some kind of situational impression. Were gonna be talking about using Drupal use in a average Joe way, not in cluster configurations just one fysical machine running the webserver and database. The way small to medium buisnesses have and will configure their drupal websites in the future.

Now from what I have experienced in my use of drupal is that its extremely easy to install, has an abundance of free functionality in its huge repositry of available modules. But here in lies one of the greatest problems I have encountered and still encounter with Drupal. When using a combination of 20+ modules of wich the most important are the CCK and Views module drupal bootstrap will start to slow down substantialy.

Thats all perfectly fine because drupal comes with 2 modes of caching: normal and agressive. Use of the drupal caching system is sort of mandatory because without it the configuration described above will lead to page request times of 1+ seconds. Now normaly all the websites can use the normal cache and even aggresive cache sometimes. But when clients get used to Drupal they will want more dynamic content like polls, bocks displaying specific user information and other information/widgets changing on more specific criteria than a menu handle.

According to me the problem lies in the lack of depth in the caching system. Either a page gets cached or it doesn't. This for most of my cases is too spartan. Wicht leads to programming many basic modules specifying content types/pages that could have easely been implemented with cck and views. But when programming something myself I do get to control the cache.

What I propose is the following: I would like to add specific hooks to control the cache. These hooks will enable modules to optionaly implement a more specific caching system. The caching system will work based on object states. These can be block states, cck field states, page states the module developer gets the free hand in what to use the system for. The cache will be multilayered so even if a page with state [x] doesn't get cached the cck field with state [z] may still be loaded from cache within the current requests context.

I would like to discus the matter before I start. Would it be usefull for site admins to add more context criteria to when something gets cached yes/no. Would other programmers like this functionality when programming their modules?

Kind regards, Joost Pluijmers.

Comments

Don't reinvent the wheel

crea's picture

There are already lots of caching stuff that does granular caching of different blocks: block caching, panel caching, views caching, etc. It's just spread between many contrib modules. Only exception is block cache, which is in core.
When you properly cache stuff it's possible to get 200-300ms page generation time which is ok in most cases. Your users will more likely notice slow loading of images rather than this page generation time.

Its not that simple

joostpluijmers's picture

I know there are a lot of contrib caching modules available. But as I stated they either cache or do nothing at all. When using a CCK and Views setup with in example a pollfield an place that in a block on the homepage you can't use pagecaching or block caching. When does it need to cache the block? the drupal caches are reletively stupid, the granularity is limited to role or user selections. There are no other means to define in wich cases caching should take place without programming something yourself.

In my idea the module will be able to define(hooks) sertain states of the objects they deliver. Ie the pollfield would have 2 states: unvoted and voted. In the settings tab you will be able to define seperatly wich states get cached and by what criteria(in what context). The context filters are also defined by modules(hooks) ie. the user module could define/mediate the user/role based context but via the same api the cck_pollfield could provide other context templates like when a vote has been cast.

Thats more along the lines I was thinking. More depth, making it more extensible. You don't have to program the context templates over and over again only the way your module reacts to them.

I agree :)

Bensbury's picture

There are lots of great caching mods I agree, but I also agree with Joost.

I have ran into problem with making caching language aware (views) and had to learn to build a module just to enable it.
The other trouble I have with the cache is that none of them allow caching by theme.

So I have a site that switches between mobile and PC.
If I use a number of the caching modules with that my mobile users get served up PC pages and that's not cool in anyone's book.

So I use caching, and it does a fine job, but it doesn't allow me to get the caching I need, which is specific to certain states.

Having content cache aware would be awesome.

Cache by Role
Cache by Theme
Cache by Type
Cache by Path

etc.

I think Joost's module would be very valuable.

If this causes a big module Poo throw down, then maybe some of the other modules could get around to implementing the features..... or have Joost work with them to implement the feature and have their module rise to the cream of the crop.

Anyway, I would love to see a caching module that can do that.

Thanks bensbury

joostpluijmers's picture

Thanks for your reaction. "content aware caching" is a nice term for what Iam trying to achieve, but its also only one aspect of what would be ultimately possible when implementing these features.

As for wich modules I would like to support, those would be CCK, views, block and node as these modules will cover alot of the drupal websites in production. For those modules wishing to either leverage the caching system or provide context filters will have an api trough wich to do so.

Also theme context filters would be a great feature thanks for the suggestion.

Iam currently looking into the posibilities of the trigger/action system and if it can be leveraged to trigger the specific events.

I hope to get as much information from you(my fellow developers) before I start producing a workable proposal.

Thanks for the usefull reply, any other ideas/critism would be welcome.

Boost

mikeytown2's picture

You should check out boost & the ajax loading of content. It has a lot there.
http://drupal.org/project/boost

Can you give me a little more

Bensbury's picture

Can you give me a little more direction on that, because I have been boosting before and ran into the mobile switching problem.
What's the deal with the ajax stuff and is there a node or section I can learn it from?
Cheers.

Info

mikeytown2's picture

Ajax
http://drupal.org/node/583264#whoonline
http://drupal.org/node/657826

Look at boost's code for some ideas on cache expiration; it does a fairly good job ATM.

In terms of mobile stuff, make different subdomains for each phone; control where it goes via rules in htaccess.

Thanks, I'll check that

Bensbury's picture

Thanks,
I'll check that out.

As for the mobile, I can't do that.
The site has to sit in the same place. Making subdomains got vetoed :(

No Javascript

Bensbury's picture

Hi,

Sorry I was a bit fried when I read that and the nagging thought in my head was correct.
The problem is that Japanese mobile phones do not run Javascript across their networks and so ajax is useless.

Non-AJAX Boost?

raintonr's picture

I have to say, that I can completely see where Joost is coming from.

One only has to take 2 simple scenarios to show how limited caching is in Drupal:

  • A block somewhere on a page that should show random ads. These ads should rotate on every page refresh.
  • The random image block.

Now, even with the most basic level of cache turned on, the randomness of both the above is broken for users who are not logged in (which is the majority in just about any site). So for truly random content (without having to resort to AJAX and the like) one has to disable all caching!

I've read about Boost and while it sounds clever, I'm sorry, don't like it. Relying on a browser to perform one or more AJAX requests to fill a page seems silly when the server could integrate that dynamic content before returning the page.

IMHO a better approach would be that cached pages should include special markup. Something like "". The caching system can build pages and store this markup, and retrieve it as now. However, it should be fed through what I guess is a filter that would replace this markup with appropriate HTML (ads or images in the examples given above) before sending it out the door to the browser.

Can anyone comment on if/why they think this would be good or bad?

What you are basically

Jamie Holly's picture

What you are basically describing is ESI (Edge Side Includes) and usually handled by higher caching/accelerator apps such as Varnish.

There are a few problems with doing static caching + ajax. First is mobile devices. A lot don't support javascript, so it's useless there. Then you also get accessibility issues, where a lot of screen readers don't support Javascript. Also if you want the Ajax loaded content to be indexed by search engines then you are out of luck.

For ads, those are best handled by Javascript. When people are trying to squeeze out as much performance for their site as possible, I always suggest using an external ad server (Google Ad Manager, OpenX, etc.). A big performance problem with ads, especially rotating ones, is that you want to track the impressions, so you need a way to do that also. That's where an external ad server shines.

IMHO the best route would be to implement a pseudo ESI method. Pages are stored with actual ESI syntax, then a special page loader is called through .htaccess to assemble the pages. This would provide advanced caching to those who don't have the ability to install advanced caching/accelerator apps, but still remain compatible with those apps if they are available on a server.

Say you are doing a Digg style site with vote up/down. The full body of the page is cached with the ESI markup. Then where ever the vote widget appears you would have a tag appear:

<esi:include src="http://example.com/cache/votewidgets/11211.html" onerror="continue"/>

The page assembler sees that tag and loads in that html file, which is just the widget and injects it before serving the page back.


HollyIT - Grab the Netbeans Drupal Development Tool at GitHub.

Definitely some interesting

brianmercer's picture

Definitely some interesting work being done in the ESI area with Varnish (or SSI+memcache in nginx) to address these issues.

http://drupal.org/node/651902

http://drupal.org/node/634746

Thanks for the links. Very

crea's picture

Thanks for the links. Very interesting indeed.

Block cache override

raintonr's picture

Thanks for pointing ESI out. Yeah, so simple it had to have been done before.

So thinking about this what I'd like to see (not sure if this help the original poster though) is some sort of override-per-block. A config option for each block that, when checked, replaces the block content with an ESI tag. This ESI tag is then used to generate the dynamic content for this block before it's returned to the user.

Just to confuse matters, this is pretty much the opposite of block cache. As discussed however, it would allow the use of page caching where it could not otherwise be used, thus actually increasing overall site performance.

Does anyone know if this (or something like it) is being worked on in D7?

Thanks

RichieRich's picture

I never realised that Drupal wasn't clever enough to realise that randomly-generated block content shouldn't be cached. In fact, I suspected the opposite - that Drupal may fail to cache the entire page in such cases.

This is actually critical information for my site as I planned to offer randomly presented adverts. I've also just discovered that my randomly-generated image blocks don't work after signing out and checking.

Concerning, but good to know. Thanks.

There's work being done on that

gchaix's picture

I know there are several people in the Drupal community who are working on improving this. They're working on using things like Edge Side Includes (ESI) to push block content into an external cache like Varnish and work is being done in Views to make it and the blocks it generates better handle cache.

...

RichieRich's picture

So, does all this imply that when using Views new node which meets the query conditions will not be added to the page / block if caching is enabled? For example, in the case of the sightseeing spots list on my website would it be best to clear the cache every time I add a new 'sight' node. Here's the page:

http://www.ishigaki-japan.com/sights

Thanks in advance if you get the chance to have a quick look. - Rich

Perhaps you could run a

brianmercer's picture

Perhaps you could run a separate ad server on a subdomain and embed the ads in your static page.

Bite the bullet

raintonr's picture

I've recently had to bite the bullet and turn on caching. For random images and the like I figure the guest users will just have to live with it. For ads I switched them to Javascript as per other advice. It works but they are easily blocked. Mind you, the static ads are too so guess it's not so different.

I might yet write bit of Javascript code to flick the random images in the same way.

I don't really like this Javascript stuff, but that's the solution right now.

FWIW, I also moved from private to public files which had a large impact on the site speed.

Basic Question

webservant316's picture

I found this thread looking for an answer as to why my rotating image block (using views of a nodes with images) would not rotate the image for unauthenticated users. Sadly I see that Drupal cannot do that with cacheing enabled. I had page cache enabled and block cache disabled, but apprently one needs to disable both to get images to rotate in a block. That makes me sad.

My basic question is how does one go about writing a Javascript image rotator? Is there a module that does that or do I need to put javascript into a node somehow? Any code examples would be appreciated.

Also is this problem true of the Drupal built in blocks, such as 'Last Viewed'? So that my unauthenticated uses see the same 'Last Viewed' information with every page load?

Jeff

Blocks

mikeytown2's picture

You can now ajax load blocks easily with this module. Give it a try
http://drupal.org/project/ajaxify_regions

Block caching mode

kwinters's picture

Can you confirm that the block was set to the right caching mode? I don't have the code handy, but I think you have to look up the row in the database and compare against the constants in the core blocks code.

If the block was set to the default, which is once-per-role IIRC, then your problem may just be configuration.

Ken Winters

Views Slideshow module can do

dalin's picture

Views Slideshow module can do random images via JavaScript. Very easy to setup.

--


Dave Hansen-Lange
Director of Technical Strategy, Advomatic.com
Pronouns: he/him/his

@raintonr: You don't have to

crea's picture

@raintonr:
You don't have to completely disable anonymous page cache. You can do it only for pages where your dynamic block is showed. And as always, "there's a module for that" :)

Yes, Drupal lacks out-of-the-box granular caching. But that's not because Drupal is bad at this, but rather because granular cache invalidation in generic way is very hard. To effectively cache individual content pieces one would need to flush cache for these pieces. Then there's problem noone knows what your content pieces are, and how do you use them. Because of this, out-of-the box granular caching is not possible.

You can look at the Panels module. Using Panels, it's possible to divide pages into separate blocks, and cache these blocks differently and separately. Then it's possible to flush your caches, using context system. Context system of Panels furtunately is very useful for caching, because it answers simple but important for caching questions in generic way: "What is inside this block ? How does it depend on external data ?". Then, because you know the answers, you know relationship to the external data, and can track that external data, and propagate invalidation of cache using context system. That's what Advanced Panels Cache module does for node context.

Link to Advanced Panels Cache

jcchapster's picture

Link is broken above to Advanced Panels Cache. Missing "he" at end of url.

It is here: http://drupal.org/project/ap_cache

Everywhere

raintonr's picture

@crea... when you put ads and/or random images just about everywhere it's hardly worth the effort to figure out when not to cache pages.

I've seen the panels module but it's not useful when the dynamic bits of the pages you want to refresh on each load are in blocks on the side regions of the page.

@raintorn For ads, I

crea's picture

@raintorn
For ads, I recommend to use JS invocation. That way your pages are static and can be cached. Note that this is also recommended setup for OpenX advertisement engine. So I would say, nowadays it's industry standard to use JS for ads.

Panels work without regions too, now officially with "Panels Everywhere" module.

But then isn't a bit off that

Bensbury's picture

But then isn't a bit off that you are forced to use panels and context to build your site so you can have decent caching?

Wouldn't it be better to just have a caching module that works with what you build your site with?
Seems to me there is a genuine need for something like this.

You are not forced to use

crea's picture

You are not forced to use Panels. It's just Panels has infrastructure useful for granular caching. You can apply same logic in your custom module to blocks. If you managed to make such module everyone would be grateful. Just don't expect that it will be easy.

But isn't the point of the

Bensbury's picture

But isn't the point of the thread, that Joost wants to build a module to allow people to have granular caching from a new caching module?

Then it was said we don't need a custom module because there are already modules available.
But the current modules don't support circumstances for a number of people.

Then it was suggested that panels can be used to achieve this effect.
But that then means people have to use panels.

So then it appears that Joost should make the module, because if he doesn't people who want granular caching have to use panels to achieve it.

Using panels isn't a caching solution but a work around to get the functionality he thinks deserves a new caching module.

Therefore Joost is quite justified in going to build a new caching module.

You know, when you mix

crea's picture

You know, when you mix several conversations together you don't always end with logical result.

Thanks for the feedback so far.

joostpluijmers's picture

Before summing up all the comments I would like to point out that javascript on demand loading of content is outside the scope of what I am trying to achieve. Let me sum up what I would like to create:

A general cache control module responsible for:
- Handling knowledge of wich cachable objects and associated states exist. These may be defined by one or multiple hooks.
- Presenting a backend for the site administrator to define the context that will meet the criteria for when to clear the caches. In example: "Added new node for content type X" or "Vote cast on pollfield attatched to node".
- Center control for context aware caching. It will dispatch all context aware caching requests for it will hold all the information concerning the object(&states), the configured triggers and actions. It will match the object(state) being loaded against the provided contexts and handle approriatly.

A contrib module would be able to integrate this by:
- Defining ie: hook_[mymodulename]state(). In wich you could define all your objects you want to be configurable by the cache.
- Defining ie: hook
[mymodulename]_context(). Wich will allow you to define custom contexts for your module.
- Allowing perhaps different optional proccessors by the module for when the cache handling is too specific. This is just a tought.

Now what this project won't do:
- Handle cache backends, I would much rather like to see integration with the cache router project.

The goal of this project:
- Adding depth and granularity to the caching of whatever objects you would like to see cached.
- Easy to use hooks for the programmers since it will be designed to make their life's easier and removing redundant custom cache handling. Thus removing the need to otherwise develop custom modules that would have been achievable by combining others IE cck&views.
- A way for site administrators(non-programmers) to use this functionality provided by other modules to speed up their website.

Essential for the success of this project:
- This module will only create the general API + I will personaly integrate some frequent used modules like node,cck, and views (maybe later the block module too). But for this module to become a success it must become a everyday tool in the module developers workset. The point being is that I can't build all the context, so the more context modules will be build the more this module will grow.

High performance

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: