Sunday, 17 October 2010
Reducing backend load
So far they look promising; being able to run Zeus on your own generic hardware could be a cost saving in the long run. For example we had to buy some spare PSUs out of fear we wouldn't be able to buy them in the future.
One feature I really like the sound of is the "webcache!refresh_time". It smooths out the load to your backend by only sending one request to your appserver while serving the rest from cache. For sites that must have low cache times this makes a lot of sense. If you get 30 requests per second for an item, you only send one request to your backend as it expires from cache.
Turns out F5 also have a similar sounding feature called Fast Cache but for us it would be an additional module (read additional cost).
If anyone has experience with either I'd love to hear their thoughts.
Tuesday, 30 December 2008
Invalidating Single Cached Items
Sometimes we need to remove content from our CMS which means our app servers will serve up 404s for those requests. But we found that our F5 kept serving content from its stand-in cache for another 24 hours after the max-age had expired. We thought the stand-in cache was only there for when all the nodes in your pool had died so it looks like it's doing a little more than that.
Anyway, sometimes when we remove stuff from 'live' we really want it gone so we searched around and found that you can remove a single item from the F5 cache using a SOAP request to the management interface. The bad news is that you have to provide usernames and passwords in the clear but there's a nice way to get the same effect using invalidation triggers. At the back of Chapter 11 in the Policy Management Guide there's a straightforward example of what to do.
Thursday, 11 December 2008
Caching Grails Services
I've been plugging away for a few days on adding caching to Grails services. At first I tried to go down the road of decorating the services' metaClasses but since Grails uses an AOP proxy to add transactional behaviour to services this wouldn't work - the metaClass I got from the injected service object was not the same one my plugin had added stuff to. Also annotations on the service class were unavailable from the proxy.
The Spring Modules project has a nice caching implementation that uses annotations to decorate methods with caching and flushing behaviour. Getting this to work with Grails, was reasonably straightforward. As it turns out one additional config line made the difference between the spring-modules example config and something that worked in Grails.
I based the config on the annotation example from the Spring Modules documentation, converting the Spring XML to Grails BeanBuilder format:
import org.springframework.aop.framework.autoproxy.*The vital bit is the
import org.springmodules.cache.annotations.*
import org.springmodules.cache.interceptor.caching.*
import org.springmodules.cache.interceptor.flush.*
def doWithSpring = {
// declaration of cacheManager and cacheProviderFacade omitted - implementation specific
autoproxy(DefaultAdvisorAutoProxyCreator) {
proxyTargetClass = true
}
cachingAttributeSource(AnnotationCachingAttributeSource)
cachingInterceptor(MetadataCachingInterceptor) {
cacheProviderFacade = ref("cacheProviderFacade")
cachingAttributeSource = ref("cachingAttributeSource")
def props = new Properties()
props.myCachingModel = 'cacheName=MY_CACHE_NAME'
cachingModels = props
}
cachingAttributeSourceAdvisor(CachingAttributeSourceAdvisor, ref("cachingInterceptor"))
flushingAttributeSource(AnnotationFlushingAttributeSource)
flushingInterceptor(MetadataFlushingInterceptor) {
cacheProviderFacade = ref("cacheProviderFacade")
flushingAttributeSource = ref("flushingAttributeSource")
def props = new Properties()
props.myFlushingModel = 'cacheNames=MY_CACHE_NAME'
flushingModels = props
}
flushingAttributeSourceAdvisor(FlushingAttributeSourceAdvisor, ref("flushingInterceptor"))
}
proxyTargetClass = true
on the autoproxy bean. I won't pretend to understand what that's doing - I just noticed that's how ServicesGrailsPlugin
was getting the transactional proxies to work.After that it's a simple case of annotating service methods (in fact methods on any Spring-managed bean but services are the obvious use case).
import org.springmodules.cache.annotations.*This works fine on transactional and non-transactional Grails services. You can see the cache operations by setting
@Cacheable(modelId = "myCachingModel")
def getSomethingInAnExpensiveWay(param1, param2) {
// ...
}
@CacheFlush(modelId = "myFlushingModel")
def updateSomething(param1, param2) {
// ...
}
log4j.logger.org.springmodules.cache = "trace"
.The actual caching implementation used can be anything - spring-modules supports ehcache, oscache, JBoss cache, JCS, etc. All that's required is to wire in the cacheManager and cacheProviderFacade beans as described in the Spring Modules documentation.
I've bundled the results up as a Grails plugin (grails install-plugin springcache
). It uses a ConcurrentHashMap
backed simple cache implementation by default but wiring in ehcache or oscache is easy.
Caching and flushing models are configured in Config.groovy, e.g.:
springcache {Particular caching implementations may have further options or require additional external config (such as ehcache's
cachingModels {
cachingModel1 = 'cacheName=CACHE_1'
cachingModel2 = 'cacheName=CACHE_2'
}
flushingModels {
flushingModel1 = 'cacheNames=CACHE_1,CACHE_2'
}
}
ehcache.xml
file).To disable the plugin you can set springcache.disabled=true
. For example, it may be desirable to disable the plugin in the test environment.
Edit: Documentation added on grails.org