Chapter 12. Caching

Dynamic content distinguishes the web as an interactive medium, but dynamic content can also mean huge strains on web servers. Thankfully, caching can be used to relieve this stress by eliminating redundancies among the generation of identical response content. To this end, the Merb plugin merb-cache is included in the Merb stack and has been designed to simplify the common challenges of integrating caching in an application.

12.1 Configuration

Though caching is included within the Merb stack, you need to configure it to put it to use.

12.1.1 Fundamental stores

There are two fundamental cache stores, FileStore and MemcachedStore. You can use multiples of each of these stores in your application if necessary.

FileStore—an implementation of caching using files. It stores these files in the directory dir, which, if not specified, defaults to Merb.root_path(:tmp / :cache). File stores have the best performance for fragment and page caching but not for object caching.

MemcachedStore—an implementation of caching using memcached, a caching daemon used by nearly all the web’s largest sites. By virtue of its incredible versatility, memcached allows you to distribute caching across multiple servers and suits all forms of efficient caching. The two options namespace and servers accept a string for the memcached application namespace and an array for server addresses, respectively. The defaults of these two configuration options are nil and ["127.0.0.1:11211"].

To set up a cache store within Merb, you can pass a block of cache registrations into Merb::Cache. This is best done either in config/init.rb or through one of the environment files should you need to tailor caching to the environment.

image

Above we have set up a single-file store cache as well as a secondary memcached cache named memcached. Once registered, all data stores are accessible via Merb::Cache. Treated like an array, Merb::Cache by default retrieves the default store and otherwise pulls up the store we specify by name:

image

12.1.2 Strategy stores

Strategy stores are layered stores on top of the two fundemental stores. You can wrap them on top of both file and memcached stores or even on top of themselves.

ActionStore—stores responses for cached controller actions that may have responses conditioned upon request parameters

AdhocStore—wraps a list of multiple stores together using the first one that will work

GzipStore—gzips cached data and is thus suitable for large files

PageStore—sends out cached responses for simple actions, avoiding full controller dispatch

SHA1Store—hashes parameters to form a key for each cache and is best used when numerous parameters are involved

Below we wrap the stores we previously created with two of the strategy stores from above.

image

12.2 Caching basics

Merb application development does not typically involve getting your hands dirty with low-level caching methods. However, understanding how to get down to caching basics adds both breadth to your understanding of the plugin as well as a few essentials to your development arsenal. Therefore, let’s take a look at the basic methods used to interact with cache stores.

12.2.1 Writing

There are two methods related to writing data to a cache. These are writable? and write. The first checks to see if a particular cache key is writable or not. Between the two fundamental data stores, write makes a call to writable? in order to get the go-ahead to cache data. Therefore, as an application developer you need to be aware of only the method write. Here we use it to store a value into the cache store:

image

The first line is the easier of the two, simply setting data to be associated with a value. The second, however, has two extra method parameters, the first being a hash of additionally identifying parameters and the second being a condition that applies only to memcache stores.

In order to contrast the two methods and know how they work, let’s take a look at the two implementations of write, first for FileStore and second for MemcachedStore:

image

As previously mentioned, both make use of the writable? method, but the file store is more complicated. It creates a path for the file and then writes to it.

12.2.2 Reading

Reading, like writing, is handled by two methods, exists? and read. You may end up finding some use for exists? as an application developer, but for the most part read is sufficient since the first thing it does is seek the approval of exists?.

image

Above we have pulled the data that we previously persisted in the two data stores.

image

Note that the read method of FileStore uses exists?, as opposed to Data-Store#read, which rescues not-found errors, ignoring them and returning nil.

12.2.3 Fetching

The fetching of records is essentially shorthand for the retrieval or otherwise writing of a cached value. Below we use a block to return the potential value of a cache element that may not exist.

image

The fetch methods for both of the fundamental stores is the same:

image

In its highly condensed statement, fetch reads from or otherwise attempts to write to a cached element.

12.2.4 Deleting

You can delete cached data using the method delete and passing in the cached element key along with any identifying parameters needed. Observe that the code behind the delete method differs between the two fundamentals, but no more than we’ve seen before:

image

12.3 Caching helpers

Various helpers exist to ease the use of caching away from the primitive methods we have so far seen. We’ll take a glimpse at all of these in this section.

12.3.1 Action caching

In order to better facilitate the page and action stores, a number of methods are mixed into controllers at both an instance and a class level. The simpliest of these is cache!, which caches all actions. Alternatively, the method cache accepts a list of actions to cache. More precisely, we can specify that a particular action should be cached only under certain conditions with cache_action:

image

All of these work by adding in before filters:

image

Do note that the position of the cache class methods can have an effect on the ultimate request, since they may be part of a complex filter chain. Authentication filters, for instance, should certainly appear above cache method lines.

12.3.2 Eager caching

A variant of action caching that is better suited for pages where the most current information is mildly less important than the speed of the response is eager caching. Making use of after filters instead of before filters, eager caching updates stale versions of the cache based upon the evoking of a triggering action. It does so in a run_later block after the triggering action is evoked, making eager caching perfect for actions with expensively constructed responses. However, that’s the only problem eager caching solves, since it also effectively marks as stale all old caches. This versatility can be seen in the example below, where we employ the method eager_cache.

image

The two methods build_url and build_request are helper methods used by the eager_cache method to construct URLs and internally dispatch requests, respectively. In the first case above we don’t pass in a block and let eager_cache do its own magic. The second is more explicit.

Here’s the code that sets up the after filters:

image

But far more interestingly, here’s the code that dispatches the eager requests to be cached. Pay special attention to the variety of forms in which requests can be created.

image

12.3.3 Fragment caching

Fragment caching through the method fetch_fragment allows application developers to store small sections of a view template. This is perfect if only a region of a template needs caching.

image

Looking into the source, we see how it magically identifies fragments by file and line number:

image

12.3.4 Partial caching

The method fetch_partial can act as a replacement for partial when the partial needs to be cached. As we saw with fetch, the cached element is generally either read or otherwise written. However, unlike fetch, the fact that we’re referring to a template means there is no need for passing in a block.

fetch_partial 'users/stats', :user => @user

Here’s the source behind fetch_partial; note how it takes a possible third parameter of conditions that will be passed along to the actual fetch method.

image

12.4 Conclusion

Caching in Merb can be handled in a number of ways. The best ways, however, are those that interfere the least with application code. The code behind action and eager caching exhibits the Merb controller’s ease in layering these mechanisms. Our look at the various caching stores available within Merb should make it clear that no one storage mechanism fits all, and that caching must make sense for the particular data being cached. Nonetheless, the caching store strategies provide a number of extensions on the abstract stores and when needed can be used to create composite user-defined stores as well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.255.250