|
From: Rob B. <rob...@ve...> - 2003-09-10 15:18:08
|
Hello all,
In Rod's book he mentions that when your application is deployed in a cluster that you should hold multiple small objects in session instead of one large monolithic object graph. The reason for this is that the app servers can reduce the amount of data that is replicated for failover by only needing replicate the objects that have changed instead of the entire object graph.
Generally appservers have an optimization where you can specify that only objects that are "added" or "re-added" to a session be replicated. i.e. You inform the app server that your object's data/state has changed by adding it to session, even if it is already held in session. By adding it to session with the same name, the original reference is over-written, so only one copy is held in session. You do the "re-add" specifically to tell the appserver that data has changed in this object, and it's data/state needs to be re-transmitted to the other servers.
It is the developers responsiblity to "inform" the app server by "re-adding" the object to session. If the developers forgets to do so, the app will still work fine most of the time. However, when the app does need to failover to the other server you will now run into a problem because the objects data/state modifications did not get replicated. Policies, code reviews, etc. can all reduce the chances that someone forgets to "re-add" an object to session after modification, but it is still a very simple / easy thing to miss.
How about adding a feature to the spring MVC framework to take care of this automatically. The "Dirty Marker" pattern can be very helpful here.
Implement an interface:
public interface DirtyMarker {
public static final int NEW = 0;
public static final int DIRTY = 1;
public static final int CLEAN = 2;
/**
* Returns the dirt state of the object.
* @return int - dirt state of object
*/
int getDirtState();
/**
* Sets the dirt state of the object
* @param newState - the new dirt state to set
*/
void setDirtState(int newState);
}
I would recommend implementing the interface like this instead of using isNew() isClean() isDirty() because it allows the use of switch/case blocks.
Have any object that you are going to put in session implement this interface. Your object should have all of it's setter methods call
setDirtState(DIRTY).
Add code to the spring framework so that after the presentation logic implementation is finished it will:
1) loop through all the objects in session
2) check if the object implements DirtyMarker
3) if the object implements DirtyMarker{
switch(getDirtState()){
case NEW: setDirtState(CLEAN); // if NEW, set to CLEAN.
break;
case DIRTY: setDirtState(CLEAN);
// set dirtState clean before replication
// so it is clean on failover machine
// this prevents a replication storm
// if failover does happen.
then "re-add" to session
break;
}
}
In this way the framework will track if the object should be "re-added" to the session to take advantage of the replication optimization.
Of course, if the object in session has a child object, and you only update the child object, this will not work. However, you could handle this in design. Either by design, your objects that get put into session have no child objects, or a parent object can recursively call getDirtState on its child objects from getDirtState. (Do the same for setDirtState) If anyone returns DIRTY then the parent should return DIRTY. (Of course, if you are following Rod's advice, these parent-child object graphs will be small, or non-existant).
If you need to put an object into session that does not implement dirty marker, then it's ok, because the framework will check for the interface first and do nothing if the object does not implement the interface. You can then choose to not use the framework and have to remember to "re-add" the object yourself. OR, you can use the Decorator pattern to wrap that object inside your own that does implement DirtyMarker.
The one big negative of this approach is that when you first add an object to session it will get transmitted for replication twice. The first time when you manually add it to session, and the second time when the framework re-adds it to session for you automatically. You could avoid this by manually setting the object to CLEAN before adding it to session (NEVER DO IT AFTER! This can cause replication storms on failover). If you forget to set the object to clean, you take the performance hit of replicating twice, when the object is first added to session, but your failover will still work properly. Even if you set the object to clean AFTER you add it to session, you may pay a performance hit of a replication storm, but the failover will work!
I haven't yet finished Rod's book (work/life keeps me to busy to read as much as I would like during the day), so I don't know if the framework already does this. Just thought it would be a good feature.
Also, the DirtyMarker interface is not tied to the web tier so it could be used in command objects too without tying them to the web tier.
What do you think?
Later
Rob
|