Archive for February 2011
Friday I was stuck in a day long platform architecture and infrastructure meeting and one topic brought up was caching. Someone asked “How will the caching work across the cluster?” to which I offhandedly replied “Probably either use terracotte or do it over JMS or AMQP or something.” Of course, ehcache doesn’t even have an AMQP based replication strategy. Till now.
Over the weekend I devoted a few hours to building a new plugin for ehcache, ehcache-amqpreplication. This basically builds off work already done on jmsreplication but uses AMQP as the protocol, which is WOLRDS simpler than JMS. Here’s an example configuration file:
This configuration just tells ehcache to use the amqp bases cache event listeners and cache peer providers. The properties attribute of both also take a comma separated listing of key value pairs that map directly onto rabbit-client’s ConnectionFactory object (meaning you can configure anything on it, logins, auth method, etc). Start up ehcache and now any ehcache put, remove, or removeAll operations will be replicated across amqp! Here’s a demo project I wrote that contains a simple REST service that performs prime factorization with a 3 second wait before returning results. Check it out and fire up two server instances.
gradle jettyRun -Pport=8080
gradle jettyRun -Pport=8090
Now navigate to one of them at http://localhost:8080/amqpreplication-demo/factor/3124. Do the same for port 8090. You should notice that on the second one there was no wait, ditto if you hit 8080 again. If you look at the console logs, you’ll see this for the first hit:
INFO PrimeFactorFinder - Finished computing prime factors for 3125
But not the second hit. The operation has been cached and replicated to the other server instance. I have also tried this across multiple boxes and it works. Woot!
For now this uses java’s bargain basement serialization, meaning you’ll have to implement Serializable for any objects you plan to cache. I plan on changing this in the future. I also have thought about possibly serializing to JSON using jackson. Just imagine the possibilities… a java cluster running ehcache and a php based cluster running memcache with the possibility of replicating objects between both! OMG!
Is It Production Ready?
Really depends on what you mean by production ready. This was cobbled together over a combined total of 10 hours over the weekend and there are several open issues. For the most part, it DOES work but with a few small caveats.
Publishers also receive a copy of their own messages they send out (resulting in an extra hit). I have also done no benchmarking tests whatsoever so it’s possible performance might even totally suck at them moment. I’m sure there are more minor issues lurking as well. In the future I’d like to make this work with objects that aren’t serializable but at the moment you’ll get an exception if you try to cache a non-serializable value. Feel free to try it out, but I’d wait for a non-snapshot release to use in production.
Thought I’d jot down some thoughts to adhere to during the week. Lately I’ve been a jerk and a disruptive team player, so some random thoughts about how to do better this week.
- Create space – don’t jump in and fill in pauses when people speak. Give them space to voice their opinion.
- Be open – have a relaxed expression and listen.
- Show interest – don’t roll eyes or stare off into space when others speak. This should really be adhered to even if the viewpoint boils my blood or bores me to death.
- Follow up discussions in private with those who my viewpoints might disagree with the most. Is there a common ground? Misunderstandings?
The first item has been a bit of a problem lately. I think it has to do with an anxiety I have from my introverted past… a meeting would take place in which I had expertise that could have been shared but other participants filled the space of the meeting completely, leaving me unable to participate in a meaningful way. Main focus is to ensure to give others space and listen but ensure that my own opinions are voiced and heard.
The key point to remember this week is that Respect is fundamental part of any team that wants to operate efficiently and to focus exclusively on respecting others as well as myself.
Another new feature released yesterday came in parallel with me tryingo ut some annotation based caching strategies. Caching Abstraction basically takes convention from an existing project and makes it part of spring core.
Essentially it introduces a new interface, CacheManager, which can be implemented by a specific cache implementation. From there it adds a few new annotations to make methods cacheable. Here’s an example using my previous posts objects.
Here you’ll notice that the finder method has a @Cachable annotation on it with a name that specifies the cache to store to. it can also use additional attributes, for example a key which uses an expression language to determine a key from the arguments that are passed in. The default is the value of all the method arguments. On the save method I use @CacheEvict to remove the cached element from the cache if it already exists.
This of course won’t work on it’s own, so you’ll have to enable it yourself (which is good… the last thing you need is to discover a production app caching things it shouldn’t be caching). Sadly as of the time of this writing I haven’t discovered how to do this in non-xml, so here is the spring xml file to enable it and use ehcache as the implementation.
The ehcache configuration:
And finally adding this to the AppConfiguration, which includes doing a simple @ImportResource.
When running this example there should be a log message for the first time the method is hit, then it is not seen the second time (since it is being pulled from the cache. This is definitely pretty awesome for implementing Memoization for methods that might just have some CPU intensive computations (but give the exact expected results given a set of of inputs). I’m excited about doing some more work in this area… I’ve done method level caching before (it’s common) but it is awesome to be able to use it without having to DIY.
Spring 3.1.0.M1 was just released yesterday with a slew of new features, but one of them is something I have been wanting for quite a long time. In Spring 2.5 the concept of component-scan was introduced to lessen the burden of XML configuration (thank God!). This allowed one to simply define a package to scan for components and beans annotated @Repository, @Component, @Service, or @Controller would automatically get registered in the application context.
Spring 3 took this a step further by allowing Java based configurations but with one small caveat: the java based configuration didn’t support component scan. The only way to use component scan from within java configuration would be to define an XML file with the component-scan related configuration in it and then do a @ImportResource(“classpath:whatever.xml”) in the Java config. Thankfully, as of yesterday this is no more and I will illustrate how to do it.
First off you’ll need to include spring 3.1.0.M1 from the milestone releases in your favorite build script. Here’s my gradle file:
Now let me quickly define the domain. It includes a simple domain type (Message) with a repository to look them up plus a little class that does something using the repository. Here they are:
And finally the java based configuration (taking advantage of @PostConstruct to “do something” on initialization versus having a main method doing work):
Pretty nifty. You can also include all the other usual features that component scan has (such as inclusion and exclusion filters) within the annotation. It is definitely refreshing to be able to retire the last piece of XML I was required to use in my spring enabled applications.
Recently I installed the RabbitMQ management plugin and ran into a couple problems so i thought I’d document how to fix this. The cause seems to be rooted in the fact that the erlang-base package uses an older version of erlang that has methods the plugin uses missing. The solution (at least for the time being) is to uninstall rabbitmq and erlang and reinstall it by hand.
First, install libncurses5-dev as it is needed to build erlang. Then go fetch the latest version of OTP from the erlang website. Unpack it and run
./configure && make && sudo make install
Once that is installed, go download the latest rabbitmq and install it. You can do this either by using agner or by building it yourself. Here’s the command I use to build it myself:
make && sudo make install SBIN_DIR=/usr/local/sbin MAN_DIR=/usr/local/man/ TARGET_DIR=/usr/local/lib/rabbitmq
Now download the files located on the plugin page and copy them to /usr/local/lib/rabbitmq/plugins. Start up that rabbitmq-server and if all goes well you’ll see no errors and you can access the admin console at http://server-name:55672/mgmt/. Have fun!