Tuesday, August 18, 2009

Welcome EHCache Community

I'm excited to be welcoming Greg Luck and the EHCache community to the Terracotta family. EHCache is an extremely useful/usable product and nearly ubiquitous in the caching space. Greg has spent years solving the important real world problems associated with building highly performant applications. The Terracotta Dev team is very much looking forward to helping accelerate EHCache's development as well as provide the best possible integration with the Terracotta product family.

EHCache will remain under the Apache 2 license and we have created the beginnings of a new website at www.ehcache.org. Greg will continue to drive EHCache's vision and direction, as well as being highly involved in it's development. He will also be instrumental in helping Terracotta to define and build out our caching strategy as a whole. His vision, as well as the EHCache community's help are essential in allowing us to together take these products to the next level.

We see a great future of product offerings for your desktop app, on your servers and in your cloud solving the scale/performance problems of today, tomorrow and beyond.

Wednesday, August 12, 2009

Distributed Data Structures: ConcurrentDistributedMap

Concurrent Distributed Data Structures?

Many challenges exist when developing a high scale multi-node application. Our goal at Terracotta is to take on those challenges in ways that remove them from the plate of those architecting and developing applications and place them squarely on our shoulders.

In order to accomplish such a lofty goal we first had to create some core pieces of infrastructure on which many higher order abstractions could be built. One such "piece" is our ConcurrentDistributedMap. This data structure is a fundemental piece of our Distributed Cache, our Hibernate product and our Web Sessions product and is also available for use in custom solutions for those using Terracotta as a platform.


Challenges and Tradeoffs

Developing a data structure that is Distributed as well as Concurrent and Coherent has very different trade-offs from developing for a single JVM. If one took a standard concurrent data structure like ConcurrentHashMap and just clustered it "as is" one would likely run into performance and memory efficiency issues. Even a really cool concurrent data structure like Cliff Click's Non Blocking Hash Map would not do well if one used the algorithms without thought in a coherent cluster.

The challenge is that the trade-offs change when you add the latency of a network and data locality in the middle of the game. In normal concurrent data structures you care about:

- How long you hold locks
- How much is locked while you hold it.
- CPU usage
- Memory Usage and Object creation

In the clustered case you add the following:

Lock locality - Is the lock you need already held on the local machine or do you need to go get it over the network. If you need to go get it how long does that take. While a little of the question of "How long does it take to get the lock" exists on a multi-cpu single machine it's not nearly to the same degree.

Data locality - Is the data I need already local or do I need to go get it. If I need to get it how long does that take

Data change rate - How much clustered data am I changing and how long does it take to send it around? Also, do I send it around?

Data size - In a clustered world one often uses data structures that don't fit entirely in a single node. One has to take pains to control the size and amount of the data in each JVM for efficiency.

There are other implementation specific/point in time issues like number of locks and their cost but those can mostly be optimized away at the platform level.


Single JVM ConcurrentHashMap

ConcurrentHashMap adds concurrency by collecting groups of entries into segments. Those segments are grouped together both from a lock perspective, they share a lock, and from a physical space perspective, all entries in a segment are generally in one collection. In a single JVM the only risk of sharing a lock between the entries is that one can contend on the in-memory speed look-ups. This is a very effective way to handle large numbers of threads making highly contended gets and puts to the map. If one runs into contention with this kind of data structures one can just up the number of segments in the Map.


Concurrent Map In A Clustered World

In a clustered world problems occur with a data structure like this. First, getting a lock or an object can be either in-memory speed or take many times in-memory speed depending on whether it has recently been accessed locally. In some cases this is no problem and in some cases it's pretty bad. It's also a space issue. If a segment is brought in as a whole and it's entries are in that segment strictly because of it's hashCode then the natural partitioning of the app's usage won't help save space by only loading the entries needed locally. Instead it will load the needed objects and anything else in it's segments. This elimenates the benefits of any natural or forced locality that occurs in a multi-node application.


Use-Case Analysis

In order to highlight some of the pro's and con's of CHM (ConcurrentHashMap) I'm going to vet it against a few use-cases.

Use-case 1 - An 8 node app sharing a clustered ConcurrentHashMap

All the data in the map is read only and it's used in all nodes evenly and the data fits entirely in a single JVM's heap.

GOOD NEWS! you will be fine with a regular clustered ConcurrentHashMap. Lets look at why.

1) All data will be loaded everywhere so unnecessary faulting (the act of pulling a data item into a node) won't be happening
2) All locks will be read locks and will be local everywhere so your latency will be nice and low (Due to greedy locks)
3) Won't have contention on the segments because reads are pretty much concurrent

Use-case 2 - The same as use-case 1 but now the map data is bigger than memory and you have a sticky load balancer.

Some good and some bad:

1) Since data is batched into segments by hash code and your load balancer hashes on something completely different than your map hashes on you will end up loading data into each node that is not needed. This is a result of the ConcurrentHashMap segmenting strategy.

2) Locks will still be fine because it's all read and read locks are very concurrent so segment contention won't be an issue.

So the memory manager may be doing unnecessary work and whether you will be in trouble depends on how big the ConcurrentHashMap is

Use-case 3 - Same as use-case 2 with the exception that now we are doing 50 percent writes. Something similar to caching conversations.

1) Still have the above problem of loading unneeded batches
2) But now, due to the writes, you are also maintaining the state of the objects that have unnecessarily poor locality in all the nodes where they don't belong.
3) Now you have a locking problem. While writing an entry to a segment you are blocking people in other nodes from reading or writing to that segment adding some serious latency. Plus the locks are getting pulled around to different nodes because even though your load balancer provides locality it is on a different dimension that of the internals of the map and is therefore not helpful.

Reviewing the problems highlighted by use case 3:

- Lock hopping leading to slow lock retrieval
- Lock contention due to grouping of multiple unrelated entries with locks.
- Faulting and Memory wasting due to unfortunate segmenting of data
- Broadcasting of changes or invalidations to nodes that shouldn't care


What did we do?

We built a specialty highly concurrent map tuned for distribution and the above challenges call ConcurrentDistributedMap.


Locking:
Instead of breaking things down into segments for locking we lock on the individual keys in the map. This gives the same correctness guarantees while giving the maximum concurrency. This drastically reduces lock hopping and contention and provides in-memory lock speeds most of the time.


Segmenting:
The segments go away completely. Key Value pairs are managed on an individual basis so no unnecessary faulting occurs.


Broadcasting and invalidation:
The above, plus an efficient memory manager means that values are only faulted into nodes where they are used. Since those values aren't in all nodes anymore invalidation and or broadcasting of changes for those entries is no longer needed.

This data structure takes excellent advantage of any natural partitioning that may occur at the application level.


Summary

Building a fast, coherent, concurrent, distributed data-structure requires thinking about an extended set of concerns. However, if one pays attention to the issues it is possible to create a highly useful solution. To learn more check out the ConcurrentDistributedMap described above.


Additional Reading:




For more information on Terracotta's distributed data structures one can always look here:


Friday, February 6, 2009

Maven Is Cooler than you think...

I'm sure I'm not the only one who has heard people curse Maven. But Maven is cooler than you think. Back in the day when I wanted to start a project I always had to get a whole bunch of gunk setup before I even wrote a line of code. Especially when trying a new framework or tool. Today I was whipping up a new project for a simple micro-benchmark on some Terracotta stuff and it reminded me why Maven really can be quite awesome. It took me 10 minutes and about 7 steps. The next time around I won't need to do the installs and then it's 4 steps.

These were the steps I took to get started:

1) Install Maven 

2) Used the Pojo Archetype to create the build and test environment for my project.
- Creates a Mavenized directory structure ready for build, test, run etc. Hooks up to Terracotta maven plugin as well.
- make sure you replace the group id and project id in the command line.

updated - with the latest eclipse plugin this is unnecessary
X 3) In my new project directory type: "mvn eclispe:m2eclipse"
- This takes your Maven project and readies it for eclipse

4) Install the Maven Eclipse Plugin (I already had eclipse installed)
- Makes dealing with Maven from eclipse much easier

- Makes dealing with Terracotta from eclipse much easier

6) File-> Import-> Maven projects and import your project into eclipse
- Loads up the project directory created from the archetype into Eclipse
7) Select the project and hit Terracotta->Add Terracotta Nature

What you end up with here is a complete project setup ready to be built and tested from both Eclipse and the command line using Maven.

Literally took me about 10 minutes to get started. Notice what you didn't have to do.

1) Didn't have to build a pom.xml or other kind of build file
2) Didn't have to download or install Terracotta or any of it's pieces
3) Didn't have to think about your directory structures, where you want to put your tests, how you want to run those tests
4) Didn't have to figure out how to do all this stuff in Eclipse or the commandline

Sure, Maven can be challenging at times, but in cases like this, when the vendors have things setup for you, it can be a huge time saver.

update:
Looks like we've reduced the number of steps to 6 the first time and 3 after that. If we take the guy's idea about auto-applying the Terracotta Nature in archetype we could reduce it to 5 and 2.

Monday, November 10, 2008

Web 2.0 Scaled Out Reference App...

It has struck me that not many good, scaled out, start to finish, Open Source Java reference applications exist for developers to learn from. Something that can demonstrate a modern and diverse stack of software handling large amounts of users.

Well check out the Examinator Web Reference App. It's goal is to demonstrate and document everything from "Build and test" to "Deployment" for a high scale, realistic, web application. It strives to be well written and as simple as possible while still being a good demonstration of best practices. It also strives to document all the relivant pieces so others can learn from it. This is quite a challenge and I'm sure dissagreement will exist on some of the choices. I think it's an excellent start and the right set of goals.

Here is a taste of the stack and tools:
  • Spring Webflow
  • Spring MVC
  • Sitemesh
  • Spring
  • Spring Security
  • Freemarker
  • Terracotta
  • JPA
  • Hibernate
  • Apache DBCP
  • MySQL
  • Apache mod_proxy
  • Tomcat
  • Jetty
  • Maven
  • Eclipse (+WTP)
  • Cargo
  • JUnit
  • HttpUnit
  • Selenium
  • Crosscheck
Click here to learn more about the choices and why they were made.

It's pretty good now and I'm pretty sure it's going to get better and better over time so check in early and often. I hope others can learn as much from reading about it and hacking on it as we did writing it.


Wednesday, September 24, 2008

JVM Wish List

I'm sitting at the JVM Summit at Sun for the next few days. It is an interesting group of about 80 people mostly represented by language implementers who target the JVM. Then their are these two guys (me and tim) who work on clustering of the JVM. Seems that our wish list for improvements to the JVM is a bit different than what others here are looking for. I asked one of the speakers about the proxify stuff below and he shot me down like I was Dick Cheney's pal on a quail hunt. Anyway, what the heck, here's my list.

Proxify - In Terracotta we dynamically swap objects in and out of the JVM and back to a server in order to create a Virtual Heap. We do this in a way that maintains Object Identity. We rely on a bevy of tricks to do this but it would be much more efficient if we could point to an object (or more than one object) and say proxify (or if a become: call existed we could use that as well, see Smalltalk for more info). All references to the original object would now be pointing to a light weight proxy. If someone touches the thing we would then inflate it back to being a full fledged object.

Array Instrumentation - Currently we instrument arrays in java by instrumenting the classes that reference the array. This is a bit messy and expensive and forces us to instrument classes that we might not otherwise need to. It also forces us to do more magic than I like to associate a shadow object with the array. Would be great if we could make this go away.

Native Method Replacement - When we want to muck with things like System.arraycopy we can't just wrap and replace because native methods get unhappy with that approach. So we have to replace at the caller. Would be nice if we didn't have to do that as much like arrays this is messy and forces us to instrument extra classes.

JVM support for meta-level monitoring of objects and code - This is not a new idea but it would be simpler and more efficient if we could ask the jvm to callback on us when things like field changes, lock acquires, field accesses occur on objects we care about. Would also be cool if we could associate meta-data with an instance (shadow objects) and ask for stats on a live instance (for our memory manager to make really good decisions on when to proxify). We do all these things now but they are complicated and more expensive then they need to be because we do them at the JRE level.

Good Hot swapping - If we can't have any of the above, good Hot swapping would also make things easier. We could decide what to instrument on the fly to simplify config a little bit and it would enable some optimizations that are very difficult to do now.

Solve the Int Size Problem - Currently arrays and all collections in Java are sized by an integer. As JVM's go more and more 64bit and people start creating collections larger than a couple billion in size it sure would be nice if they didn't bump up against this limitation.

That's it, my quick and dirty brainstormed wish list. Maybe some JVM fairy God Mother will some day grant me three wishes and bring some of these to reality.




Thursday, April 24, 2008

More Advice To A Young Developer...

I read Alex Miller's blog post on "Advice To A Young Developer" and it got me thinking. What general advice would I give to young developers. I came up with a few things. Hopefully they will help somebody.



1) Become your best by NOT being the best - This may seem obvious but the best way to be your best is to put your self in positions where your surrounded by people who are better than you on at least one dimension. This leads to point number 2.



2) Listen more than you talk - Use a bit of insecurity and a bit of wanting to be the best to drive you to suck the knowledge and experience from the people around you. Even the people you may view as less than you on some dimension or another will still teach you things if you listen. While your talking you are NOT listening.



3) Be Stupid, Stupid! - Sometimes being smart is a smart person's worst enemy. Don't ever use your intelligence as a crutch. Do research, talk to people, listen to people, read code, read books. In short allow yourself to evolve or risk not knowing how bad you are at things that you could have been great at. Watch out if you find yourself doing things from first principles all the time.



4) Slow Down - Of course a developer should work ones ass off. Almost all of the good ones do. But allow yourself time to think. Step back and look at what you are doing. In software it is very easy to rat hole on the wrong thing so take brakes, think, and get back to it. No more than 50 percent of your time should be spent typing (I actually think for an experienced dev it should be more like 25 percent).



5) Be A Tester - This is really for all Software Engineers, but... Be a tester, learn to write great automated tests that exercise at the unit, component, and system level. NOTE: This doesn't mean write tons and tons of tests. It means learn to write good ones.



6) Read your code - Software is complicated. Go back and read your code. You'll find all kinds of interesting things



7) Refactor - Refactor your code for readability, testability and maintainability. A myth exists that doing something in a messy poorly organized way is somehow quicker than doing it in a clean way. This is flat out untrue. I've actually timed myself. It takes longer to do things poorly. You are not saving any time by leaving bad code around. If it's a state machine write it as a clean well factored state machine. If you see a ton of nested if's extract methods, use null objects, what ever is needed.



8) Don't Guess - I first started with don't pre-optimize but I figured I would go one step further. Don't Guess! Write tests to show a perf problem before fixing them, don't guess about what features will be needed in the future, don't guess about whether your change fixes a bug. PROVE IT!



9) Trust Me - If you find yourself trying to win an argument by saying "trust me, I've done this or that before", or "I just know" then STOP. If you can't explain your point then you probably don't really have one so either figure out what the point really is or just admit your wrong.



10) Wishful thinking - Any decent list always has 10 items in it right? Anyway program by wishful thinking. Keeps you focused.



Hope someone can find some benefit from it.



Anyone else have ideas?

Thursday, January 24, 2008

Why I love and hate statics in Java

I was chatting with some fellow geeks earlier this evening and it occurred to me that I've said to people that they should almost ALWAYS use static and also told people they should almost NEVER use static. Am I schizophrenic, a hypocrite, or just dumb. Maybe all three but it has nothing to do with this blog. I'm talking about two different language usages of the static reserved word.

USAGE 1, where the love is:
Inner classes. I hate non-static inner classes. IMHO non-static inner-class is unnecessary syntactic sugar that leads to hard to read code and subtle bugs. For those who don't know, non-static inner classes maintain a hidden instance variable holding a parent instance. It then uses specially generated methods to give access to the parent's private fields and auto-magically calls methods on the parent if no local method of the used name exists. I've seen this lead to memory leaks (people passing around instances of inner classes and not realizing that they are keeping around parents), all kinds of confusing issues with methods of the same name in inner and outer classes and variable problems of the like. On the occasions I use inner classes I almost always go with the static kind.

USAGE 2, no love here:
Static variables. With the exception of constants I have a strong dislike of static variables. Why you ask? When used to create various versions of singletons it leads to messy hidden code dependencies . It also makes it hard to do mock object stuff for testing, creates hidden initialization stuff and makes it difficult to create multiple environments in a single JVM. Just darn inflexible for no gain. I would go into details but this has been covered quite nicely here

Anyway, in summary, STATIC inner classes good, STATIC variables bad.
Goodnight ...