<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;C0QNQXg_eyp7ImA9WxBWEU4.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308</id><updated>2010-02-02T09:23:10.643-08:00</updated><title>Grid Designer's Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.griddynamics.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Grid Dynamics</name><uri>http://www.blogger.com/profile/18125799569183836823</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/griddynamics" /><feedburner:info uri="griddynamics" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;CEcAR3w-fyp7ImA9WxBQGEU.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1485479515011646318</id><published>2010-01-06T23:01:00.000-08:00</published><updated>2010-01-18T22:20:46.257-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-18T22:20:46.257-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="capacity" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Java tricks, reducing memory consumption</title><content type="html">In this blog post, I want to discuss optimization of java memory usage.  The Sun JDK has two simple-but-powerful tools for memory profiling -- jmap and jhat.&lt;br /&gt;
&lt;br /&gt;
jmap has two important capabilities for memory profiling.  It can:&lt;br /&gt;
• create a heap dump file for any live java process&lt;br /&gt;
• show a heap distribution histogram&lt;br /&gt;
&lt;br /&gt;
Neither of these capabilities requires any special parameters for the Java virtual machine (JVM).  Below is a heap distribution histogram produced by jmap.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: xx-small;"&gt;&amp;gt;jmap -histo:live 16608&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: xx-small;"&gt;num #instances #bytes class name&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: xx-small;"&gt;----------------------------------------------&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: xx-small;"&gt;1: 464773 45411544 [C&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;2: 148131 22404200 &lt;/span&gt;&lt;constmethodklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
3: 21461 13197200 [S&lt;br /&gt;
4: 148131 11862064 &lt;/span&gt;&lt;methodklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
5: 231304 11562840 &lt;/span&gt;&lt;symbolklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
6: 448533 10764792 java.lang.String&lt;br /&gt;
7: 14801 9520800 &lt;/span&gt;&lt;constantpoolklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
8: 14801 6706536 &lt;/span&gt;&lt;instanceklassklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
9: 20178 6060872 [B&lt;br /&gt;
10: 250951 6022824 java.util.HashMap$Entry&lt;br /&gt;
11: 12530 5532096 &lt;/span&gt;&lt;constantpoolcacheklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
12: 26538 4437384 [Ljava.util.HashMap$Entry;&lt;br /&gt;
13: 54179 4381328 [I&lt;br /&gt;
14: 73294 3939656 [Ljava.lang.Object;&lt;br /&gt;
15: 34872 3905664 org.eclipse.swt.graphics.TextLayout$StyleItem&lt;br /&gt;
16: 27360 1551928 [Ljava.lang.String;&lt;br /&gt;
17: 16056 1541376 java.lang.Class&lt;br /&gt;
18: 20222 1294208 org.eclipse.core.internal.resources.ResourceInfo&lt;br /&gt;
19: 47006 1128144 java.util.ArrayList&lt;br /&gt;
20: 25235 1009400 java.util.HashMap&lt;br /&gt;
21: 22911 983784 [[I&lt;br /&gt;
22: 13398 857472 org.eclipse.swt.custom.StyleRange&lt;br /&gt;
23: 14362 831832 [[C&lt;br /&gt;
24: 16264 780672 org.eclipse.ui.internal.handlers.HandlerActivation&lt;br /&gt;
25: 36992 591872 org.eclipse.ui.internal.handlers.LegacyHandlerListenerWrapper&lt;br /&gt;
26: 423 591304 [Lorg.eclipse.swt.custom.StyleRange;&lt;br /&gt;
27: 13427 537080 org.eclipse.jface.text.TreeLineTracker$Node&lt;br /&gt;
28: 20254 486096 org.eclipse.core.internal.dtree.DataTreeNode&lt;br /&gt;
29: 19700 472800 org.eclipse.swt.internal.win32.SCRIPT_ANALYSIS&lt;br /&gt;
30: 19700 472800 org.eclipse.swt.internal.win32.SCRIPT_STATE&lt;br /&gt;
31: 17108 410592 org.eclipse.jface.text.Line&lt;br /&gt;
32: 1255 401600 &lt;/span&gt;&lt;objarrayklassklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;"&gt;&lt;br /&gt;
33: 16650 399600 java.util.Hashtable$Entry&lt;br /&gt;
34: 10952 350464 org.eclipse.ui.internal.services.EvaluationReference&lt;br /&gt;
35: 8665 346600 org.eclipse.ui.commands.HandlerSubmission&lt;br /&gt;
36: 10624 339968 java.util.TreeMap$Entry&lt;br /&gt;
37: 6598 307376 [Lorg.eclipse.swt.graphics.TextLayout$StyleItem;&lt;br /&gt;
38: 18520 296320 java.lang.Integer&lt;br /&gt;
39: 8567 274144 org.eclipse.ui.commands.ActionHandler&lt;br /&gt;
40: 11268 270432 org.eclipse.ui.internal.help.WorkbenchHelpSystem$6&lt;br /&gt;
...&lt;br /&gt;
Total 2894736 198472504&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
For each class we can see the class name, the number of instances of the class in the heap, and the number of bytes used in the heap by all instances of the class.  The table is sorted by consumed heap space.  Although it is very simple, it is extremely useful.  This information is enough to diagnose 60% of heap capacity problems.&lt;br /&gt;
&lt;br /&gt;
If a heap distribution histogram is too high-level, you can try jhat.  jhat can read and explore a heap dump.  It has a web interface and you can click though your dumped object graph.  Of course, clicking through a few million objects is not fun.  Fortunately, jhat supports query language.  Let's give it a try.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: xx-small;"&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;gt;jmap -dump:file=eclipse.heap 16608&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Dumping heap to C:\Program Files (x86)\Java\jdk1.6.0_11\bin\eclipse.heap ...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Heap dump file created&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; &amp;gt;jhat -J-Xmx1G eclipse.heap&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Reading from eclipse.heap...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Dump file created Wed Oct 14 08:41:07 MSD 2009&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Snapshot read, resolving...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Resolving 2300585 objects...&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Chasing references, expect 460 dots.............................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ................................................................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ................................................................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; .......................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Eliminating duplicate references................................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ................................................................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ................................................................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ....................................&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Snapshot resolved.&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Started HTTP server on port 7000&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; Server is ready.&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;
&lt;br /&gt;
Now open http://localhost:7000 and you can see a summary of all classes.  You can use standard queries via links or go straight to the “Execute Object Query Language (OQL) query” link at the bottom and type your own query.  Query language is quite awkward (it is based on the java script engine) and may not work well for large numbers of objects, but it is a very powerful tool.&lt;br /&gt;
&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;b&gt;Enterprise applications are 80% strings and maps&lt;/b&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;br /&gt;
Let’s look at the jmap histogram again.  In the top row, we can see "[C" class consuming most of the heap space.  Actually, these char arrays are part of String objects, and we can see that String instances are also consuming considerable space.  From my experience, 60-80% of heaps in an enterprise application are consumed by strings and hash maps.&lt;br /&gt;
Strings&lt;br /&gt;
Let's look how the JVM is storing strings.  String objects are semantically immutable. Each instance has four fields (all except hash are marked final):&lt;br /&gt;
• Reference to char array&lt;br /&gt;
• Integer offset&lt;br /&gt;
• Integer count of character&lt;br /&gt;
• Integer string hash (lazily evaluated, and once evaluated never changes)&lt;br /&gt;
&lt;br /&gt;
How much memory does one String instance consume?&lt;br /&gt;
&lt;br /&gt;
Here and below are size calculations for the Sun JVM (32bit).  This should be similar for other vendors.&lt;br /&gt;
Object header (8 bytes) + 3 refs (12 bytes) + int (4 bytes) = 24 bytes.  But the String instance is only a header.  Actual text is stored in char array (2 bytes each character + 12 bytes array header).&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://4.bp.blogspot.com/_6Xw_KFI7ZPs/S0Y5wA9TfAI/AAAAAAAADjQ/423ENgs3P0A/s320/1.png" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;String instances can share char arrays with each other.  When you call substring(…) on a String instance, no new char array allocation happens.  Instead, a new String referencing subrange of existing char arrays is created. Sometimes this can become a problem.  Imagine you are loading a text file (e.g., CSV).  First you are loading the entre line as string, then you seek the position of the field and call substring(…).  Now your small field value string object has a reference to an entry line of text.  Sometime later, a string header for the text line object is collected, but characters are still in memory because they are referenced via other string object.&lt;br /&gt;
&amp;nbsp;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://2.bp.blogspot.com/_6Xw_KFI7ZPs/S0Y6P7_uPZI/AAAAAAAADjY/JjJrS5GHSis/s320/2.png" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt; &lt;br /&gt;
&amp;nbsp;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;In the illustration above, useful data is marked by yellow.  We can see that some characters cannot be accessed any more, but still occupy space in the heap.  How can you avoid such problems?&lt;br /&gt;
If you are creating a String object with a constructor, a new char array is always allocated.  To copy content of a substring you can use the following construct (it looks a bit strange, but it works):&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; new String(a.substring(…))&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt; String.intern() – think twice&lt;/b&gt;&lt;br /&gt;
String class has a method intern() that can guarantee the following:&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; a.equals(b)&amp;nbsp; =&amp;gt; a.intern() == b.intern()&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
There is a table inside of the JVM used to store normal forms of strings.  If some text is found in a table then value from a table will be returned from intern(), else the string will be added to table. So a reference returned by intern() is always an object from JVM intern table.&lt;br /&gt;
&lt;br /&gt;
String intern table keep weak references to its objects, so unused strings can be collected as garbage when no other references exist except from intern table itself.  It looks like a great idea to use intern(), and eliminate all duplicated strings in an application. Many have tried … and many have regretted such decision.  I cannot say this is true for every JVM vendor, but if you are using Sun’s JVM, you should never do this.  Why?&lt;br /&gt;
&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&amp;nbsp; JVM string intern tables are stored in PermGen -- a separate region of the heap (not included in -Xmx size) used for the JVM’s internal needs.  Garbage collection in this area is expensive and size is limited (though configurable).&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;/li&gt;
&lt;li&gt;&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&amp;nbsp; You would have to insert a new string into the table which has O(n) complexity, where n is table size.&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;  String intern tables in JVMs work perfectly for the JVM’s needs (new entries are added only while loading new classes so insertion time is not a big issue) and it is very compact. But it is completely unsuitable for storing millions of application strings. It just was not designed for such a use case.&lt;br /&gt;
Removing of duplicates&lt;br /&gt;
The JVM’s string intern table is not an option but the idea of eliminating string duplicates is very attractive.  What can we do?&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;public&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; class InternTable&lt;/span&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;private&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp; final Map&lt;/span&gt;&lt;x, x=""&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; table = new HashMap&lt;/span&gt;&lt;x, x=""&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;();&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;public X intern(X val) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; X in = table.get(val);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; if (in == null) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; table.put(val, val);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; in = val;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; return in;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; &lt;/span&gt;Above is a simple snippet of a custom intern table. It can be used for strings or any other immutable objects.  Looks good, but it has a problem. Such an implementation will prevent objects from being collected by GC.  What can we do?&lt;br /&gt;
&lt;br /&gt;
We need to use weak references.  There are WeakHashMap classes in the JDK.  It is a hash table that uses weak references for keys.  Let's try to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; public&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; class InterTable&lt;/span&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; private&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; final Map&lt;/span&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;x&gt; table = new WeakHashMap&lt;x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/span&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;();&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; public X intern(X val) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; WeakReference&lt;/span&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; ref = table.get(val);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; X in = ref == null ? null : ref.get();&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; if (in == null) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; table.put(val, new WeakReference&lt;/span&gt;&lt;x&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;(val));&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; in = val;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp; return in;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;}&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt; &lt;br /&gt;
Did you notice we also need a weak reference for the wrap value?  This will work, but what is the cost?&lt;br /&gt;
• Reference from hash table – 1 ref * ratio of unused slots (~6 bytes)&lt;br /&gt;
• WeakHashMap$Entry object – 40 bytes&lt;br /&gt;
• value WeakReference – 24 bytes&lt;br /&gt;
&lt;br /&gt;
The cost per entry in the table is about 70 bytes.  That’s expensive.  Can we reduce it?&lt;br /&gt;
&lt;br /&gt;
Right now we have to have two weak references per entry. If we rewrite WeakHashMap to return an entry from the get(...) method (instead of the value), we can drop the second weak reference and save 24 bytes. But the cost of such an intern table is still high. You should analyze/experiment with your data to see if such a trick will bring greater benefits in your case.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UTF8 strings&lt;/b&gt;&lt;br /&gt;
Java strings are UTF and encoded using UTF16 in memory. If they are to be converted to UTF8, the actual text is likely to consume half the memory. But using UTF8 will break compatibility with the String class. You have to create your own class and convert it to standard String for a majority of operations.  This will increase CPU usage, but in some edge cases this approach can be useful for overcoming heap size limitations (e.g., storing large text indexes in memory).&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
Maps and sets&lt;/b&gt;&lt;br /&gt;
Good old java.util.HashMap is used everywhere. Standard implementation in JDKs is to use the open hash table data structure.&lt;br /&gt;
&lt;/x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://3.bp.blogspot.com/_6Xw_KFI7ZPs/S0Y7K91fsMI/AAAAAAAADjg/MJuko6Rj6CM/s320/3.png" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;x&gt;&lt;x, x=""&gt;&lt;x, x=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x&gt;&lt;x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;x&gt;&lt;x, x=""&gt;&lt;x, x=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x&gt;&lt;x&gt;References to key and value are stored in the Entry object (which also keeps the hash for the key for faster access).  If several keys are mapped to same hash slot, they are stored as a list of interlinked entries.  The size of each entry structure: object header + 3 references + int = 24 bytes.  java.util.HashSet is using java.util.HashMap under the hood so your overhead will be the same.  Can we store map/set in more compact form?  Sure.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt; Sorted array map&lt;/b&gt;&lt;br /&gt;
If the keys are comparable, we can store the map or set as sorted arrays of interleaved key/value pairs (array of keys in the case of a set).  Binary search can be used for fast lookups in an array, but insertion and deletion of entries will have to shift elements.  Due to the high cost of updates in such a structure, it will be effective only for smaller collection sizes, and for operation patterns that are mostly read.  Fortunately, this is usually what we have -- map/set of a few dozen objects that are read more often than modified.&lt;br /&gt;
&lt;b&gt; &lt;br /&gt;
Closed hash table&lt;br /&gt;
&lt;/b&gt; If we have a collection of a larger size, we should use a hashtable.  Can we make the hashtable more compact?  Again, the answer is yes.  There are data structures called closed hashtables that do not require entry objects.&lt;br /&gt;
&lt;br /&gt;
&lt;/x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://2.bp.blogspot.com/_6Xw_KFI7ZPs/S0Y7MP3lG0I/AAAAAAAADjo/ygSkMAnL1uc/s320/4.png" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;x&gt;&lt;x, x=""&gt;&lt;x, x=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x&gt;&lt;x&gt;&lt;br /&gt;
In closed hashtables, references from the hashtable point directly to an object (key).  What if we want to put in a reference to a key but the hash slot is occupied already?  In such a case, we should find another slot (e.g., next one).  How do you lookup a key?  Search through all adjacent slots until key or null reference is found.  As you can see from algorithm, it is very important to have enough empty slots in your table.  Density of closed hash tables should be kept below 0.5 to avoid performance degradation.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Maps structures summary&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table border="1" bordercolor="black" cellspacing="0"&gt;&lt;tr valign="top"&gt;&lt;td&gt;&lt;u&gt;Open hash map/set&lt;/u&gt;&lt;br /&gt;
Cost per entry:&lt;br /&gt;
&lt;ul type="DISC"&gt;&lt;li&gt;1 ref * 1.33 (for 0.75 density)&lt;/li&gt;
&lt;li&gt;Entry object&lt;/li&gt;
&lt;li&gt;Total: ~30 bytes&lt;/li&gt;
&lt;/ul&gt;+ Better handling hash collisions.&lt;br /&gt;
+ Fast access to hash code.&lt;br /&gt;
&lt;/td&gt;   &lt;td&gt;&lt;u&gt;Closed hash map/set&lt;/u&gt;&lt;br /&gt;
Cost per entry (map):&lt;br /&gt;
&lt;ul type="DISC"&gt;&lt;li&gt;2 ref * 2 (for 0.5 density)&lt;/li&gt;
&lt;li&gt;Total: 16 bytes&lt;/li&gt;
&lt;/ul&gt;Cost per entry (set):&lt;br /&gt;
&lt;ul type="DISC"&gt;&lt;li&gt;1 ref * 2 (for 0.5 density)&lt;/li&gt;
&lt;li&gt;Total: 8 bytes&lt;/li&gt;
&lt;/ul&gt;- Generally slower than open version.&lt;br /&gt;
&lt;/td&gt;   &lt;td&gt;Sorted array map/ser&lt;br /&gt;
Cost per entry (map):&lt;br /&gt;
&lt;ul type="DISC"&gt;&lt;li&gt;2 ref&lt;/li&gt;
&lt;li&gt;Total: 8 bytes&lt;/li&gt;
&lt;/ul&gt;Cost per entry (set):&lt;br /&gt;
&lt;ul type="DISC"&gt;&lt;li&gt;1 ref &lt;/li&gt;
&lt;li&gt;Total: 4 bytes&lt;/li&gt;
&lt;/ul&gt;- For small collection only.&lt;br /&gt;
- Expensive update/delete.&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
The JDK is using an open hashtable structure because in general case it is a better structure.  But when you are desperate to save memory, the other two options are worth considering.&lt;br /&gt;
&lt;br /&gt;
&lt;constmethodklass&gt;&lt;methodklass&gt;&lt;symbolklass&gt;&lt;constantpoolklass&gt;&lt;instanceklassklass&gt;&lt;constantpoolcacheklass&gt;&lt;objarrayklassklass&gt;&lt;x&gt;&lt;x, x=""&gt;&lt;x, x=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x, weakreference=""&gt;&lt;x&gt;&lt;x&gt;&lt;x&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;
Optimization is an art.  There are no magical data structures capable of solving every problem.  As you can see, you have to fight for every byte.  Memory optimization is a complex process.  Remember that you should design your data so each object can be referenced from different collections (instead of having to copy data).  It is usually better to use semantically immutable objects because you can easily share them instead of copying them.  And from my experience, in a well-designed application, optimization and tuning can reduce memory usage by 30-50%.  If you have a very large amount of data, you have to be ready to handle it.  At Grid Dynamics, that’s our day-to-day job!  So, if you are building system capable of handling enormous amounts of data, don’t hesitate to ask us for assistance :)&lt;br /&gt;
&lt;br /&gt;
&lt;/x&gt;&lt;/x&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/x,&gt;&lt;/x,&gt;&lt;/x&gt;&lt;/objarrayklassklass&gt;&lt;/constantpoolcacheklass&gt;&lt;/instanceklassklass&gt;&lt;/constantpoolklass&gt;&lt;/symbolklass&gt;&lt;/methodklass&gt;&lt;/constmethodklass&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1485479515011646318?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1485479515011646318/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1485479515011646318" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1485479515011646318?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1485479515011646318?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/k8ZjIxUHRT0/java-tricks-reducing-memory-consumption.html" title="Java tricks, reducing memory consumption" /><author><name>Alexey Ragozin</name><uri>http://www.blogger.com/profile/13720493857045012756</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03800576285958180449" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_6Xw_KFI7ZPs/S0Y5wA9TfAI/AAAAAAAADjQ/423ENgs3P0A/s72-c/1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/01/java-tricks-reducing-memory-consumption.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYDRHw8cCp7ImA9WxNVFUs.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7255942681266654076</id><published>2009-10-26T05:26:00.000-07:00</published><updated>2009-10-26T07:42:55.278-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-26T07:42:55.278-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Oracle Coherence memory usage, indexes</title><content type="html">In previous posts we discussed a memory consumption in Oracle Coherence. We loaded 1M of DomainObj into cached and looked into memory dumps aquired with jmap utility. Now, we will talk about memory overheads caused by another powerful feature of Coherence - indexes.&lt;br /&gt;
&lt;br /&gt;
Coherence support indexes. Indexes are another major memory consumer, and if you going to use indexes you should plan memory usage for them. We will use a distributed scheme with a local scheme on the back end in this case. An index is created for each of the DomainObjAttrib fields, and the number of unique values of this field should be about 1M/16 (each value of indexed field should match 16 objects).&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color:lightgray"&gt;&amp;lt;distributed-scheme&amp;gt;&lt;br /&gt;
&amp;lt;scheme-name&amp;gt;simple-distributed-scheme&amp;lt;/scheme-name&amp;gt;&lt;br /&gt;
&amp;lt;backing-map-scheme&amp;gt;&lt;br /&gt;
&amp;lt;local-scheme/&amp;gt;&lt;br /&gt;
&amp;lt;/backing-map-scheme&amp;gt;&lt;br /&gt;
&amp;lt;backup-count&amp;gt;0&amp;lt;/backup-count&amp;gt;&lt;br /&gt;
&amp;lt;/distributed-scheme&amp;gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
First let's look at Coherence 3.5 :&lt;br /&gt;
&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfRfH3kBII/AAAAAAAAIms/Pcq7kVzteJ0/s1600-h/index-35-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379498612535592066" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfRfH3kBII/AAAAAAAAIms/Pcq7kVzteJ0/s400/index-35-mem-histo.png" style="display: block; height: 145px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;row 6 (com.tangosol.util.SegmentedHashMap$Entry) - 1M of instances related to main storage and 1062.5k to the index;&lt;/li&gt;
&lt;li&gt;row 7 ([Lcom.tangosol.util.SegmentedHashMap$Entry;) – 19Mb is related to main storage, the rest to the index;&lt;/li&gt;
&lt;li&gt;row 12 – 7.2 Mb is related to main storage, the rest to the index.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Internally the index is constructed from 2 maps:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Forward map:&lt;/b&gt;&amp;nbsp;maps indexed attribute value to a set of cache entries (I suspect that reference to the key is actually stored, but I am not sure);&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reverse map:&lt;/b&gt;&amp;nbsp;maps cache entry (or its key) to the value of the indexed attribute for this entry.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
In our case we have 62,500 unique values of indexed fields.&lt;br /&gt;
&lt;p&gt;Now let's compare the memory picture with 3.4:&lt;br /&gt;
&lt;a href="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfXEqzIGDI/AAAAAAAAIm0/1f2u3zJ7vCo/s1600-h/index-34-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379504755125524530" src="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfXEqzIGDI/AAAAAAAAIm0/1f2u3zJ7vCo/s400/index-34-mem-histo.png" style="cursor: pointer; display: block; height: 124px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Rows related to the index are highlighted by yellow, also:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;row 6 ([Lcom.tangosol.util.SafeHashMap$Entry;) – 7.2Mb related to main storage and the rest to the index.&lt;/li&gt;
&lt;/ul&gt;An interesting thing to note: in 3.4 there are 1M DomainObjAttrib objects on the heap, but in 3.5 only 62.5k (and we know there are exactly 62.5k unique objects of this kind), so 3.4 is storing duplicates of objects, which 3.5 avoids. You can find more detailed information about this on the Coherence&amp;nbsp;&lt;a href="http://forums.oracle.com/forums/message.jspa?messageID=3485879"&gt;forum&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;tr&gt;&lt;td &gt;&lt;br /&gt;
Summary for Coherence 3.4:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Domain objects: 227.3 Mb&lt;/li&gt;
&lt;li&gt;Overhead: 116.4 Mb&lt;/li&gt;
&lt;li&gt;Index: 88.5 Mb&lt;/li&gt;
&lt;li&gt;Other: 6.5 Mb&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;
&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZHhRafWI/AAAAAAAAInE/Dole-W8-oAM/s1600-h/image006.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507003131067746" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZHhRafWI/AAAAAAAAInE/Dole-W8-oAM/s400/image006.png" style="display: block; height: 166px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
Summary for Coherence 3.5:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Domain objects: 227.3 Mb&lt;/li&gt;
&lt;li&gt;Overhead: 167 Mb&lt;/li&gt;
&lt;li&gt;Index: 65 Mb&lt;/li&gt;
&lt;li&gt;Other: 8.4 Mb&lt;/li&gt;
&lt;/ul&gt;_&lt;/td&gt;&lt;td&gt;&lt;br /&gt;
&lt;a href="http://1.bp.blogspot.com/_CQV12Vs8lZ0/SqfZHeoqyvI/AAAAAAAAIm8/0FDtOsJFYQc/s1600-h/image007.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507002423298802" src="http://1.bp.blogspot.com/_CQV12Vs8lZ0/SqfZHeoqyvI/AAAAAAAAIm8/0FDtOsJFYQc/s400/image007.png" style="cursor: pointer; display: block; height: 166px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Again, we can see that Coherence 3.5 uses additional data structures to make partition operations more efficient, but, in the case of index, removing duplicated attribute values from the heap makes 3.5 more memory efficient.&lt;br /&gt;
&lt;br /&gt;
Let's find a formula for index size (N number of entries, M number of unique indexed field values)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Coherence 3.4:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Forward map&lt;/b&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;4 * M – reference in hash table&lt;/li&gt;
&lt;li&gt;24 * M –&amp;nbsp;SafeHashMap$Entry&lt;/li&gt;
&lt;li&gt;16 * M –&amp;nbsp;SafeHashSet&lt;/li&gt;
&lt;li&gt;56 * M –&amp;nbsp;SafeHashMap (backend&amp;nbsp;for&amp;nbsp;SafeHashSet)&lt;/li&gt;
&lt;li&gt;4 * N – reference in hash table of hash set&lt;/li&gt;
&lt;li&gt;24 * N –&amp;nbsp;SafeHashMap$Entry&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Reverse map&lt;/b&gt;&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;4 * N – references in hash table&lt;/li&gt;
&lt;li&gt;24 * N –&amp;nbsp;SafeHashMap$Entry&lt;/li&gt;
&lt;li&gt;&amp;lt;Size of attribute value&amp;gt; * N – stored attribute value&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Total index size&lt;/b&gt;&amp;nbsp;- 100 * M + 56 * N + N * &amp;lt;Size of attribute value&amp;gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
In our case the estimated index size for 3.4 should be 100 * 6250 + 56 * 1M + 24000000 = 81.4Mb. The formula assumes a 100% fill ratio of hash tables; it produces the lower bound for index size. The actual size will always be little bigger (unless the hash table fill ration is greater than 100%, but it should never happen).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Coherence 3.5:&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Forward map&lt;/b&gt;&amp;nbsp;– 100 * M (bytes) + size of value objects.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;4 * M – reference in hash table&lt;/li&gt;
&lt;li&gt;24 * M –&amp;nbsp;SegmentedHashMap$Entry&lt;/li&gt;
&lt;li&gt;16 * M –&amp;nbsp;SafeHashSet&lt;/li&gt;
&lt;li&gt;56 * M –&amp;nbsp;SafeHashMap (backend for SafeHashSet)&lt;/li&gt;
&lt;li&gt;4 * N – reference in hash table of hash set&lt;/li&gt;
&lt;li&gt;24 * N –SafeHashMap$Entry&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Reverse map&lt;/b&gt;&amp;nbsp;– 100 * M (bytes) + size of value objects.&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;4 * N – references in hash table&lt;/li&gt;
&lt;li&gt;24 * N –&amp;nbsp;SegmentedHashMap$Entry&lt;/li&gt;
&lt;li&gt;&amp;lt;Size of attribute value&amp;gt; * M – stored attribute value&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;&lt;b&gt;Total index size&lt;/b&gt;&amp;nbsp;- 100 * M + 56 * N + M * &amp;lt;Size of attribute value&amp;gt;&lt;/li&gt;
&lt;/ul&gt;In our case the estimated index size for 3.5 should be 100 * 6250 + 56 * 1M + 1500000 = 60Mb. Again we have the lower bound for index size.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 24px; font-weight: bold;"&gt;Summary&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Let's put the results of our experiments in single table. N is a number of entries in the cache, M is a number of distinct values of indexed field.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Coherence 3.4:&lt;/b&gt;&amp;nbsp;&amp;gt;100 * M + 56 * N + N * A&lt;br /&gt;
&lt;b&gt;Coherence 3.5:&lt;/b&gt;&amp;nbsp;&amp;gt;100 * M + 56 * N + M * A&lt;br /&gt;
&lt;p&gt;N is a number of entrees, M - is a number of distinct entries, A is a size of indexed attribute value.&lt;br /&gt;
&lt;p&gt;Because the fill ratio of the hash table will always be below 100%, in practice, the cache will always consume slightly more memory than the value calculated by the formulas above.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style="font-size: 24px;"&gt;Conclusion&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
Working with Coherence caches, it is always important to remember that both main data and indexes are stored in main memory. Here I tried to give a simple tool to get a good estimation of memory consumption.&lt;br /&gt;
Hope you will find it useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7255942681266654076?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7255942681266654076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7255942681266654076" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7255942681266654076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7255942681266654076?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/pZBsI87PJSA/coherence-memory-usage-indexes.html" title="Oracle Coherence memory usage, indexes" /><author><name>Alexey Ragozin</name><uri>http://www.blogger.com/profile/13720493857045012756</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03800576285958180449" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfRfH3kBII/AAAAAAAAIms/Pcq7kVzteJ0/s72-c/index-35-mem-histo.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/10/coherence-memory-usage-indexes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MDRnc9fCp7ImA9WxNVE00.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8536528197967331117</id><published>2009-10-23T07:17:00.000-07:00</published><updated>2009-10-23T07:51:17.964-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T07:51:17.964-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="capacity" /><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="memory" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Oracle Coherence, memory structure of cache</title><content type="html">Imagine that you are working on project involving an in-memory data grid. You have analyzed your requirements and you can see that you need to store 10 million objects in your grid. The next question is how much physical memory do you need to provide such capacity? I recently have been facing the same question, and want to share some findings about how Oracle Coherence (popular in-memory data grid middleware) uses memory.&lt;br /&gt;
&lt;br /&gt;
My approach is very simple. I am creating a cache, then puttung 1 million objects in it, and then analyze heap memory usage.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Local scheme&lt;br /&gt;
&lt;/h2&gt;Lest start with local scheme. While it may not be so often used by itself, a local scheme may serve as a backing map for other schemes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: rgb(217, 217, 217) none repeat scroll 0% 0%; border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 638px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: 0.5pt solid black; padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;local-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: black;"&gt;local-scheme&lt;/span&gt;&lt;span style="color: teal;"&gt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;local-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
The memory picture for one million objects is:&lt;br /&gt;
&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfPkF7kQZI/AAAAAAAAImE/E-wFln8f7eI/s1600-h/local-scheme-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379496498891604370" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfPkF7kQZI/AAAAAAAAImE/E-wFln8f7eI/s400/local-scheme-mem-histo.png" style="cursor: pointer; display: block; height: 90px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
(Sun JDK contains a 'lmap' tool that can display memory usage by objects for a live Java &lt;span style="font-size: 100%;"&gt;process. It is an extremely handy tool for memory profiling.)&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;On the diagram we can see our domain objects (&lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;DomainObjAttrib&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;, &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;DomainObject&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;, &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;DomainObjKey&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;).  Also we can see 1M of &amp;nbsp;c&lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;om.tangosol.net.cache.LocalCache$Entry&lt;/span&gt; objects. They are part of hash table implemented in Coherence. If you put the same objects in &lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;java.util.HashMap&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;, the picture will be almost the same, but you will see 1M of &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;java.util.HashMap$Entry&lt;/span&gt; instead.&lt;span style="font-size: 100%;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;Lets summarize memory consumption:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 291px;"&gt;&lt;/col&gt;&lt;col style="width: 348px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: medium none; padding-left: 7px; padding-right: 7px;"&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Domain object: 140.6Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Hash table: 77.3Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Other: 4.8Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td style="border: medium none; padding-left: 7px; padding-right: 7px;"&gt;&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZ3fBvUiI/AAAAAAAAIns/tCX_jIywfhg/s1600-h/image001.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507827162173986" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZ3fBvUiI/AAAAAAAAIns/tCX_jIywfhg/s400/image001.png" style="cursor: pointer; display: block; height: 168px; margin: 0px auto 10px; text-align: center; width: 378px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;span style="font-size: 100%;"&gt;In short, we have overhead of about 77 bytes per cache entry. How this space is used by Coherence?&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;72 bytes – size of &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;LocalCache$Entry&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; (BTW, the size of HashMap$Entry is just 24 bytes because it does not need to store additional data needed to support eviction and statistics collection);&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;4 bytes – reference from hash table;&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Because the hash table fill ration is always less than 100%, some references are unused. This produces an additional 1.3 bytes per entry in our case.&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Distributed scheme&lt;br /&gt;
&lt;/h2&gt;Now let's switch to a distributed scheme (distributed hash table implementation of Coherence). As in the first case, we will use a simple configuration with a local scheme on the back end.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: rgb(217, 217, 217) none repeat scroll 0% 0%; border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 638px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: 0.5pt solid black; padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;distributed-scheme&amp;gt;&lt;span style="color: teal;"&gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: black;"&gt;simple-distributed-scheme&lt;/span&gt;&lt;span style="color: teal;"&gt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/span&gt;backing-map-scheme&amp;gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;local-scheme&lt;span style="color: teal;"&gt;/&amp;gt;&lt;/span&gt;backing-map-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/span&gt;backup-count&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: black;"&gt;0&amp;lt;&lt;/span&gt;&lt;span style="color: teal;"&gt;/&lt;/span&gt;backup-count&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;distributed-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;The memory picture for one million objects is:&lt;br /&gt;
&lt;/span&gt;&lt;a href="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfRdz57-mI/AAAAAAAAImM/Ha9kZoDPyUY/s1600-h/distributed-scheme-35-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379498589996972642" src="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfRdz57-mI/AAAAAAAAImM/Ha9kZoDPyUY/s400/distributed-scheme-35-mem-histo.png" style="cursor: pointer; display: block; height: 138px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;span style="font-size: 100%;"&gt;Now things look much more complicated. First, there are no domain objects on the heap – that's because in distributed scheme objects are stored in serialized form. Coherence is using &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;com.tangosol.util.Binary&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;objects to wrap the actual byte array (this way they can be store in the backing map), so we have 2M of wrapper objects (for each key, and each value). The next strange thing is &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;SegmentedHashMap,&amp;nbsp;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;which is not a part of local scheme, so it should be related to the distributed scheme. In Coherence prior to version 3.5 the data for all partitions was stored in a single backing map instance and to relocate a partition data from backing map, a full scan was required. Version 3.5 introduced a new mechanism - an additional index that remembers a key set for each partition. It improves partition relocation performance drastically but increases memory usage. Finally there is a pack of &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;int[]&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; objects, but this is still a mystery for me.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;I think it is worthwhile to compare the 3.5 results with the 3.4 results at this point. With exactly the same configuration, the memory picture for Coherence 3.4 is:&lt;br /&gt;
&lt;/span&gt;&lt;a href="http://3.bp.blogspot.com/_CQV12Vs8lZ0/SqfReDadwWI/AAAAAAAAImU/SHcwxLbxD98/s1600-h/distributed-scheme-34-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379498594159935842" src="http://3.bp.blogspot.com/_CQV12Vs8lZ0/SqfReDadwWI/AAAAAAAAImU/SHcwxLbxD98/s400/distributed-scheme-34-mem-histo.png" style="cursor: pointer; display: block; height: 97px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;span style="font-size: 100%;"&gt;Two things to note:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Size of &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;LocalCache$Entry&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; in 3.4 is 64 bytes instead of 72 in 3.5&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;There is no &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;SegmentedHashMap&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; related staff in 3.4&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;span style="font-size: 100%;"&gt;Let's summarize memory usage.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 299px;"&gt;&lt;/col&gt;&lt;col style="width: 339px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="font-size: 100%;"&gt;Coherence 3.4:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Domain objects: 227.3Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Overhead: 116.4Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Other 11Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZ2wWRuYI/AAAAAAAAInk/AeIcBHcYZ3Y/s1600-h/image002.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507814631848322" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZ2wWRuYI/AAAAAAAAInk/AeIcBHcYZ3Y/s400/image002.png" style="cursor: pointer; display: block; height: 166px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 300px;"&gt;&lt;/col&gt;&lt;col style="width: 339px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="font-size: 100%;"&gt;Coherence 3.5&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Domain objects: 227.3Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Overhead: 167Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Other 8Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;a href="http://1.bp.blogspot.com/_CQV12Vs8lZ0/SqfZI5wkpWI/AAAAAAAAInc/6CO8BJntB0s/s1600-h/image003.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507026884076898" src="http://1.bp.blogspot.com/_CQV12Vs8lZ0/SqfZI5wkpWI/AAAAAAAAInc/6CO8BJntB0s/s400/image003.png" style="cursor: pointer; display: block; height: 166px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;span style="font-size: 100%;"&gt;Conclusion:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;In the distributed scheme we have 2 additional &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;Binary&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; objects per entry (+48 bytes)&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Also 3.5 adds additional data structures, which consume about 50 bytes per object&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: 100%;"&gt;Data structures added in 3.5 are a trade-off to provide better performance in partition-related operations. They have their merits for sure, but is still would be preferable to have an option for turning them off.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;External scheme&lt;br /&gt;
&lt;/h2&gt;&lt;span style="font-size: 100%;"&gt;A local scheme is not the only option to use as a backing map. Coherence also has a so-called external scheme, which can store data off the heap using the &lt;/span&gt;&lt;span style="font-family: 'Lucida Console'; font-size: 100%;"&gt;BinaryStore&lt;/span&gt;&lt;span style="font-size: 100%;"&gt; plugin (plugins for NIO memory storage and several disk backend storage models are supported out of the box). Let's analyze the distributed scheme with an external scheme (nio memory) as the back end.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: rgb(217, 217, 217) none repeat scroll 0% 0%; border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 638px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: 0.5pt solid black; padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="font-size: 100%;"&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;distributed-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: black; font-size: 100%;"&gt;external-distributed-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;scheme-name&amp;gt;&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;backing-map-scheme&amp;gt;&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;external-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;nio-memory-manager&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;/&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;external-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;backing-map-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;backup-count&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: black; font-size: 100%;"&gt;0&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;backup-count&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="font-size: 100%;"&gt;distributed-scheme&lt;/span&gt;&lt;span style="color: teal; font-size: 100%;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;The memory picture for one million objects is:&lt;br /&gt;
&lt;/span&gt;&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfReTEbxSI/AAAAAAAAImc/ZzynMr-qpPs/s1600-h/external-scheme-35-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379498598362498338" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfReTEbxSI/AAAAAAAAImc/ZzynMr-qpPs/s400/external-scheme-35-mem-histo.png" style="cursor: pointer; display: block; height: 104px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;Please keep in mind that we are analyzing only the Java heap and in this case some amount of data is stored out of the heap using direct memory buffers. You may expect that all your business data will be stored out of the heap, but still we can see plenty of binary objects in memory. These binaries are keys. Yes, while values are stored entirely in external storage, keys are stored in the heap (actually they are stored in both the heap and external storage). Coherence 3.4 shows a similar picture, so I will just omit it.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 100%;"&gt;In this case the diagram does not show the full memory picture (only the heap) so you should not compare it directly to the previous cases.&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 298px;"&gt;&lt;/col&gt;&lt;col style="width: 340px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="font-size: 100%;"&gt;Coherence 3.5:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Key duplicates: 32Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Overhead: 66Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-size: 100%;"&gt;Other: 18Mb&lt;br /&gt;
&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td style="padding-left: 7px; padding-right: 7px;"&gt;&lt;a href="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfZIVkJJHI/AAAAAAAAInU/iveC5FSX9YA/s1600-h/image004.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507017168266354" src="http://4.bp.blogspot.com/_CQV12Vs8lZ0/SqfZIVkJJHI/AAAAAAAAInU/iveC5FSX9YA/s400/image004.png" style="cursor: pointer; display: block; height: 165px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;span style="font-size: 100%;"&gt;Conclusion:&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: 100%;"&gt;While the external scheme is using non-heap memory for data storage, it istill consumes enough of the heap for keys and other structures.&lt;/span&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Replicated cache&lt;br /&gt;
&lt;/h2&gt;Cache configuration:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: rgb(217, 217, 217) none repeat scroll 0% 0%; border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 638px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: 0.5pt solid black; padding-left: 7px; padding-right: 7px;"&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;replicated-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: black;"&gt;simple-replicated-scheme&lt;/span&gt;&lt;span style="color: teal;"&gt;&lt;/span&gt;scheme-name&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;backing-map-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&amp;lt;&lt;/span&gt;local-scheme&lt;span style="color: teal;"&gt;/&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;backing-map-scheme&lt;span style="color: teal;"&gt;&amp;gt;&lt;br /&gt;
&lt;/span&gt;&lt;span style="color: teal;"&gt;&amp;lt;&lt;/span&gt;replicated-scheme/&lt;span style="color: teal;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
The memory picture for one million objects is:&lt;br /&gt;
&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfRe7wVmlI/AAAAAAAAImk/O1NX1iqU_NA/s1600-h/replicated-scheme-35-mem-histo.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379498609284061778" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfRe7wVmlI/AAAAAAAAImk/O1NX1iqU_NA/s400/replicated-scheme-35-mem-histo.png" style="display: block; height: 131px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;I rarely use a replicated scheme, so the number of additional data structures is a little surprising. As you can see, the replicated scheme is storing plain Java objects (unlike the distributed scheme, which is always operating with serialized blobs).&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;table border="0" style="border-collapse: collapse;"&gt;&lt;colgroup&gt;&lt;col style="width: 268px;"&gt;&lt;/col&gt;&lt;col style="width: 370px;"&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td style="border: 0.5pt solid black; padding-left: 7px; padding-right: 7px;"&gt;Memory summary is (for Coherence 3.5)&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Domain objects: 140.6Mb&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Overhead: 263.3Mb&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Other: 7.6Mb&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/td&gt;&lt;td style="border-color: black black black -moz-use-text-color; border-style: solid solid solid none; border-width: 0.5pt 0.5pt 0.5pt medium; padding-left: 7px; padding-right: 7px;"&gt;&lt;a href="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZIMiEuLI/AAAAAAAAInM/lmlsMvUgFUo/s1600-h/image005.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5379507014743668914" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfZIMiEuLI/AAAAAAAAInM/lmlsMvUgFUo/s400/image005.png" style="cursor: pointer; display: block; height: 166px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;&lt;br /&gt;
&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;span style="font-size: x-large;"&gt;&lt;span style="font-size: 24px;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Lets put all results in a simple table with capacity formulae:&lt;br /&gt;
&lt;a href="http://1.bp.blogspot.com/_6Xw_KFI7ZPs/SuHCUHcRFHI/AAAAAAAADPY/N074PqFV79g/s1600-h/coh-cap.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_6Xw_KFI7ZPs/SuHCUHcRFHI/AAAAAAAADPY/N074PqFV79g/s640/coh-cap.png" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Here N is a number of entries, K is a size of keyset.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: 24px; font-weight: bold;"&gt;Stay tuned&lt;/span&gt;&lt;br /&gt;
Hope, this will help you to more presizely estimate memory consumptions of your Coherence cluster. In next blog posting I will describe the structure and overheads of secondary indexes in Oracle Coherence. Stay tuned!&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;&lt;span style="font-family: Arial; font-size: small;"&gt;&lt;span style="font-size: 13px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8536528197967331117?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8536528197967331117/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8536528197967331117" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8536528197967331117?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8536528197967331117?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/w63JDQAWF5s/oracle-coherence-memory-structure-of.html" title="Oracle Coherence, memory structure of cache" /><author><name>Alexey Ragozin</name><uri>http://www.blogger.com/profile/13720493857045012756</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03800576285958180449" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SqfPkF7kQZI/AAAAAAAAImE/E-wFln8f7eI/s72-c/local-scheme-mem-histo.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/09/oracle-coherence-memory-structure-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAASX44cCp7ImA9WxNQFUk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-973402290072663389</id><published>2009-09-18T03:36:00.001-07:00</published><updated>2009-09-21T08:25:48.038-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-21T08:25:48.038-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="POF" /><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Oracle Coherence using POF, without a single line of code</title><content type="html">&lt;span xmlns=""&gt;&lt;p&gt;People developing distributed Java applications know the importance of wire formats for objects. Native Java serialization has only one advantage—it is built in. It is relatively slow, not very compact, and has other quirks. Starting with version 3.2, Oracle Coherence is offering its own proprietary binary wire format for objects—&lt;a href="http://coherence.oracle.com/display/COH35UG/The+Portable+Object+Format"&gt;POF serialization&lt;/a&gt;. POF is not only cross platform, but also much more compact and faster compared to built-in serialization. Both compactness and speed are extremely important for data grid application. The only disadvantage of POF is that you should write custom serialization/deserialization code for each of your mobile objects. Not only domain objects stored in cache should have serializers, but also entry processors, aggregators, etc. The amount of code you have to write may look daunting and force you to stick with built-in Java serialization.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;But there is a simple way to get best of both worlds. In a recent project I have implemented a generic POF serializer. It uses reflection and doesn't require any changes in code, although you still need to register classes in coherence-pof-config.xml. Still it offers the advantages of the POF format – compact object size and performance. While performance is a bit degraded from using reflection (but still much faster than Java serialization), the sizes of serialized objects are similar to a handmade POF serializer.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Some people believe that reflection is slow. I have performed simple speed tests between Java reflection, a handmade POF serializer, and a reflection-based POF serializer—a very simple single threaded test doing serialization and deserialization of an object in a loop.&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Java serialization – 8K ops/sec&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Handmade POF – 46.4K ops/sec&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Reflection based POF – 35K ops/sec&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Sweet! I got 4 times speed up, 8 times reduced size just by writing 5 lines in coherence-pof-config.xml. Numbers may be different for different application but the trend is obvious.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;And one more good thing—you can combine a reflection-based POF serializer with handmade ones. You can start with using generic implementation for all objects, and later write a few handmade serializers to reclaim ~24% lost on serialization for &lt;em&gt;hot&lt;/em&gt; objects.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If you are interested you can look at the implementation &lt;a href="http://code.google.com/p/gridkit/source/browse/trunk/coherence/benchmarks/cache-capacity/src/main/java/com/griddynamics/gridkit/coherence/utils/pof/ReflectionPofSerializer.java"&gt;here&lt;/a&gt;, available under the Apache 2.0 license.&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-973402290072663389?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/973402290072663389/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=973402290072663389" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/973402290072663389?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/973402290072663389?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/SVKj5WW0w6Q/oracle-coherence-using-pof-without.html" title="Oracle Coherence using POF, without a single line of code" /><author><name>Alexey Ragozin</name><uri>http://www.blogger.com/profile/13720493857045012756</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03800576285958180449" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/09/oracle-coherence-using-pof-without.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMNSHg9cSp7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-5688233876162385817</id><published>2009-08-31T05:06:00.000-07:00</published><updated>2009-10-23T08:08:19.669-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:08:19.669-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Bokov" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="amazon ec2" /><category scheme="http://www.blogger.com/atom/ns#" term="gogrid" /><title>GoGrid is out of beta</title><content type="html">GoGrid is &lt;a href="http://blog.gogrid.com/2009/08/19/gogrid-officially-out-of-beta/" target="_blank"&gt;officially out of beta,&lt;/a&gt; so now it's time to compare GoGrid with the public cloud market leader, &lt;a href="http://aws.amazon.com/ec2" target="_blank"&gt;Amazon EC2&lt;/a&gt;. Both vendors have &lt;a href="http://www.cloudclimate.com/" target="_blank"&gt;relatively stable&lt;/a&gt; performance metrics and they both implement the basic functionality of a cloud provider:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Programmatic control via REST API&lt;/li&gt;
&lt;li&gt;Scalable data storage solution: &lt;a href="http://aws.amazon.com/ebs/" target="_blank"&gt;Elastic Block Storage&lt;/a&gt; in Amazon AWS and &lt;a href="http://wiki.gogrid.com/wiki/index.php/Cloud_Storage" target="_blank"&gt;CloudStorage&lt;/a&gt; in GoGrid&lt;/li&gt;
&lt;li&gt;Ability to assign external IP addresses&lt;/li&gt;
&lt;li&gt;Ability to grant root/administrator credentials&lt;/li&gt;
&lt;li&gt;Many options to configure the cloud cluster&lt;/li&gt;
&lt;li&gt;Windows and Linux support&lt;/li&gt;
&lt;li&gt;Web console for monitoring and management&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
So far, as cloud providers GoGrid and Amazon EC2 look very similar, but practical experience of using them in real-life projects helps us identify some unique features that can be important for specific applications.&lt;br /&gt;
&lt;br /&gt;
For Amazon EC2 we can highlight the features listed below:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;We can choose instances with different performance characteristics: Amazon EC2 has a product line that can be scaled by performance&lt;/li&gt;
&lt;li&gt;&lt;a href="http://aws.amazon.com/ec2/#os"&gt;Support for multiple OSes&lt;/a&gt;, some of them powered by marker leaders such as &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=205" target="_blank"&gt;Oracle&lt;/a&gt;, &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=204" target="_blank"&gt;Sun&lt;/a&gt;, and &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=229" target="_blank"&gt;IBM&lt;/a&gt;. Also, the &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=202&amp;amp;resultOffset=0&amp;amp;sortField=107&amp;amp;sortOrder=0&amp;amp;filterEntryTypeID=-1" target="_blank"&gt;community&lt;/a&gt; has made a big commitment to Amazon EC2 resources.&lt;/li&gt;
&lt;li&gt;User-friendly web console and web help&lt;/li&gt;
&lt;li&gt;Service popularity: most questions about EC2 can be answered on the web; it's very possible that someone else has already solved the same problem&lt;/li&gt;
&lt;li&gt;Start-up time for instances based on a popular AMI. It takes from 2 to 4 minutes to invoke an AMI and start the OS.&lt;/li&gt;
&lt;li&gt;We always have access to instances. Even if we can't have SSH access into an instance we can look onto system logs or reboot and instance using the web console.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Although there are many positive aspects for Amazon EC2, some negative points can be identified as well:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;There is no SLA for CPU, very low performance for m1.small  and  &lt;a href="http://www.paessler.com/blog/2009/04/06/prtg-7/monitoring-cloud-computing-performance-with-prtg-cpu-disk-memory-speed-comparison-of-amazon-ec2-instance-types/" style="text-decoration: none;" target="_blank"&gt;performance level of m1.small is unstable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.paessler.com/blog/2009/04/14/prtg-7/comparing-amazon-ec2-performance-with-other-cloudvps-hosting-options-and-real-hardware/" target="_blank"&gt;Pricing&lt;/a&gt; for high performance instances m1.large and m1.xlarge is not attractive&lt;/li&gt;
&lt;li&gt;No logging for API access&lt;/li&gt;
&lt;li&gt;There is only one way to build hybrid clouds: use a VPN connection to boxes outside the EC2 cluster.&lt;/li&gt;
&lt;li&gt;No control over instances deployment. It may happen that instances will be deployed onto one physical box, but for some applications it's critical to have instances deployed on different boxes. We can specify different regions and geozones for this application, but further control would be desirable.&lt;/li&gt;
&lt;li&gt;Independent namespaces for different regions: each region has its own namespace for keys, AMI, instances, etc.&lt;/li&gt;
&lt;li&gt;Security management isn’t always logical. For example, we can create instance without specifying a key-pair that will be inaccessible via ssh (in those rare cases when we really need it) or we can accidentally have access (and even terminate) instances that belong to the same account, but which were created with other security keys; for example, another development group in the same company.&lt;/li&gt;
&lt;li&gt;Startup time of custom AMI : an instance's pending time can be about 10-15 minutes.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Compared to Amazon EC2, so far GoGrid does not have a big list of different features, but despite their recent entrants to the market, they already have some unique features:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;True hybrids: we can build &lt;a href="http://www.gogrid.com/how-it-works/cloud-connect.php"&gt; hybrid clouds along with colo servers&lt;/a&gt;, which will be located in the same network switch with virtual cloud instances.&lt;/li&gt;
&lt;li&gt;Logging API usage by a &lt;a href="http://wiki.gogrid.com/wiki/index.php/Job_History"&gt;job's history&lt;/a&gt;. Actually, we can monitor all requests to GoGrid’s API.&lt;/li&gt;
&lt;li&gt;Non-transient instances: We can reboot instances without data-loss.&lt;/li&gt;
&lt;/ul&gt;And, as with Amazon EC2, GoGrid has some challenges as well:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The web interface needs to be more user-friendly.&lt;/li&gt;
&lt;li&gt;Using and mounting Cloud Storage is more complex than it is expected and it performs as a local disk drive only in case of low network load.&lt;/li&gt;
&lt;li&gt;Choice of OS is limited only to &lt;a href="http://www.gogrid.com/how-it-works/cloud-server-images.php"&gt;Windows, RedHat and CentOS&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For cloud instances we can choose only RAM size, not different CPU levels. This point can be partially reconciled by using bare metal as part of the cluster infrastructure.&lt;/li&gt;
&lt;li&gt;Practical experience with GoGrid's instances shows that maintenance windows happen more often than anticipated.&lt;/li&gt;
&lt;/ul&gt;Obviously, choosing a cloud infrastructure provider for a particular project should be based on determining which application's requirements will be best fitted for this  cloud provider and which requirement will not be satisfied. Providing hybrid clouds with bare metal boxes can be a unique differentiator, but not all applications really need it. The main promise of cloud computing is 'resources by demand' and this can be delivered by Amazon EC2 more than GoGrid—they provide a wide variety of different infrastructure parameters (such as CPU, RAM, and OS) for instances, they have more users,  and they're currently more experienced as an infrastructure cloud provider.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-5688233876162385817?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/5688233876162385817/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=5688233876162385817" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5688233876162385817?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5688233876162385817?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/I8-dh7yupRs/gogrid-is-out-of-beta.html" title="GoGrid is out of beta" /><author><name>abokov</name><uri>http://www.blogger.com/profile/16164698628747095370</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="16934754117869422020" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/08/gogrid-is-out-of-beta.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQDQXw_fSp7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7957882547102014158</id><published>2009-08-25T03:00:00.000-07:00</published><updated>2009-10-23T08:06:10.245-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:06:10.245-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="~Kirill Shileev" /><category scheme="http://www.blogger.com/atom/ns#" term="Microsoft HPC" /><title>Provisioning in Microsoft HPC</title><content type="html">Suppose you have five machines under your desk and need to establish a small HPC cluster for development from this estate, but you are too lazy to do it manually machine-by-machine. Or even better--you are in charge of a large HPC cluster that has thousands of nodes spanning multiple racks installed in an area over 2000 square meters. Obviously, manual installation is not an option here.&lt;br /&gt;&lt;br /&gt;What to do? The answer is simple: use automatic provisioning. In this post, I'll try to share my recent experience provisioning with &lt;a href="http://www.microsoft.com/hpc/en/us/default.aspx"&gt;Microsoft High Performance Cluster 2008&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Good news: provisioning is an intrinsic feature of HPC 2008, which uses Microsoft &lt;a title="Windows Deployment Server" href="http://technet.microsoft.com/en-us/library/cc766320%28WS.10%29.aspx" id="zagb"&gt;Windows Deployment Server&lt;/a&gt; technology under the hood. WDS is a tool to exploit PXE (Preboot execution environment), which is a "must have" feature of all modern network cards.&lt;br /&gt;&lt;br /&gt;This solution completely shields me from the complexity of WDS. Like many MS products, HPC Cluster manager provides a wizard for creation of a &lt;span style="font-style: italic;"&gt;template&lt;/span&gt;. A template is a central notion of the whole system. It's merely an installation image, bootable over the network, accompanied by a script that does additional steps needed to get a node ready for joining the cluster.&lt;br /&gt;&lt;br /&gt;However, just having an image is rarely sufficient. It allows you to install just the basic OS without anything on top of it, which is usually not what we want. That is where the script comes into play with its ability to execute (almost) arbitrary OS commands, even including executables from the network shares. If one tries to code those commands by hand, it would be somewhere between boring and very boring. Fortunately, HPC cluster manager's designers applied a lot of effort to make things simple. Just follow the wizard and you'll get a fully operational template in almost no time.&lt;br /&gt;&lt;br /&gt;Hey, but what if you wanna add some specifics, something not provided by default? Well, nothing is lost, you can create a default template with the wizard and run the edit tool from the context menu. In the opened editor you can add new commands or delete the existing ones. When the template is ready, you invoke another wizard, which controls the process of installation. The only thing to do is to choose a template and turn on all the machines you want to have installed with this template. Simple.&lt;br /&gt;&lt;br /&gt;Finally, if you don't have an installation image, you may create it from the distribution media by means of another wizard, embedded into HPC Cluster Manager. I'm not sure why this feature's needed, because for years the Microsoft installation media has included the installation images, but it might be valuable for image developers.&lt;br /&gt;&lt;br /&gt;So far so good and it sounds like a magic, but there are some pitfalls I encountered when playing with MS HPC auto-provisioning.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First of all never ever try to run this kind of installation on a network that is not under your control, and first of all, DHCP. Obviously, HPC will need to add a record to DHCP for a new node.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Always use multicast mode when you are dealing with more then one node. It significantly reduces the time to provision, although even with multicast it may take a long time in some cases. In one of my experiments, I tried to provision 3 virtual nodes on the same VMware server with 5 additional VMs running. It took about 150 min on my not-so-old server (Supermicro SuperServer 6015B-UR 2 x XeonE5430 @2.66GHz (Quad-core) 16GB RAM). &lt;/li&gt;&lt;br /&gt;&lt;li&gt;And last but not at all least. Do not use the &lt;i&gt;clusrun&lt;/i&gt; utility in your template scripts. Obviously, commands from a template will be executed on all nodes for which the provisioning is requested. If you try to run clusrun (whose task is to run its argument command on every nodes in cluster) on each node , you may get an unpredictable result.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;All in all, Microsoft HPC implements a PXE style deployment in a comfortable way, allowing you to do this task without serious troubleshooting.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7957882547102014158?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7957882547102014158/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7957882547102014158" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7957882547102014158?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7957882547102014158?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/rg_bBfxmhE4/provisioning-in-microsoft-hpc.html" title="Provisioning in Microsoft HPC" /><author><name>Kirill Shileev</name><uri>http://www.blogger.com/profile/18292784177481663496</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02051345241709398853" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/08/provisioning-in-microsoft-hpc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQHo-fSp7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-478854449598984663</id><published>2009-08-19T03:02:00.000-07:00</published><updated>2009-10-23T08:09:21.455-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:09:21.455-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="gogrid" /><category scheme="http://www.blogger.com/atom/ns#" term="~Roman Bogorodskiy" /><title>GoGrid Management Tools and Library</title><content type="html">When we started working with GoGrid, we began using the web interface at my.gogrid.com. It's done pretty well -- powerful and user-friendly. However, after some time we decided to implement our own set of tools -- fortunately, GoGrid provides a great designed API -- for the following reasons:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;While the UI is good, it has no facilities for automating things. For instance, if you need to create several servers of the same configuration using the web interface you have to create all the servers manually one-by-one, while using gg-tools, you can do something like this:&lt;br /&gt;&lt;br /&gt;   &lt;code&gt;for i in `seq 5`; do gg-server-add -i 10 -r 2GB -n server$i; done&lt;/code&gt;&lt;br /&gt;&lt;br /&gt; To create 5 servers with names like server1, server2, ..., server5 of the same configuration.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;gg tools allow you to use all the power of the Unix command line. For example, if you need a password for server with ip, say 192.168.0.1, you can do:&lt;br /&gt;&lt;br /&gt;   &lt;code&gt;gg-password | grep 192.168.0.1&lt;/code&gt;&lt;br /&gt;&lt;br /&gt; and you will see the password for the required server right on your screen instead of searching in a long list of passwords and servers in the UI.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;With the GoGrid UI, you have to remember your login and password. If you're using gg tools, you can configure it once and then do not have to type logins and passwords all the time. If you have it installed on a *nix box with ssh access, you can use it from every place where you have ssh client configured.&lt;/li&gt;&lt;/ul&gt;Initially, gg tools started as a few Python scripts to start, bootstrap and shut down servers. After working with these scripts they have grown pretty quickly and we decided it would make sense to split the bootstrap functionality and provide general tools for GoGrid management. Later on it turned out it would make sense to re-organize the code one more time and split out a general library that could be used not only by gg tools, but any project that needs to control GoGrid.&lt;br /&gt;&lt;br /&gt;As a result, now we have a GoGridManager -- a Python module that supports almost all operations provided by the GoGrid API and gg tools -- a set of CLI tools that use GoGridManager.&lt;br /&gt;&lt;br /&gt;GoGridManager is also quite easy to use. Here's a basic example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(11:53) novel@hybrid:~/zf0 %&gt; python&lt;br /&gt;Python 2.5.2 (r252:60911, Oct  5 2008, 19:24:49)&lt;br /&gt;[GCC 4.3.2] on linux2&lt;br /&gt;Type "help", "copyright", "credits" or "license" for more information.&lt;br /&gt;&gt;&gt;&gt; from GoGridManager import GoGridManager&lt;br /&gt;&gt;&gt;&gt; manager = GoGridManager()&lt;br /&gt;&gt;&gt;&gt; server = manager.get_servers()[0]&lt;br /&gt;&gt;&gt;&gt; print server&lt;br /&gt;server my_go_grid (id = 28940, descr = , state = Started, ip = 173.1.54.221)&lt;br /&gt;&gt;&gt;&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We have been working for almost half a year now with GoGrid and for many months gg tools has become an everyday tool for us. Recently it was rewritten to use XML responses&lt;br /&gt;from the API and MyGSI support has been added. However, there is a lot of work left to do. For example, Load Balancer API calls are not implemented yet, as we haven't use it so far and&lt;br /&gt;for example, Job and Billing support could be better.&lt;br /&gt;&lt;br /&gt;Check GG Tools out on &lt;a href="http://github.com/novel/gg/tree/master"&gt;http://github.com/novel/gg/tree/master&lt;/a&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;Further reading:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://wiki.gogrid.com/wiki/index.php/API"&gt;http://wiki.gogrid.com/wiki/index.php/API&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.gogrid.com/wiki/index.php/MyGSI"&gt;http://wiki.gogrid.com/wiki/index.php/MyGSI&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-478854449598984663?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/478854449598984663/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=478854449598984663" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/478854449598984663?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/478854449598984663?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/4UdfnMvabfA/gogrid-management-tools-and-library.html" title="GoGrid Management Tools and Library" /><author><name>empt1e</name><uri>http://www.blogger.com/profile/05480927125413977720</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10164089692579906587" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/08/gogrid-management-tools-and-library.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAMQXkzeCp7ImA9WxNSEkw.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1204187433217875726</id><published>2009-07-13T03:17:00.001-07:00</published><updated>2009-08-25T08:06:20.780-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-25T08:06:20.780-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="LDAP" /><category scheme="http://www.blogger.com/atom/ns#" term="~Dmitry Korotkov" /><title>OpenLDAP perfomance testing</title><content type="html">&lt;h4&gt;Introduction&lt;/h4&gt;Our team is working on the metadata repository for a large-scale grid file storage project. This repository should make grid storage searchable and browseable. Since grid storage is presumed to store huge amounts of data, metadata repository should be able to store large amounts of metadata as well.&lt;br /&gt;&lt;br /&gt;In our solution the metadata is typed, heterogeneous and has a hierarchical structure; metadata storage should be searchable, replicated and scalable. Also, we have strict requirements for new entry types to be definable at runtime. Taking these considerations into account, we chose to push for a LDAP-based solution. Since we had a requirement not to be tied to any particular vendor, OpenLDAP was a natural choice.&lt;br /&gt;&lt;br /&gt;We've made a number of OpenLDAP performance tests to examine how OpenLDAP worked with large numbers of entries. Below, we will share some of the results we've achieved. We do not dive deeply into details of the testing machine configuration, since absolute timing values do not give many data points when you are trying to evaluate scalability of the solution. Trends, in this particular case with regards to the time consumed, are much more important.&lt;br /&gt;&lt;br /&gt;The benchmarking stand can be described as a single-core Linux box using OpenLDAP version 2.4.16 (the latest at the moment of testing). OpenLDAP was built from the sources, as is &lt;a href="http://www.openldap.org/faq/data/cache/1456.html"&gt;recommended&lt;/a&gt; by the OpenLDAP documentation. OpenLDAP native HDB  (based on Berkeley DB database with hierarchical database layout that supports subtree renames) was used as the database backend. All tests were performed by connecting to the OpenLDAP server through the loopback interface (127.0.0.1) to eliminate the impact of network bandwidth saturation.&lt;br /&gt;&lt;br /&gt;For read performance measurements we used three LDAP entry attributes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;dn (distinguished name) - distinguished name of the LDAP entry, identifying an entry and its location.&lt;/li&gt;&lt;li&gt;cn (common name) - general string attribute of the LDAP entry.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;entryUUID - builtin, server-maintained unique entry identifier. It remains unchanged when entry is being moved from one subtree into another on the contrary to dn, which is being changed.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Directory reading&lt;/h4&gt;Generally speaking, OpenLDAP finds an entry using an index much faster than delivering an entry client through the network. A more interesting case is how OpenLDAP handles concurrent reads and writes with regards to the number of clients.&lt;br /&gt;&lt;h5&gt;Test I. Concurrent reading&lt;/h5&gt; The case: the OpenLDAP directory consists of a flat list of about 100K entries indexed by cn. Each client sequentially queries 1000 random existing entries by dn, cn and entryUUID. A number of clients (1 - 20) are executed simultaneously. Three curves on the graph show total time with regards to the number of concurrent clients in three different scenarios:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;search by dn;&lt;/li&gt;&lt;li&gt;searching by cn;&lt;/li&gt;&lt;li&gt;search by entryUUID.&lt;/li&gt;&lt;/ul&gt;Testing results are shown in two charts, containing absolute timing values and normalized by dividing timing value by the number of concurrent clients.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9g8QFmHJL_E/SlsW0BL4jGI/AAAAAAAAAIA/SvV2uCqvCIg/s1600-h/Test-1-2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://2.bp.blogspot.com/_9g8QFmHJL_E/SlsW0BL4jGI/AAAAAAAAAIA/SvV2uCqvCIg/s400/Test-1-2.png" alt="" id="BLOGGER_PHOTO_ID_5357901264614624354" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9g8QFmHJL_E/SlsWzr0yASI/AAAAAAAAAH4/UVbI7BHMxC0/s1600-h/Test-1-1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://2.bp.blogspot.com/_9g8QFmHJL_E/SlsWzr0yASI/AAAAAAAAAH4/UVbI7BHMxC0/s400/Test-1-1.png" alt="" id="BLOGGER_PHOTO_ID_5357901258880581922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Searching without indices was not tested because it is too slow on big data sets. As we can see, searching by distinguished name takes much less time than searching among children of the parent by indexed attribute. Another conclusion is that it is better to avoid searching by entryUUID despite the convenience of this attribute.&lt;br /&gt;&lt;h4&gt;Directory reading combined with writing&lt;/h4&gt;&lt;h5&gt;Test II. Concurrent reading &amp;amp; writing&lt;/h5&gt;The case: the OpenLDAP directory consists of a flat list of about 100K entries. Each client sequentially performs 1000 requests. Each request is a read of a random existing entry by dn or by creating a new one. Three cases were tested: 99.9%, 99.0% and 90.0% of read operations against the corresponding number of write operations. A number of clients (1 - 20) were executed simultaneously.&lt;br /&gt;&lt;br /&gt;So, we have three curves showing total time with regards to the number of concurrent clients in three different scenarios:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;99.9% reads; 0.01% writes;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;99.0% reads; 1% writes;&lt;/li&gt;&lt;li&gt;90.0% reads; 10% writes.&lt;/li&gt;&lt;/ul&gt;Testing results are shown in two charts, containing absolute timing values and normalized by dividing timing value by the number of concurrent clients.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9g8QFmHJL_E/Slsbrt9l00I/AAAAAAAAAIQ/JQdxRA1HEpM/s1600-h/Test-2-2.png" style="text-decoration: none;"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://1.bp.blogspot.com/_9g8QFmHJL_E/Slsbrt9l00I/AAAAAAAAAIQ/JQdxRA1HEpM/s400/Test-2-2.png" alt="" id="BLOGGER_PHOTO_ID_5357906619573588802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238);"&gt;&lt;span class="Apple-style-span" style="text-decoration: underline;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 0);"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_9g8QFmHJL_E/SlsbrUC4NoI/AAAAAAAAAII/QyW9p9dsTMU/s1600-h/Test-2-1.png"&gt;&lt;img src="http://3.bp.blogspot.com/_9g8QFmHJL_E/SlsbrUC4NoI/AAAAAAAAAII/QyW9p9dsTMU/s400/Test-2-1.png" alt="" id="BLOGGER_PHOTO_ID_5357906612616443522" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;These data contradict the OpenLDAP 2.1.21 measurements of Andreas Krennmair and Rainer Lischka (&lt;span class="nobr"&gt;&lt;a href="http://www.lizenzfrei.at/downloads/ldap-paper.pdf" rel="nofollow"&gt;http://www.lizenzfrei.at/downloads/ldap-paper.pdf&lt;/a&gt;&lt;/span&gt;), where time consumption grows linearly depending on the number of concurrent clients. Moreover, there is no big difference between 90%-read and 99.9%-read curves. So, we can say that OpenLDAP performance has been significantly improved since version 2.1.21.&lt;br /&gt;&lt;h4&gt;Directory writing&lt;/h4&gt;&lt;h5&gt;Test III. Directory writing with indices&lt;/h5&gt;The case: the OpenLDAP directory is empty in the beginning of the test. It is indexed by cn and objectClass. A single client uploads bunches of 100 entries at a time under one particular parent and measures the time of each bunch upload. After 50 000 entries were uploaded, the client uploads 50 000 entries under another parent in the same manner. Then the directory contents are erased and 50 000 entries are uploaded in bunches of 100 entries at a time. Each bunch is stored under a different randomly named parent. So, we have three curves:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Upload under first parent depending on the number of entries already existing under this parent.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Upload under second parent depending on the number of entries already present under this parent (not regarding 50K entries that exist under first parent already).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Upload under different parents depending on the total number of entries in directory tree.&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9g8QFmHJL_E/Slser5YUBjI/AAAAAAAAAIY/_i0iUC1vWkk/s1600-h/Test-3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://1.bp.blogspot.com/_9g8QFmHJL_E/Slser5YUBjI/AAAAAAAAAIY/_i0iUC1vWkk/s400/Test-3.png" alt="" id="BLOGGER_PHOTO_ID_5357909921173341746" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Obviously, storing data as a tree is preferable to storing data as a flat list, because it is 2-3 times faster.&lt;br /&gt;&lt;h5&gt;Test IV. Directory writing without indices&lt;/h5&gt;The case: the OpenLDAP directory is empty in the beginning of the test. It is not indexed at all. A single client uploads bunches of 100 entries at a time under one particular parent and measures the time of each bunch upload. After 50 000 entries were uploaded, the client uploads 50 000 entries under another parent in the same manner. So, we have two curves:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Upload under first parent.&lt;/li&gt;&lt;li&gt;Upload under second parent.&lt;/li&gt;&lt;/ul&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9g8QFmHJL_E/Slsf9u0827I/AAAAAAAAAIg/JnPJn4JVYHw/s1600-h/Test-4.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://4.bp.blogspot.com/_9g8QFmHJL_E/Slsf9u0827I/AAAAAAAAAIg/JnPJn4JVYHw/s400/Test-4.png" alt="" id="BLOGGER_PHOTO_ID_5357911327089941426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As we can see, the children count of one parent merely affects the creation time of objects under another parent. But while creating objects under one particular parent, object creation time grows depending on the number of children of the parent. This proves the conclusion, made in Test III, that storing data as a tree is preferable to storing data as a flat list.&lt;br /&gt;&lt;h5&gt;Test V. Lots of objects created with and without indices&lt;/h5&gt;The case: the OpenLDAP directory is empty in the beginning of the test. It is not indexed at all. A single client uploads bunches of 1000 entries at a time under different parents and measures the time of each bunch upload. After 500 000 entries were uploaded, directory content is erased, indices on cn and objectClass are added and 500 000 entries are uploaded in the same manner. So, we have two curves:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Upload without indices.&lt;/li&gt;&lt;li&gt;Upload with indices.&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9g8QFmHJL_E/SlsjI8fcoEI/AAAAAAAAAIw/CwWryzqakYg/s1600-h/Test-5.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://1.bp.blogspot.com/_9g8QFmHJL_E/SlsjI8fcoEI/AAAAAAAAAIw/CwWryzqakYg/s400/Test-5.png" alt="" id="BLOGGER_PHOTO_ID_5357914818271289410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;As we can see, indexed and non-indexed directory write performances become similar on big directory sizes.&lt;br /&gt;&lt;h4&gt;Dynamic schema extending&lt;/h4&gt;&lt;h5&gt;Test VI. LDAP schema writing&lt;/h5&gt;The case: the OpenLDAP directory is empty. The OpenLDAP schema is the default core schema. A single client creates object classes using a ldapmodify operation. Each operation adds 100 object classes. Each operation execution time is measured.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9g8QFmHJL_E/SlskWccN8aI/AAAAAAAAAI4/lD7RF-b6og4/s1600-h/Test-6.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 208px;" src="http://4.bp.blogspot.com/_9g8QFmHJL_E/SlskWccN8aI/AAAAAAAAAI4/lD7RF-b6og4/s400/Test-6.png" alt="" id="BLOGGER_PHOTO_ID_5357916149697606050" border="0" /&gt;&lt;/a&gt;As we can see, the time to extend the schema grows linearly with regards to the total number of objectClass entries. This may be a bottleneck in LDAP system scalability, because the directory tree may be replicated, clustered some way, but it is impossible to split the LDAP schema into parts. But there is some good news: objectClass creation does not depends on directory data size. (This test gives exactly the same results on an empty directory and on a directory filled with 100 000 objects.)&lt;br /&gt;&lt;h4&gt;Conclusion&lt;/h4&gt;In our performance tests OpenLDAP has shown pretty good results in most test cases. We were glad to see dramatic concurrent writing performance improvement since version 2.1. But there are still a couple of issues with the current version.&lt;br /&gt;&lt;br /&gt;First, the OpenLDAP client developer always faces a dilemma: either to use DN for identifying an entry and face the risk of losing renamed or moved entries, or to use entryUUID for identifying an entry and get much lower performance. It looks like it is very hard to solve this problem due to the distributed directory tree structure.&lt;br /&gt;&lt;br /&gt;The second and the most important issue is poor performance of dynamic LDAP schema extension. Also, the slapd daemon starts very slowly when the directory schema contains 10K objectClasses, even with slaptest disabled. (On our test machine OpenLDAP startup took several minutes with slaptest disabled and 10K objectClasses in the schema.)&lt;br /&gt;&lt;br /&gt;We are eagerly awaiting schema management performance improvements in the future releases.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1204187433217875726?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1204187433217875726/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1204187433217875726" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1204187433217875726?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1204187433217875726?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/Pr1me4D2yW8/openldap-perfomance-testing.html" title="OpenLDAP perfomance testing" /><author><name>Dmitry Korotkov</name><uri>http://www.blogger.com/profile/07023646962814250784</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="08149820018584167276" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_9g8QFmHJL_E/SlsW0BL4jGI/AAAAAAAAAIA/SvV2uCqvCIg/s72-c/Test-1-2.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/07/openldap-perfomance-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQHo9eip7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-3870382272773649304</id><published>2009-05-18T04:19:00.000-07:00</published><updated>2009-10-23T08:09:21.462-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:09:21.462-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gemfire" /><category scheme="http://www.blogger.com/atom/ns#" term="data aware routing" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="Sun Grid Engine" /><category scheme="http://www.blogger.com/atom/ns#" term="convergence" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Data-Aware Routing on a Cloud, featuring Sun Grid Engine, GemFire and EC2</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_CQV12Vs8lZ0/ShFOS2t-TII/AAAAAAAAIGQ/2VNtsMtvZrU/s1600-h/demo-screen2.png"&gt;&lt;/a&gt;&lt;p class="MsoNormal"&gt;We are excited to announce that we have taken our Convergence project to the next step in the last few weeks. &lt;a href="http://blog.griddynamics.com/2008/02/data-aware-routing-datasynapse_14.html"&gt;Last time&lt;/a&gt; we demonstrated how data aware routing can speed up the combination of compute grids and data grids. Since then, we have developed new grid adapters for our Convergence project and moved to the cloud.&lt;/p&gt;&lt;p style="font-weight: bold;" class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;New adapters: Sun Grid Engine, GemFire&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a href="http://www.sun.com/software/sge/"&gt;Sun Grid Engine&lt;/a&gt; (SGE) is an open source batch-queuing system, developed and supported by Sun Microsystems. SGE is typically used in a server farm or high-performance computing (HPC) cluster and is responsible for accepting, scheduling, dispatching, and managing the remote and distributed execution of large numbers of standalone, parallel or interactive user jobs. It also manages and schedules the allocation of distributed resources such as processors, memory, disk space, and software licenses. We have developed an adapter that wraps SGE's Java API and enables data aware routing of tasks.&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;a href="http://www.gemstone.com/products/gemfire/"&gt;GemFire&lt;/a&gt; is an Enterprise Data Fabric (EDF) solution from GemStone Systems, Inc. It is a high performance, distributed in-memory-data-grid (IMDG) that offers very low latency, high resiliency, scalability and high throughput data sharing and event distribution features for high performance computing applications that need access to real-time data. We have developed a monitor component, which can query location of data from GemFire regions with partitioned schema.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-weight: bold;" class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Running on the cloud&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Along with integrating new grids, we changed our demo application to use a cloud infrastructure. It is deployed now on Amazon EC2. Our demo now allocates servers, completes setup of cluster software (SGE and GemFire in this case) and starts the demo application server on the fly. Just a single click and few minutes later you will have a new cluster up and running.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The deployment process is straightforward and requires just a couple of scripts. First, we allocate one EC2 server and start the master node. When the master is started, it starts allocating worker nodes and sets up the grid software. When the cluster setup is complete, we start the demo control UI on the master node, and from that moment our interactive data aware routing demo is available. Each cluster has a time to live, and when its lifespan expires, all servers are returned to EC2. We are using OpenSolaris AMI, provided by Sun Microsystems, for all our servers. Deployment of GemFire is trivial --we just need to copy few jars. Installing SGE has its quirks, but after we have figured out how to do it correctly, it just works.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;From a usability point of view, cloud hosting has huge benefits. Each developer can work with his own cluster, or even several clusters (e.g., comparing the effects of data aware routing between clusters of different size).&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="font-weight: bold;" class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Data-aware routing demo&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;W&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;e have adapted our existing demo application to work with new grids and be scalable on a cloud. In our demo application we are simulating a financial application. We have a set of trade objects, which are loaded into a partitioned GemFire region. 50k objects are placed on each server (size of each object is about 2Kb). Those trades belong to different equal-sized books (5K trades in each book). The job here is to evaluate all books using Sun Grid Engine to distribute work across cluster nodes. This means that a job consists of 10*(number of servers) tasks and each task should fetch 5K trades (about 10MB of data) from the data grid and perform some calculation over them. For simplicity, we just sum the IDs of the trades and return the result.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;U&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;nlike DataSynapse GridServer, SGE is a process-oriented computational grid. Each task in SGE is an operating system process, and execution time includes all JVM startup and class loading overheads. Usually tasks are long enough, and process start up time does not make much difference, but in the case of an interactive demo we should find a balance. We cannot make the user wait half an hour to see the first result, but if we make tasks too short, the effect of data aware routing will not be visible due to JVM startup overheads.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;" href="http://1.bp.blogspot.com/_CQV12Vs8lZ0/ShFOS2t-TII/AAAAAAAAIGQ/2VNtsMtvZrU/s1600-h/demo-screen2.png"&gt;&lt;img style="margin: 0px auto 10px; text-align: center; width: 400px; display: block; height: 281px; cursor: pointer; text-decoration: underline;" id="BLOGGER_PHOTO_ID_5337133119243701378" alt="" src="http://1.bp.blogspot.com/_CQV12Vs8lZ0/ShFOS2t-TII/AAAAAAAAIGQ/2VNtsMtvZrU/s400/demo-screen2.png" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;span style="color: rgb(0, 0, 0);" class="Apple-style-span"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The demo runs a constant flow of jobs and constantly measures job completion latency and task completion latency. To illustrate data aware routing advantages we introduced 3 different scheduling modes. “Data aware” mode is where we perform data aware routing, ensuring local space access for the engine. “Neutral” mode is where we do unguided DS scheduling &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;as SGE sees fit. “Anti data aware” mode is where we deliberately violate data awareness and ensure network space access. The user can change the task scheduling mode on the fly and see the impact of the scheduling mode on performance.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The diagram on the left shows the completion time of the job and small gray bars show cumulative task execution time on each server in cluster. Gray bars do not include JVM start up time, so cumulative execution time on each server is considerably smaller then job execution time.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The diagram on the right shows average task completion latency (without JVM startup time), so you can see effect of data aware routing on task and job level.&lt;/span&gt;&lt;/p&gt;&lt;div style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Conclusion&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;We have demonstrated how a generic data-aware routing approach implemented in the Convergence project can be used with different grid products. We had a very good experience migrating our research/demo platform to the cloud. Using a cloud provided us flexibility and comfort of development, which are hard to achieve in traditional resource constraint environment.&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Stay tuned for more advances in the Convergence project!&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-3870382272773649304?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/3870382272773649304/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=3870382272773649304" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/3870382272773649304?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/3870382272773649304?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/HPcuswsh-3g/data-aware-routing-gemstone-gemfire-and.html" title="Data-Aware Routing on a Cloud, featuring Sun Grid Engine, GemFire and EC2" /><author><name>Alexey Ragozin</name><uri>http://www.blogger.com/profile/13720493857045012756</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="03800576285958180449" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_CQV12Vs8lZ0/ShFOS2t-TII/AAAAAAAAIGQ/2VNtsMtvZrU/s72-c/demo-screen2.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/05/data-aware-routing-gemstone-gemfire-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEAR38-cSp7ImA9WxJRF0g.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1628332447054810167</id><published>2009-05-05T09:50:00.000-07:00</published><updated>2009-05-19T10:20:46.159-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-19T10:20:46.159-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="hpc" /><category scheme="http://www.blogger.com/atom/ns#" term="Waters" /><category scheme="http://www.blogger.com/atom/ns#" term="Microsoft HPC" /><category scheme="http://www.blogger.com/atom/ns#" term="Conference" /><category scheme="http://www.blogger.com/atom/ns#" term="~Shravan Kumar" /><title>Waters Power 2009 Conference</title><content type="html">Grid Dynamics was one of the sponsors for Incisive Media's &lt;a href="http://web.incisive-events.com/fit/2009/04/waters-power/"&gt;Waters Power 2009 event&lt;/a&gt; that was held in New York City. Main agenda of the conference was to showcase the most up-to date developments in HPC with in-depth analysis of cloud computing, virtualization and SOA solutions, bringing the latest strategies, techniques and technologies that give optimum performance and maximum efficiency for any data center. Major HPC vendors and many wall street firms were represented at the conference&lt;br /&gt;&lt;br /&gt;Key note speech was presented by Jeffrey Birnbaum from Merrill Lynch. It was a well presented speech that highlighted the opportunities, challenges and approaches of cloud computing for HPC. Highlights from his speech are&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Main attraction of cloud computing is to drive the cost of computing down. Google and Amazon had done a good job getting the cost pretty low. How can the enterprises do the same, or come close?&lt;/li&gt;&lt;li&gt;Most cloud providers like Amazon, Google etc. are GbE Based. Everyone is moving towards 10GbE and this serves as foundation for viable clouds&lt;/li&gt;&lt;li&gt;Enterprise cloud infrastructure needs a global file system. All software is installed on that file system. This makes it simple for the end users, in order to run any compute environment - just mount a file system&lt;/li&gt;&lt;li&gt;In order to get global scalability - use multiple copies of the files&lt;/li&gt;&lt;li&gt;Replicate the files in real-time on any update. It might be better to wait on update than deal with eventual consistency&lt;/li&gt;&lt;li&gt;For better performance cache the files in regional locations&lt;/li&gt;&lt;li&gt;Do not provide node-level redundancy and increase the cost of hardware, buy commodity hardware and design for failure. Route the workload from a node that failed to some available node (like what Google and Amazon do)&lt;/li&gt;&lt;li&gt;Design Data Centers around PODs connected by layer-2, not layer-3.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;Technologies that will change the world,&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Multi-core/multi-socket commodity compute nodes (run more VMs, writing more parallel code)&lt;/li&gt;&lt;li&gt;10GbE with iWARP or RDMA (lower latency to storage)&lt;/li&gt;&lt;li&gt;Flash-based storage at 200K IOPS (totally changes how you think about the problems)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br /&gt;Implications of the above changes are dramatic and will affect the way we design the Data Centers and Applications&lt;br /&gt;&lt;br /&gt;There was a Panel Discussion about "A silver lining for cloud computing". Panel included Victoria Livschitz, Founder and CEO of Grid Dynamics. Questions asked by the moderator triggered insightful discussions and sometimes contradicting answers,&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Define cloud computing? This is probably most asked question in cloud computing forums and glad to hear we are closing in on a definition. This brought up another question about what stage of technology maturity is cloud computing in. Victoria's response to this was that it is in really early stages and it will take about 5 yrs to be mature enough for enterprise adoption&lt;br /&gt;&lt;/li&gt;&lt;li&gt;What applications are not suitable for cloud computing? It was acknowledged by few panel members that low latency applications may be bad candidates before cloud infrastructure matures but one speaker thought that this is up to the design of the cloud and it is possible to host low latency applications if architected well&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An interesting conversation that came up is when cloud will get more adoption. This is same question that keeps coming up when any new technology comes into light. Old companies with huge investments in the existing infrastructure and approaches will need to spend more time adopting while newer players will benefit from them much sooner&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Victoria made an insightful argument about the way applications were designed and implemented, this was about the data and its ownership. Most of the applications now are designed with data ownership as the premise but the promise of consuming and providing data as a service has many opportunities. For e.g., cloud computing is making infrastructure, software and computation as a service and having data also as a consumable entity gives the applications unbound possibilities &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The thoughts about the data ownership and promise of being able to consume this as a service were echoed by few other speakers in later discussions&lt;br /&gt;&lt;br /&gt;Ken Michellini's (from CitiHub) speech about "Keeping your feet on the ground: Unveiling the truth about cloud computing" was educational. It talked about the ROI calculations in a public cloud, 3rd party hosted and internal cloud scenarios and gave some ideas on how you can make these decisions when building your next big application. He also talked about characteristics of a good cloud application and typical challenges in building cloud applications.&lt;br /&gt;&lt;br /&gt;There were few more Panel discussions that we attended including "Building the 21st century data center", "Preparing for Next phase in grid computing: What it takes to build the perfect data grid" and "Virtual reality: Optimizing storage, application and network virtualization" and another presentation about real life lessons learned while administering grids "Nuts and Bolts: Practical issues in grid administration"&lt;br /&gt;&lt;br /&gt;I would like to extend congratulations to Incisive Media for a well conducted conference that let many financial industry experts brain storm and discuss the opportunities of Cloud. Great job guys!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1628332447054810167?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1628332447054810167/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1628332447054810167" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1628332447054810167?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1628332447054810167?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/g-u1ADPNv7Y/waters-power-2009-conference_05.html" title="Waters Power 2009 Conference" /><author><name>Shravan (Sean) Kumar</name><uri>http://www.blogger.com/profile/09712909110035296320</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09230803115972803308" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/05/waters-power-2009-conference_05.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4CSX0-eip7ImA9WxVXEkU.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-5063298488428032343</id><published>2009-02-09T22:39:00.000-08:00</published><updated>2009-02-10T08:22:48.352-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-10T08:22:48.352-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="distributed cache" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Kharlamov" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><title>Full-text &amp; faceted search over In-Memory Data Grids</title><content type="html">Modern in-memory data grid (IMDG) solutions provide different facilities for execution of queries over whole stored data sets with different levels of sophistication. &lt;a href="http://www.oracle.com/technology/products/coherence/index.html"&gt;Oracle Coherence&lt;/a&gt; provides Query facilities (one time full scan and continuous querying with Cost-Based-Optimized). &lt;a href="http://www.gigaspaces.com/"&gt;GigaSpaces&lt;/a&gt; has a JDBC Query interface with the ability to use hash and B-Tree indexes. Those solutions work quite well for many problem areas. However, for heavy loads and complex multi-criteria queries those facilities can quickly become a bottleneck.&lt;br /&gt;&lt;br /&gt;There is a  class of workloads that produce high loads with complex queries on IMDGs. Retail companies that use IMDGs for their item catalogs are a good example. Those catalogs are hit by diverse stream of multi-criteria queries. A typical query you may see there looks like:&lt;br /&gt;&lt;blockquote&gt;give me cell phones with MP3 support, Java and in red color.&lt;/blockquote&gt;&lt;br /&gt;Fortunately, the &lt;a href="http://www.compass-project.org/"&gt;Compass Framework&lt;/a&gt; allows you to process such queries effectively. You can build inverse indexes with &lt;a href="http://lucene.apache.org/java/docs/"&gt;Apache Lucene&lt;/a&gt; and store them on a grid. This capability is based on the very modular design of the Lucene framework. All index I/O operations are well-hidden by the abstraction of FileDirectory.&lt;br /&gt;&lt;br /&gt;For now Compass provides implementations for Coherence, GigaSpaces and &lt;a href="http://www.terracotta.org/"&gt;Terracotta&lt;/a&gt;, introducing an unprecedented ability to build a vertical search solution on top of In-Memory Data Grids.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aTVQwIbMAHo/SY8yqV_ej-I/AAAAAAAAAk8/c-1ElxpXAqM/s1600-h/Compass+IMDG.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 142px;" src="http://1.bp.blogspot.com/_aTVQwIbMAHo/SY8yqV_ej-I/AAAAAAAAAk8/c-1ElxpXAqM/s320/Compass+IMDG.png" alt="" id="BLOGGER_PHOTO_ID_5300510989477646306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;In addition, Compass has a sophisticated object-to-document mapping system that allows you to make stored objects searchable just by adding Java annotations or XML mapping files. Mappings can also be built in runtime.&lt;br /&gt;&lt;br /&gt;However, despite its great codebase, Compass documentation is pretty sparse. It may take significant time to dive into the code and docs to get what you want. But the results will overcome all your expectations. Search engine performance on top of data grids easily overcomes any old-generation search technology.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Enjoy!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-5063298488428032343?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/5063298488428032343/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=5063298488428032343" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5063298488428032343?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5063298488428032343?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/HVkEK1k_iaQ/full-text-faceted-search-over-in-memory.html" title="Full-text &amp; faceted search over In-Memory Data Grids" /><author><name>Gurney</name><uri>http://www.blogger.com/profile/09326323020559522679</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01349825872338679018" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_aTVQwIbMAHo/SY8yqV_ej-I/AAAAAAAAAk8/c-1ElxpXAqM/s72-c/Compass+IMDG.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2009/02/full-text-faceted-search-over-in-memory.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcMRXs8eCp7ImA9WxRaGUg.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-2683915723008575189</id><published>2008-12-22T00:57:00.000-08:00</published><updated>2008-12-22T05:54:44.570-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-22T05:54:44.570-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Velocity" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="~Max Martynov" /><category scheme="http://www.blogger.com/atom/ns#" term="Microsoft HPC" /><category scheme="http://www.blogger.com/atom/ns#" term="distributed cache" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><title>Speeding up data-intensive HPC applications with Velocity</title><content type="html">Massively parallel, data intensive applications that run on computer grids require timely access to their data. When the application data is distributed among the grid nodes, data access is not a problem because it scales along with the number of computational task. However, when the application data is stored in a centralized database, access to data can quickly become a serious bottleneck.&lt;br /&gt;&lt;br /&gt;We encountered such a problem in one of our recent projects, where a single database was used as a centralized application data repository for the entire compute grid. In this case, access to application data became bogged down enough to cause an overall degradation of the system performance, despite the fact that the database was being hosted on sufficiently powerful server.&lt;br /&gt;&lt;br /&gt;In this article we will describe different ways of reducing database load and how they affect the overall system performance. We will also explore the advantages and disadvantages of &lt;a href="http://msdn.microsoft.com/en-us/data/cc655792.aspx"&gt;Velocity&lt;/a&gt; as one of the ways to reduce data access latency. More specifically, we will show that:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Database load can be reduced by introducing Velocity distributed cache, or by simplifying SQL queries with moving all calculations from SQL to application logic.&lt;/li&gt;&lt;li&gt;Velocity CTP1 distributed cache improves overall system performance dramatically. In our case, querying data with active Velocity cache was up to 31 times faster than without it!&lt;/li&gt;&lt;li&gt;In CTP1, we experienced some scalability issues in particular configurations, but we are confident these issues will be resolved in future releases.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Compute Environment Overview&lt;/span&gt;&lt;br /&gt;&lt;a href="http://labs.microsofthpc.net/"&gt;HPC++ CompFin Labs&lt;/a&gt; is a compute cloud that was created to give university students the ability to run massive analytical financial computations.&lt;br /&gt;&lt;br /&gt;When a computation needs to be performed, one has to create a custom computational model that defines how the calculation will be performed and how the resulting data will be handled. The computational model operates in accordance with the MapReduce paradigm and includes an Excel-based UI with a list of input parameters, and the .NET assembly with the logic for splitting the computation into tasks, running a single task (map task) and combining task results into computation results (reduce task).&lt;br /&gt;&lt;br /&gt;For example, one may write a model that performs some statistical calculation for a given stock symbol over some period of time. Later, someone else can open the Excel UI, change the stock symbol and the time period, and re-run the calculation. The following diagram illustrates how the example model would work in a CompFin cloud:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU9tu0y2e9I/AAAAAAAAABg/L4ZR7dvDJvA/s1600-h/CompFinArchitecture.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 379px;" src="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU9tu0y2e9I/AAAAAAAAABg/L4ZR7dvDJvA/s800/CompFinArchitecture.png" alt="" id="BLOGGER_PHOTO_ID_5282561539142220754" border="0" /&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 1. Original CompFin&lt;/span&gt;&lt;/p&gt;The system consists from the following components:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A &lt;a href="http://www.blogger.com/www.microsoft.com/HPC/"&gt;Microsoft HPC Server 2008&lt;/a&gt; cluster.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;A Sharepoint Server, where the CompFin website and the computational model files are hosted.&lt;/li&gt;&lt;li&gt;A SQL Server, where computation results are stored.&lt;/li&gt;&lt;li&gt;A SQL Server Intermediate Storage Provider (ISP), where task results are stored for subsequent consumption in the “reduce” phase.&lt;/li&gt;&lt;li&gt;A centralized market data database, where all financial data is located.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The computation proceeds as follows:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The user navigates to the CompFin website. On this website, the user chooses the model to run and opens the appropriate Excel file. Next, the user fills in the required computation parameters and, with CompFin Excel plug-in, submits the job.&lt;/li&gt;&lt;li&gt;The job start request is handled by the CompFin web service, which typically runs on the Sharepoint server as well. This web service calls the model logic to split the computation into tasks.&lt;/li&gt;&lt;li&gt;All computational tasks are submitted to the Microsoft HPC Cluster.&lt;/li&gt;&lt;li&gt;The map tasks are started first. Each task retrieves appropriate data from central market database, performs calculations on this data, and submits intermediate results in the SQL Server ISP.&lt;/li&gt;&lt;li&gt;When all map tasks are finished, the reduce task is launched. It retrieves intermediate data, combines it into final results data, and stores final results into the result storage.&lt;/li&gt;&lt;li&gt;After the computation is finished, the user may request job results via the CompFin website.&lt;/li&gt;&lt;li&gt;The computation results are retrieved from the result storage and returned to the user.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;The above compute grid uses one SQL Server database for storage of stock prices, and one SQL Server database for storage of intermediate and final results. The combined compute capacity of the HPC compute cluster is 400GB of RAM and 200 (2.00GHz) Xeon cores, in particular, 50 machines each with 4 (2.00GHz) Xeon cores and 8GB of RAM. The capacity of each SQL Server is 32GB of RAM and 4 (2.33GHz) Xeon cores. So, the compute cluster had 12.5 times more RAM and 50 times more CPU. Based on these numbers, we anticipated two potential places of bottlenecks – the central market database, and the ISP.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Finding the bottleneck&lt;/span&gt;&lt;br /&gt;The computational model, chosen for our experiments, computed correlation between stock prices over some period of time and contained very data-intensive computations with complex queries to the SQL Server that required significant grouping and sorting. The model used significant amount of data, most of which could be cached. The anticipated maximum cache hit ratio for the model was greater than 90%.&lt;br /&gt;&lt;br /&gt;First, we needed to conduct a test of the model. We decided to test all three ways of scalability measurement (one data logical unit is roughly equal to 32 millions of records in database or 512MB of tick data returned from queries):&lt;br /&gt;&lt;br /&gt;Leave amount of data to process, increase processing power:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQqMv72I/AAAAAAAAACA/p3_cOoo7z40/s1600-h/TestPlan3.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 339px; height: 61px;" src="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQqMv72I/AAAAAAAAACA/p3_cOoo7z40/s400/TestPlan3.png" alt="" id="BLOGGER_PHOTO_ID_5282567617971744610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Increase amount of data, leave processing power:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQldAzSI/AAAAAAAAAB4/rsCkaaCeBk8/s1600-h/TestPlan2.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 307px; height: 61px;" src="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQldAzSI/AAAAAAAAAB4/rsCkaaCeBk8/s400/TestPlan2.png" alt="" id="BLOGGER_PHOTO_ID_5282567616697781538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Increase amount of data and processing power synchronously:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQtLiD1I/AAAAAAAAABw/BdyA24zBcQ0/s1600-h/TestPlan1.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 275px; height: 61px;" src="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU9zQtLiD1I/AAAAAAAAABw/BdyA24zBcQ0/s400/TestPlan1.png" alt="" id="BLOGGER_PHOTO_ID_5282567618771947346" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We tested the model using this test plan and measured the entire time of map task, time spent in retrieving financial data from central market database (GetTrades method), and time spent in SQL Server ISP. There is also the graphic, which shows how the task time will behave if the system is completely linear:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aiaCCVNI/AAAAAAAAADI/GEOHmUKECg8/s1600-h/Benchmark1_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 301px;" src="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aiaCCVNI/AAAAAAAAADI/GEOHmUKECg8/s800/Benchmark1_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610803822974162" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU93LqRLLKI/AAAAAAAAACI/rO8E0QrKYFc/s1600-h/Benchmark1.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 2. Map task time distribution of original model in CompFin&lt;/span&gt;&lt;/p&gt;You may notice that the bottleneck was in the central market database: time, spent in retrieving financial data is almost equal to the entire task time. You also may notice that currently the system is much worse than linear. So, it was a good chance for Velocity to help to improve the performance and scalability.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Getting rid of the bottleneck – Velocity cache for tick data&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;At first, we created a Velocity distributed cache for financial data. This was just an intra-job cache for reducing the negative impact of data-reuse inside the computation job. Complete replacement of central market database by the Velocity cache was not considered at this stage. This approach is shown as on the picture 3 (blue cloud):&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU9313AFm1I/AAAAAAAAACQ/3zhDivoV5uY/s1600-h/CompFinAndVelocityArchitecture.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 397px;" src="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU9313AFm1I/AAAAAAAAACQ/3zhDivoV5uY/s800/CompFinAndVelocityArchitecture.png" alt="" id="BLOGGER_PHOTO_ID_5282572655109970770" border="0" /&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 3. CompFin + Velocity improvements (distributed and local caches)&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size:100%;"&gt;Velocity cache for tick data ran on HPC cluster nodes. More precisely, the same machines, where the computation tasks ran, were also used as Velocity hosts.&lt;br /&gt;&lt;br /&gt;We compared this approach with the Original CompFin:&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aiQyeqBI/AAAAAAAAADQ/W3M9p0WBDzM/s1600-h/Benchmark2_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aiQyeqBI/AAAAAAAAADQ/W3M9p0WBDzM/s800/Benchmark2_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610801341802514" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU94ki5iXRI/AAAAAAAAACY/PYrk4Ufy-_s/s1600-h/Benchmark2.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 4. Comparison of map task time between original CompFin and CompFin with Velocity distributed cache&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size:100%;"&gt;In the beginning, everything was working well. Velocity distributed cache reduced the number of requests to the central market database and performance increased dramatically.&lt;br /&gt;&lt;br /&gt;As the number of processors used for the computation increased to 128, the performance started to decrease. On 32 machines (128 processors), Velocity still dramatically outperformed the original CompFin results, but some performance degradation was experienced relative to the 16 machine (64 processors) scenario. On 50 machines (200 processors), in CTP1, we began to experience some failures and timeouts.&lt;br /&gt;&lt;br /&gt;Nevertheless, keeping in mind that Velocity was in first CTP, the results were still quite amazing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Velocity scalability – local cache &amp;amp; data-aware routing&lt;/span&gt;&lt;br /&gt;Fortunately, we had a plan of how to further improve the performance and reduce the load on Velocity distributed cache. We enabled Velocity “local cache” and added data-aware routing in the CompFin (see picture 3). This was possible, because all tasks, which execute on the same HPC node, execute in the same Windows process. The local in-process cache can improve performance if the data-reuse factor for tasks that run in the same process is high. Hence the data-aware routing was required.&lt;br /&gt;&lt;br /&gt;Below is the comparison between this approach and the approach with Velocity distributed cache alone:&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aijvpQ8I/AAAAAAAAADY/rcaRHLayrcU/s1600-h/Benchmark3_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-aijvpQ8I/AAAAAAAAADY/rcaRHLayrcU/s800/Benchmark3_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610806430188482" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU94kweLrMI/AAAAAAAAACg/HpwbZ1Xvk1Q/s1600-h/Benchmark3.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 5. Comparison of map task time between distributed cache and local cache&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size:100%;"&gt;The problems with Velocity distributed cache scalability were solved, and we can conclude that Velocity can work well in CTP1 even on large clusters.&lt;br /&gt;&lt;br /&gt;This approach performed from 5.6 to 31.9 times better than original CompFin. It also scaled better than any other approach, although not linearly. We believe that this is because the interaction with the SQL Server was still required before data was retrievied from the cache.&lt;br /&gt;However, in the “Finding the bottleneck” chapter we mentioned that the model used complex queries with grouping to SQL Server. So, maybe the performance can be improved by just simplifying these queries and moving all logic from database to compute nodes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Getting rid of the bottleneck via simplified queries&lt;/span&gt;&lt;br /&gt;Following the previous assumption, we tried to reduce the load on the central market database by simplifying the queries used in the model through removal of grouping operations. The results were largely positive:&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-ai3Cnr1I/AAAAAAAAADg/8qlPBL1fOfw/s1600-h/Benchmark4_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-ai3Cnr1I/AAAAAAAAADg/8qlPBL1fOfw/s800/Benchmark4_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610811610050386" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU94lGI322I/AAAAAAAAACo/dejG1Mo3i5A/s1600-h/Benchmark4.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 6. Comparison of map task time between original CompFin with complex and simple queries&lt;/span&gt;&lt;/p&gt;The time, spent on retrieval of tick data, was reduced from 8.5 to 52 times and the task time became almost linear. However, the scalability problem with the SQL Server remained the same, so we tried to further improve the time by using our previous best approach – Velocity distributed cache with enabled local cache and data-aware routing:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-ajEvOvyI/AAAAAAAAADo/k5s2DEqY8yc/s1600-h/Benchmark5_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-ajEvOvyI/AAAAAAAAADo/k5s2DEqY8yc/s800/Benchmark5_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610815286820642" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_sZh4q0-S4-Y/SU94lRkXZqI/AAAAAAAAACw/fmk2w-FXyGQ/s1600-h/Benchmark5.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 7. Comparison of map task time between original CompFin and CompFin with Velocity local cache. Simplified queries are used in both cases.&lt;/span&gt;&lt;/p&gt;Surprisingly, doing so did not improve the task performance significantly. Perhaps, the overhead of putting items in Velocity distributed cache was too big, or the cache services just stole CPU cycles from computations. Nevertheless, we believed that these factors had only a minor impact on performance so we decided to compare only the time spent in GetTrades method, where the financial data was retrieved:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-arLwWx2I/AAAAAAAAADw/i6mZsormu4w/s1600-h/Benchmark6_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU-arLwWx2I/AAAAAAAAADw/i6mZsormu4w/s800/Benchmark6_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610954609543010" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU94ljfNz8I/AAAAAAAAAC4/ROscU4dLyJ0/s1600-h/Benchmark6.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 8. Comparison of time, spent on retrieving tick data, between original CompFin and CompFin with Velocity local cache. Simplified queries are used in both cases.&lt;/span&gt;&lt;/p&gt;Our assumptions were right and local cache approach greatly reduced time spent for retrieval of financial data. However, one question remained – why the overall task time was not reduced? To answer this question, we performed a number of tests to investigate the time distribution of task time, when the local cache was used:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-arCCLgUI/AAAAAAAAAD4/LjM-cp-GaoE/s1600-h/Benchmark7_1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 600px; height: 322px;" src="http://1.bp.blogspot.com/_sZh4q0-S4-Y/SU-arCCLgUI/AAAAAAAAAD4/LjM-cp-GaoE/s800/Benchmark7_1.png" alt="" id="BLOGGER_PHOTO_ID_5282610951999947074" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sZh4q0-S4-Y/SU94p6LzkyI/AAAAAAAAADA/HNjRIH8hHLU/s1600-h/Benchmark7.png"&gt;&lt;/a&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-size:78%;"&gt;Picture 9. Time distribution in CompFin with &lt;/span&gt;&lt;span style="font-size:78%;"&gt; simplified queries and Velocity &lt;/span&gt;&lt;span style="font-size:78%;"&gt;local cache.&lt;/span&gt;&lt;/p&gt;These tests revealed that the SQL Server ISP, that was typically the least time consuming element of the system, now moved to the foreground. Since retrieval of financial data was now very fast, the frequency of write operations to the SQL Server has increased, and the SQL Server ISP became a bottleneck.&lt;br /&gt;&lt;br /&gt;Our conclusion is that Velocity can improve even a very fast model, where only simple queries are used. In this environment, however, the SQL Server ISP remained as a bottleneck. We have yet to experiment using Velocity as the ISP with simple queries.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Conclusion&lt;/span&gt;&lt;br /&gt;In this article we have shown that the database is the bottleneck for data-intensive applications, running on compute grids. We tried to reduce database load using two approaches: introducing Velocity distributed cache between the database and compute grid, and simplifying SQL queries to the database by moving all calculations and aggregations to the application logic.&lt;br /&gt;&lt;br /&gt;Both these approaches improved the database performance dramatically. In particular, querying data with active Velocity distributed cache was up to 31 times faster than without it. In certain configurations, when experimenting with CTP1, we also observed some Velocity scalability issues; however, for a first CTP, Velocity performed very well. At the moment of publishing, Velocity is already in CTP2 and its development continues to be in very active stages. In the near future we expect the Velocity team to spend a lot of time focused on improving scalability and performance prior to release. Velocity team has big plans and not only will some issues soon be resolved, but lots of new functionality will be added as well.&lt;br /&gt;&lt;br /&gt;So, if you have problems with database scalability and you use Microsoft technology stack, you may consider introducing Velocity to your system.&lt;br /&gt;&lt;br /&gt;There are still many interesting topics to investigate regarding the Velocity and CompFin. Also, there can be some other improvements can be made in CompFin, so we hope that this project was not the last one, where we were working with Microsoft technologies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-2683915723008575189?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/2683915723008575189/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=2683915723008575189" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2683915723008575189?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2683915723008575189?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/xd933VY1DO4/speeding-up-data-intensive-hpc.html" title="Speeding up data-intensive HPC applications with Velocity" /><author><name>Max Martynov</name><uri>http://www.blogger.com/profile/12000269073735478943</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="16905684925284551113" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_sZh4q0-S4-Y/SU9tu0y2e9I/AAAAAAAAABg/L4ZR7dvDJvA/s72-c/CompFinArchitecture.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/12/speeding-up-data-intensive-hpc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQHo9eyp7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1941024032633285802</id><published>2008-09-24T14:45:00.000-07:00</published><updated>2009-10-23T08:09:21.463-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:09:21.463-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><title>Cloud Performance Reports</title><content type="html">Cloud computing is getting a great deal of attention these days. Unfortunately, there is very little data available about performance, scalability and usability of the cloud deployment platforms.&lt;br /&gt;&lt;br /&gt;I was recently invited to speak at &lt;a href="http://web.meetup.com/66/"&gt;Silicon Valley Cloud User Group&lt;/a&gt; where I tried to bring a "practitioner's prospective" and present the results of three different recent performance and scalability benchmarks related to the cloud computing. The first benchmark aims to establish the &lt;a href="http://blog.griddynamics.com/2008/07/gridgain-on-ec2.html"&gt;scalability of EC2&lt;/a&gt; on a perfectly parallel mathematical problem, a Monte Carlo simulation, executed by &lt;a href="http://www.gridgain.com/"&gt;Grid Gain&lt;/a&gt;'s popular open source map/reduce platform - and to document lessons learned in making the application scale to 512 nodes.&lt;br /&gt;&lt;br /&gt;The  second benchmark looks at a scalability of a more complex stateful application, typical to Risk Management, that required both in-memory data grid and compute grid. Both grids were  running on &lt;a href="http://aws.amazon.com/ec2/"&gt;EC2&lt;/a&gt; and executed by &lt;a href="http://www.gigaspaces.com/"&gt;GigaSpaces&lt;/a&gt;' data &amp;amp; compute grid platform.&lt;br /&gt;&lt;br /&gt;The third benchmark looks at a prototypical data-intensive Portfolio Analysis application used heavily in the financial services industry, and studies the performance impact of data being located close to computing, or "on the cloud" vs. "off the cloud".  This work was done in collaboration with Microsoft on their &lt;a href="http://hpc.microsofthpc.net/compfin/"&gt;HPC++ CompFin Lab&lt;/a&gt; that integrates &lt;a href="http://www.microsoft.com/hpc/en/us/default.aspx"&gt;Microsoft Windows HPC Server&lt;/a&gt;,        a central market data database and Microsoft productivity products        to provide academic community with an online service to publish, execute         and manage computational finance models.               &lt;br /&gt;&lt;br /&gt;You can find the &lt;a href="http://files.griddynamics.net/CloudUG.ppt"&gt;presentation&lt;/a&gt;, with summary of results here. Please, note that these results are very fresh and the benchmarks in two cases are still going on. You can find far more details on the first benchmark in our previous blog post. We will be coming with more detailed blog reports for the second and third benchmarks soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1941024032633285802?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1941024032633285802/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1941024032633285802" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1941024032633285802?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1941024032633285802?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/PDiCVpn5-hY/cloud-performance-reports.html" title="Cloud Performance Reports" /><author><name>Victoria Livschitz</name><uri>http://www.blogger.com/profile/12264301035182704078</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="07316905052902410928" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/09/cloud-performance-reports.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQHo9eyp7ImA9WxNVE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8746063359187804882</id><published>2008-07-31T06:08:00.000-07:00</published><updated>2009-10-23T08:09:21.463-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-23T08:09:21.463-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="~Max Gorbunov" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="Amazon" /><category scheme="http://www.blogger.com/atom/ns#" term="GridGain" /><category scheme="http://www.blogger.com/atom/ns#" term="EC2" /><title>Scalability Benchmark of Monte Carlo Simulation on Amazon EC2 with GridGain Software</title><content type="html">&lt;p&gt;This blogpost presents the report on recently concluded scalability benchmark of Monte Carlo simulations running on &lt;a href="http://aws.amazon.com/ec2"&gt;Amazon EC2 &lt;/a&gt; using the &lt;a href="http://www.gridgain.com/"&gt;GridGain framework&lt;/a&gt;. It consists of two parts: Part I is a technical report on the benchmark goals, method and results and Part II is an account of the development process and lessons learned.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-weight: bold;"&gt;Part I: Benchmark description &amp;amp; results&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The goal of the benchmark was to study the scalability characteristics of massively parallel algorithms executed on Amazon ’s Elastic Computing Cloud (EC2) and managed by GridGain &lt;/p&gt;&lt;p&gt;A Monte Carlo simulation was chosen as an algorithm to represent its widespread use in financial applications. The same algorithm with different parameters was used on a wide range of grid sizes: 2, 4, 8, 16, ..., 256, 512. The parameters guaranteed that the amount of work performed by the whole grid was always linear with respect to the number of nodes. In other words, twice as many nodes always performed twice as much work. Perfect linear scalability would demonstrate the identical *completion time* of Job-1 running on 2 node and Job-2 running on 512 nodes, given that Job-2 had 256-times more work to do.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As Amazon permitted us to use the maximum of 550 nodes in a single run, the upper limit o fthe benchmark was chosen at 512.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The test utilized a full open source software stack, including GridGain, the Linux operating system, Sun Microsystem’s Open MQ JMS messaging and Sun’s Java 5 VM. Amazon’s preinstalled Fedora Core 8 with custom testing framework was used to conduct the benchmark.&lt;/p&gt;&lt;p&gt;The results justified our hopes: we could successfully run up to 512 nodes without significant performance degradation. The results graph is shown on figure 1.&lt;br /&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_5M9BNfStEvI/SJHvpM3gcqI/AAAAAAAAAzc/CZvODJ32klo/s1600-h/timings.PNG"&gt;&lt;img src="http://bp3.blogger.com/_5M9BNfStEvI/SJHvpM3gcqI/AAAAAAAAAzc/CZvODJ32klo/s400/timings.PNG" alt="" id="BLOGGER_PHOTO_ID_5229224133461570210" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-weight: bold;font-size:78%;" &gt;Figure 1. Average task execution times on 2-512 nodes grids.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The performance degradation of 3 seconds (about 20%) should be considered minor given roughly 250-fold increase in scale. The curve rises two times: in the ranges 2-8 and 256-512, while 8-256 remains almost flat.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The range 2-8 growth can be explained by initial rapid growth of grid size, which causes the rise of maximum task execution time among nodes (the overall time is determined by the “weak link”). The range 256-512 growth could be explained by OpenMQ limitations as applied to our use case (the JMS load is quadratic against the grid size). In order to continue scaling the grid beyond 512 nodes, a clusterization of OpenMQ is likely to be required.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We can conclude that the obtained result showed near linear scalability and performance improvements from 2 to 512 nodes in all test runs.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight: bold;"&gt;Part II: How did we do it?&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;To start using EC2, just open &lt;a href="http://docs.amazonwebservices.com/AWSEC2/2008-02-01/GettingStartedGuide/"&gt;Amazon EC2 Getting Started Guide&lt;/a&gt;, download EC2 API tools and follow the instructions. You can use one of the predefined public machine images or create a bundle with your own image.&lt;/p&gt;&lt;p&gt;The relatively big problem is the lack of persistence options in EC2. When an instance goes down, all the data is lost. However, there are third party solutions capable of mounting Amazon's &lt;a href="http://aws.amazon.com/s3"&gt;S3&lt;/a&gt; storage interface as a Linux filesystem.&lt;/p&gt;&lt;p&gt;Now, we needed to create a simple framework allowing us to manage the grid on Amazon’s EC2. The basic functionality would look like:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;start the grid;&lt;/li&gt;&lt;li&gt;add/remove nodes to/from the grid;&lt;/li&gt;&lt;li&gt;display the grid health;&lt;/li&gt;&lt;li&gt;run single calculation task interactively;&lt;/li&gt;&lt;li&gt;run a benchmark (batch task execution on 1, 2, 4, …, 512,... nodes).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The first problem we encountered was that multicast is not supported in the EC2 infrastructure. By default GridGain is configured to make initial discovery by IP multicast. Unfortunately, as far as we know, the EC2 guys don’t plan to create fully functional multicast support anytime soon.&lt;/p&gt;&lt;p&gt;Luckily, GridGain is shipped with a set of various Service Provider Interfaces (SPIs). So, we could choose another DiscoverySPI that does not use IP multicast for discovery purposes, and we chose JMSDiscoverySPI. At first, we picked &lt;a href="http://activemq.apache.org/"&gt;Apache ActiveMQ&lt;/a&gt; as a JMS implementation and soon ran into stability issues. Then we switched to &lt;a href="https://mq.dev.java.net/"&gt;OpenMQ&lt;/a&gt; and it proved to be sufficiently robust.&lt;/p&gt;&lt;p&gt;Our second problem turned to be the default maximum number of running instances per user – 20. Since we were going to run grids much larger than 20 nodes, we needed to override the default limit. It took several steps and a few more days to negociate with Amazon EC2, but eventually, we were granted the right to run up to 550 nodes. It seems that the business process of requesting a large amount of nodes is still not very well-defined by Amazon.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The image creation was not a very hard task: we got the public Fedora 8 i386 image, ran it, installed Java Runtime Environment 6, GridGain and ActiveMQ, then bundled this new image.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We still required some extra configuration since the grid node must start on system startup. The hardest thing was to write shell scripts for starting the grid. These scripts had to parse user data sent to the instance (different for the Head Node and Worker Nodes), determine the node type and start the necessary software in each given configuration. Later these scripts were replaced by more convenient Java-based tools and Head Node’s ActiveMQ was replaced by a standalone OpenMQ.&lt;/p&gt;&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_5M9BNfStEvI/SJLg9fKjPII/AAAAAAAAAzk/AwnmEC8YY-o/s1600-h/ggec2-2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_5M9BNfStEvI/SJLg9fKjPII/AAAAAAAAAzk/AwnmEC8YY-o/s400/ggec2-2.png" alt="" id="BLOGGER_PHOTO_ID_5229489464272960642" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align: center;"&gt;&lt;span style="font-weight: bold;font-size:78%;" &gt;Figure 2. Initial GridGain on Amazon EC2 architecture.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So, how does the grid work? First, we start the Head Node (see figure 2). Head Node automatically starts ActiveMQ (only in early versions), GridGain in master mode (will be described later) and runs the requested number of Worker Nodes. Since Workers should connect to the JMS server, Head Node passes its IP address as user data for Worker Nodes. Worker Nodes just start GridGain.&lt;/p&gt;&lt;p&gt;We realized quickly that we needed some user-friendly interface to manage the grid. So, we rewrote the scripts in Java using the &lt;a href="http://code.google.com/p/typica/"&gt;typica&lt;/a&gt; library. Thus we integrated Amazon and GridGain management. Now we can automatically start EC2 instances, wait for them to start, get their IP’s, track status, etc. Together with GridGain management it becomes a very powerful tool. Let’s imagine the grid running completely autonomously. The management module can automatically bring up more EC2 instances or shut them down depending on the current grid load.&lt;/p&gt;&lt;p&gt;When we had the simple web UI with capabilities of seeing the table of grid nodes and running our benchmark, we felt ready to run grids larger than 20 nodes. We asked Amazon to increase our running instances limit to 1050 nodes. Amazon agreed to let us run 550 instances. The know-how of our UI was the embedded scripting engine, allowing us to change a benchmarking schema without restarting the grid. To understand how simple it is to run a benchmark consisting of several task runs on different number of nodes, just look at this code:&lt;br /&gt;&lt;/p&gt;&lt;pre style="padding-left: 20px;"&gt;var itersPerNode = 5000;&lt;br /&gt;var cnode = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512];&lt;br /&gt;for (var i in cnode) {&lt;br /&gt;&lt;pre style="padding-left: 32px;"&gt;var n = cnode[i];&lt;br /&gt;grid.growEC2Grid(n, true);&lt;br /&gt;grid.waitForGridInstances(n);&lt;br /&gt;runTask(itersPerNode * n, n, 3);&lt;/pre&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p style="text-align: left;"&gt;&lt;span style="font-weight: bold;font-size:78%;" &gt;Listing 1. Sample benchmarking script.&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The closing remarks:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The framework we built is a good place to start developing a GridGain appliance. But what if we want to create, for instance, an In-Memory Data Grid on this basis? Our next step is making the framework more generic to allow easy integration with virtually any grid framework (either computing or IMDG). There are also other ideas such as creating a generic image and storing specific grid software/configurations in S3, which should ease debugging and small alterations to the appliance.&lt;/p&gt;&lt;p&gt;We are currently evaluating if our framework will be something more than just a GridGain testing framework. We'd love to hear from the community if this line of work is interesting to others beside ourselves. If you'd like to know more about this benchmark, or get access to the full source code, please contact me at mg&lt;span&gt;o&lt;/span&gt;rbunov@&lt;span style="display:none;"&gt;&lt;img src="wrong"/&gt;&lt;/span&gt;griddynamics.com&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8746063359187804882?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8746063359187804882/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8746063359187804882" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8746063359187804882?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8746063359187804882?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/MCaibAd4liA/gridgain-on-ec2.html" title="Scalability Benchmark of Monte Carlo Simulation on Amazon EC2 with GridGain Software" /><author><name>Max Gorbunov</name><uri>http://www.blogger.com/profile/05243241093447788300</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13489806596952463622" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_5M9BNfStEvI/SJHvpM3gcqI/AAAAAAAAAzc/CZvODJ32klo/s72-c/timings.PNG" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">12</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/07/gridgain-on-ec2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EBQ3cyfip7ImA9WxdXEkk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7541093640272828945</id><published>2008-06-19T02:03:00.000-07:00</published><updated>2008-06-23T10:20:52.996-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-23T10:20:52.996-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="~Max Martynov" /><category scheme="http://www.blogger.com/atom/ns#" term="distributed cache" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="enterprise applications" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><title>Grid technologies in middle-size applications</title><content type="html">Grid technologies were born to solve extreme problems and currently they are used primarily by large-scale applications. However, like computers, which were initially used only for solving complex scientific tasks and later came to almost every house, grid technologies are coming into middle-size enterprise market. In this article I will try to answer a question about how medium application can take advantage of grid technologies.&lt;br /&gt;&lt;br /&gt;When writing large application that solve extreme problems, scalability is always an issue and you do not have a choice: you must invest resources in scalability and developers often have enough time and knowledge to solve this problem. When writing small applications, you usually do not care about this kind of problems, because all will work fine on a single server. But when writing middle-size application, you are in trouble, because you are already big enough to start thinking about scalability, but you are not big enough to invest a lot of resources in solving this problem. When middle-size applications grow from little ones the trouble becomes really serious. However, scalability problems in middle-size applications are usually caused by a very limited set of architecture decisions. Knowing these causes and their resolutions will help to build a more scalable application.&lt;br /&gt;&lt;br /&gt;Whatever architecture you choose for a middle-size application, it will usually have a web server and a database. In the best case, it will have a single physical machine with both. In the worst case, it will have web servers, application servers and database server on separate machines. In all cases, the request processing chain will include several processes and will take a lot of time. Usually, the database server is also a bottleneck for the entire system, because it doesn’t scale well. While resolving these problems, mankind invented caches. Caches are useful to store some data that is costly to compute or retrieve. They can reduce both database load and request processing time a lot. However, caches can also be scaling killers.&lt;br /&gt;&lt;br /&gt;Assume you have an architecture with a dedicated web server that hosts your application process. It is relatively easy to maintain a cache on a single server. But suppose you want to scale and the single server becomes a load balancing cluster, where each machine should maintain its own cache, and this cache should be synchronized with caches on other servers. For example, if some item is removed from the cache in one server, it should be immediately removed in every cache on every other server in the cluster. This is extremely hard to accomplish. But since developers often implement simple local caches by themselves, they try to enhance their caches to support distributed behavior. The problem is that developers often do not have enough knowledge and experience to do this. Fortunately, the problem of distributed caches is well known and the solution already exists.&lt;br /&gt;&lt;br /&gt;The solution is to use third-party distributed caches or &lt;a href="http://en.wikipedia.org/wiki/In_Memory_Data_Grid"&gt;In Memory Data Grids&lt;/a&gt; (IMDG). In Memory Data Grids were created to solve problems of scaling data in extreme applications, where the cluster contains a hundreds of servers. Data stored on these servers can be partitioned between them or replicated. If data is partitioned, each server contains only one chunk of data and each chunk is stored on multiple servers to provide failover. This allows huge amounts of data to be stored in memory. If data is replicated, it is stored in full on each server. Of course, the data cached on each server is synchronized with data on other servers. This allows very fast access to data, because it is always available locally. In Memory Data Grids provide lots of other interesting features, which deserve an entire book to describe. Distributed caches are essentially a simplified form of an In Memory Data Grid. Currently there are many implementations of both IMDGs and distributed caches and if you choose to use these technologies you have a number of options.&lt;br /&gt;&lt;br /&gt;The concrete choice will depend on what technology or framework you use in your application:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If you are using .NET, you may use &lt;a href="http://www.scaleoutsoftware.com/"&gt;ScaleOut&lt;/a&gt;, &lt;a href="http://www.alachisoft.com/ncache/"&gt;NCache&lt;/a&gt; or Microsoft’s new distributed cache &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B24C3708-EEFF-4055-A867-19B5851E7CD2&amp;amp;displaylang=en"&gt;Velocity&lt;/a&gt;, which is currently available as a Community Technology Preview. They all provide an ASP.NET session state provider – the easiest way to gain a benefit from grid technologies. With this session state provider you will not need to maintain a special SQL Server for storing ASP.NET session data, because all data will be distributed between web servers in the cluster in a reliable and robust way.&lt;/li&gt;&lt;li&gt;If you are using Java, &lt;a href="http://www.oracle.com/technology/products/coherence/index.html"&gt;Oracle Coherence&lt;/a&gt; and &lt;a href="http://www.gigaspaces.com/"&gt;GigaSpaces&lt;/a&gt; are the most famous In Memory Data Grids and, hence, can be used as distributed caches. They both provide a second level cache for Hibernate, so, if you use it, you can scale easily with no additional development efforts.&lt;/li&gt;&lt;li&gt;If you are using C++, PHP, Ruby or Python, you should consider &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt;. This is a very famous distributed cache initially developed for LiveJournal, which has already helped to scale many extreme applications, like Wikipedia, YouTube, Facebook and others.&lt;/li&gt;&lt;/ul&gt;All these implementations will help you to solve distributed cache problems and scale well. In simple cases, to start using them, you will need to replace your old local caches with new distributed ones. If you need to scale a Hibernate second-level cache, or an ASP.NET session state provider, you will not be required to write any code. However, in the case of complex and serious scalability problems you can consult with us at Grid Dynamics any time and we will help you to solve them in a most effective way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7541093640272828945?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7541093640272828945/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7541093640272828945" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7541093640272828945?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7541093640272828945?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/fVQ1LmDxzOM/grid-technologies-in-middle-size.html" title="Grid technologies in middle-size applications" /><author><name>Max Martynov</name><uri>http://www.blogger.com/profile/12000269073735478943</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="16905684925284551113" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/06/grid-technologies-in-middle-size.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYGQXk9cCp7ImA9WxdXEkk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6484477625251023454</id><published>2008-05-31T15:22:00.000-07:00</published><updated>2008-06-23T09:55:20.768-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-23T09:55:20.768-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Sylvia Kainz" /><category scheme="http://www.blogger.com/atom/ns#" term="Open Source Grid and Cluster Conference" /><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="Sun Grid Engine" /><category scheme="http://www.blogger.com/atom/ns#" term="GridGain" /><category scheme="http://www.blogger.com/atom/ns#" term="Hadoop" /><title>Open Source Grid Expertise and Thought Leadership</title><content type="html">Last week, an exciting event took place here in the Bay Area: The Open Source Grid and Cluster Conference was held in Oakland. Engineers and scientists who care about the complex interactions between open source and grid computing from around the world,  discussed their projects and research insights. Grid Dynamics was represented in two ways:&lt;br /&gt;Eugene, our CTO, gave a presentation about Convergence, one of our key project about integrating Data grids with Compute grids. Check out his &lt;a href="http://www.griddynamics.com/opensource/Convergence_EugeneSteinberg.pdf"&gt;presentation&lt;/a&gt;.&lt;img style="margin: 0px auto 10px; display: block;" src="http://bp0.blogger.com/_N3LcjoJw03o/SDNhTt6BinI/AAAAAAAAALI/vtyjszCPFRY/s200/Eugene.JPG" alt="Eugene Steinberg giving talk on OSGE&amp;amp;TL Con" id="BLOGGER_PHOTO_ID_5202608985911429746" border="0" /&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;Eugene Steinberg, CTO, Grid Dynamics&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-size: 10px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;Eugene presented the latest version of Convergence which integrates DataSynapse GridServer5.0 and GigaSpaces XAP6.0. Future versions of Convergence will provide adaptors for Sun Grid Engine, Oracle's Coherence and GridGain.&lt;br /&gt;&lt;br /&gt;The second event was moderated by Victoria Livschitz, our CEO: A panel about Trends in Open Source Data Grids with experts from the open source grid computing industry: &lt;span style="font-weight: bold;"&gt;Doug Cutting&lt;/span&gt;, creator of Hadoop, &lt;span style="font-weight: bold;"&gt;Nati Shalom&lt;/span&gt;, CTO and co-founder of GigaSpaces, &lt;span style="font-weight: bold;"&gt;Nikita Ivanov&lt;/span&gt;, President and Founder of GridGain and &lt;span style="font-weight: bold;"&gt;Daniel Templeton&lt;/span&gt;, Manager at Sun Grid Engine.&lt;br /&gt;&lt;br /&gt;The discussion started with each of the panelist introducing their products, current initiatives &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_N3LcjoJw03o/SDNpUN6BiqI/AAAAAAAAALg/IOCJcvQZMiI/s1600-h/Panelists.JPG"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://bp2.blogger.com/_N3LcjoJw03o/SDNpUN6BiqI/AAAAAAAAALg/IOCJcvQZMiI/s200/Panelists.JPG" alt="" id="BLOGGER_PHOTO_ID_5202617790594386594" border="0" /&gt;&lt;/a&gt; and their commitment to the Open Source community.  Each participant had an interesting perspective particularly to the question on why Data Grids technology is deeply anchored in the Open Source community, but many Compute Grids are not.&lt;br /&gt;&lt;br /&gt;Attendees directly participated by asking the panel specific questions around their technologies and development efforts.&lt;br /&gt;&lt;span style="display: block; padding: 0px; text-align: right; font-size:78%;"&gt;&lt;br /&gt;Left to right: Nati Shalom, Nikita Ivanov,&lt;br /&gt;Doug Cutting, Daniel Templeton&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The discussion continued  informally after the panel with conference attendees and speakers discussing product specific questions and key future technology.&lt;br /&gt;&lt;span style="display: block; padding: 0px; text-align: center;"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_N3LcjoJw03o/SDNpxd6BirI/AAAAAAAAALo/WHWwsawsa34/s1600-h/Cutting.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; padding: 0px; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_N3LcjoJw03o/SDNpxd6BirI/AAAAAAAAALo/WHWwsawsa34/s200/Cutting.JPG" alt="" id="BLOGGER_PHOTO_ID_5202618293105560242" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:78%;"&gt;Doug Cutting in discussion with conference attendees&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_N3LcjoJw03o/SDNqbN6BitI/AAAAAAAAAL4/s_ab7q-RTuk/s1600-h/Victoria+and+Nikita.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; padding: 0px; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_N3LcjoJw03o/SDNqbN6BitI/AAAAAAAAAL4/s_ab7q-RTuk/s200/Victoria+and+Nikita.JPG" alt="" id="BLOGGER_PHOTO_ID_5202619010365098706" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:78%;"&gt;Victoria Livschitz and Nikita Ivanov&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_N3LcjoJw03o/SDNp8t6BisI/AAAAAAAAALw/zHvLfJNqQfg/s1600-h/Hari.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; padding: 0px; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_N3LcjoJw03o/SDNp8t6BisI/AAAAAAAAALw/zHvLfJNqQfg/s200/Hari.JPG" alt="" id="BLOGGER_PHOTO_ID_5202618486379088578" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:78%;"&gt;Nati Shalom with conference attendee&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;The conference setting allowed attendees to actively share their experience first hand, ask questions in an informal setting, hear the experts talk about technical details and strategic directions about the industry.&lt;br /&gt;&lt;br /&gt;If you want to know more about the Open Source Grid and Cluster Conference, &lt;a href="http://www.opensourcegridcluster.org/"&gt;here &lt;/a&gt;is link to this year's conference. I also found a few bloggers taping the &lt;a href="http://blogs.sun.com/deirdre/entry/where_i_am_now_open"&gt;key note speech&lt;/a&gt; by Fritz Ferstl and some &lt;a href="http://www.flickr.com/photos/chrisdag/2492116609/in/pool-opensourcegridcluster/"&gt;pictures &lt;/a&gt;of the event. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-6484477625251023454?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6484477625251023454/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6484477625251023454" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6484477625251023454?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6484477625251023454?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/KdhkbzSIGgs/open-source-grid-expertise-and-thought.html" title="Open Source Grid Expertise and Thought Leadership" /><author><name>skainz</name><uri>http://www.blogger.com/profile/00636676289358399014</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="12766458989396206553" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp0.blogger.com/_N3LcjoJw03o/SDNhTt6BinI/AAAAAAAAALI/vtyjszCPFRY/s72-c/Eugene.JPG" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/05/open-source-grid-expertise-and-thought.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08FR346fyp7ImA9WxdREEk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-4413156283142998620</id><published>2008-05-29T04:15:00.000-07:00</published><updated>2008-05-29T00:23:36.017-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T00:23:36.017-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Alexander Kusnetsov" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="convergence" /><title>Match Making in Grid Computing</title><content type="html">Data partitioning is widely used to store and manage huge amounts of data across several servers. Often there is a need to introduce global distributed transactions to keep the data consistent. Those global transactions represent a natural limit to the scalability for the entire system.&lt;br /&gt;&lt;br /&gt;Project &lt;a href="http://openspaces.org/display/CVG/Convergence"&gt;Convergence&lt;/a&gt; was born as an example of managing interaction between in-memory data grid and computational grid to address specifically problem of data consistency in systems with global distributed transactions. Based on the idea of &lt;a href="http://blog.griddynamics.com/2008/02/data-aware-routing-datasynapse_14.html"&gt;data aware routing&lt;/a&gt;, network utilization and overall performance will be increased. In addition, data aware routing can also improve scalability.&lt;br /&gt;&lt;br /&gt;How does it work? Let me illustrate the solution by using a simple example: You are the owner of a dating agency. A candidate comes to your agency and looks for a person with specific parameters such as the love for operas, an interest in cooking and a liking for dogs . Let's assume that the set of these parameters is unique for each person and all parameters need to be matching. So, your agency will find him a perfect match or he will be put into your database as a single new customer waiting for a match. Considering your candidate’s specific parameters, you expect that it will take some time to find him an exact match.&lt;br /&gt;&lt;br /&gt;Your company has an outstanding reputation and you are flooded with candidates and your company cannot handle all the new candidates. You realize that you need to get a business partner and you partner with another dating agency in town. You also hire as secretary who greets your candidates and sends them randomly to one of the offices.&lt;br /&gt;&lt;br /&gt;One day, two candidates with the exact same parameters (a perfect match) enter your office and your secretary sends one of them to your office and the other to your business partner’s office. Both of you start looking independently for an exact match simultaneously, but both of you cannot find one in your databases. As a result, you and your companion mark both candidates as single, waiting for a match while you miss the opportunity to generate a fee from the match. How can you solve this unfortunate incident?&lt;br /&gt;&lt;br /&gt;First, you can have your secretary manage the assignment better by having her search your and your business partner's combined database: But while she is using the database, nobody else can access the database until she is done with her search. This may produce a match of the candidates, but create a bottleneck and hence impact the performance of your match making capabilities.&lt;br /&gt;&lt;br /&gt;Secondly, you divide all candidates in two groups (for example, those that like dogs and those that do not, assuming there are about the same number of candidates that like or dislike dogs). This way, you and your partner are responsible for an equal amount of candidates. You will instruct your secretary to send incoming candidates to the offices depending on the likes/dislikes of dogs. Because you are processing only half of the candidates with one parameter already matched in your database, you will achieve a match at a faster rate than before.&lt;br /&gt;&lt;br /&gt;This is exactly how in-memory data grids and computational grids interact and how data aware job scheduling can address the ‘matching of data grid and compute grid requests.’ As in our example, a database or an in-memory data grid (&lt;a href="http://www.oracle.com/technology/products/coherence/index.html"&gt;Oracle Coherence&lt;/a&gt; or &lt;a href="http://www.gigaspaces.com/xapOverview"&gt;GigaSpaces XAP&lt;/a&gt;), represents the databases with all the parameters of the candidates. You and your business partner’s represent the computational grid (&lt;a href="http://gridgain.com/"&gt;GridGain&lt;/a&gt;, &lt;a href="http://www.datasynapse.com/en/products/gridserver.php"&gt;DataSynapse GridServer&lt;/a&gt; or &lt;a href="http://www.sun.com/software/gridware/"&gt;Sun Grid Engine&lt;/a&gt;), and your secretary fulfills the function of a data aware job scheduler.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-4413156283142998620?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/4413156283142998620/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=4413156283142998620" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/4413156283142998620?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/4413156283142998620?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/mu0A4X6E9V8/data-partitioning-and-global.html" title="Match Making in Grid Computing" /><author><name>Alexander</name><uri>http://www.blogger.com/profile/12758684695414200209</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="08497447863300918744" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/05/data-partitioning-and-global.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYARH8-eyp7ImA9WxdSGU4.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-5847730442849246030</id><published>2008-05-27T02:22:00.000-07:00</published><updated>2008-05-27T17:05:45.153-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-27T17:05:45.153-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="flex" /><category scheme="http://www.blogger.com/atom/ns#" term="visualization" /><category scheme="http://www.blogger.com/atom/ns#" term="RIA" /><category scheme="http://www.blogger.com/atom/ns#" term="~Ivan Bulanov" /><category scheme="http://www.blogger.com/atom/ns#" term="graph" /><title>Choosing graph manipulation library for your Flex app</title><content type="html">The open-source movement plays a pretty big role in everyday life here at &lt;a href="http://www.griddynamics.com/"&gt;Grid Dynamics&lt;/a&gt;. We always try to do our best to improve the software we're working with and contribute back into the community.&lt;br /&gt;&lt;br /&gt;While developing     an &lt;a href="http://en.wikipedia.org/wiki/Rich_Internet_application"&gt;RIA&lt;/a&gt; project  we faced a need to display complex graphs  within an Adobe Flex application. It turns out that there are not many solutions to this problem existing at the moment. Actually AFAIK there are only &lt;a href="http://flare.prefuse.org/"&gt;Flare toolkit&lt;/a&gt;, &lt;a href="http://www.yworks.com/en/products_yfilesflex_about.htm"&gt;yFiles Flex&lt;/a&gt;, &lt;a href="http://mark-shepherd.com/blog/springgraph-flex-component/"&gt;SpringGraph&lt;/a&gt; and &lt;a href="http://code.google.com/p/flexvizgraphlib"&gt;Flex Visual Graph Library&lt;/a&gt; (further on &lt;i&gt;FVG&lt;/i&gt;). Having done the comparison between the libraries we have chosen &lt;i&gt;Flex Visual Graph Library&lt;/i&gt; as our current graphing solution.&lt;br /&gt;&lt;h3&gt;Good Things and Bad Things&lt;/h3&gt;&lt;br /&gt;&lt;div align="left"&gt;Here is the list of the &lt;span&gt;most &lt;/span&gt;distinctive features of &lt;span&gt;the&lt;/span&gt; &lt;i&gt;FVG&lt;/i&gt;:&lt;br /&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;It is an open&lt;span&gt;-&lt;/span&gt;source project so everyone can use it for free and modify it in the way he likes;&lt;/li&gt;&lt;li&gt;It can render not only trees but also (relatively) &lt;span&gt;complex&lt;/span&gt;&lt;span&gt; graphs;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;It contains a number of algorithms for performing layout;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Laying out the graph is perform&lt;span&gt;ed&lt;/span&gt;  on the client&lt;span&gt;-&lt;/span&gt;side and no server resources are involved in the process.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;The library has some documentation and samples, although sometimes (and maybe too often) one has to dig into its source code to figure out the way it works.&lt;br /&gt;&lt;br /&gt;However, it is a young project so  it is expected to be imperfect. Here are the main drawbacks that&lt;span&gt; sometimes &lt;/span&gt;annoy me:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span&gt;A somewhat m&lt;/span&gt;&lt;span&gt;onolithic&lt;/span&gt; library design, &lt;span class="Apple-style-span"&gt;god-classes&lt;/span&gt; anti-pattern here and there; favor is given to state changes instead of the parameter passing. I would also mention here coding conventions, although it is surely my personal impression;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lack of documentation on layout algorithms; incomplete design diagrams, tutorials and examples.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div align="left"&gt;When dealing with someone's else products instead of the homegrown ones you will almost always find its feature set is incomplete. This is the case not only for open-source projects but also for closed-source ones (including commercial) and the greatest advantage of open source is that it allows you to implement the desired features and not wait until someone else does it. And surely there were missing features in &lt;i&gt;FVG&lt;/i&gt; that our customers and we ourselves wanted to have.&lt;/div&gt;&lt;h3&gt;Our humble help&lt;/h3&gt; So here is a list of the things we improved:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Fixed and successfully harnessed functionality for adding and removing &lt;span&gt;of&lt;/span&gt; nodes. Before the fix it was impossible to do that after the graph was initialized. It seems that the developers of the library just did not need it so they haven't got it into shape.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fixed support for directed graphs. It was one of the most controversial changes to the library. Before, the layouting algorithms were tested only on nondirected graphs so the spanning tree in the case of a directed graph was computed in a wrong way. This led to the graph being &lt;span&gt;&lt;span&gt;laid out i&lt;/span&gt;&lt;/span&gt;nappropriately. Now the user can choose if he wants to get the new behavior or emulate the old one.&lt;/li&gt;&lt;li&gt;Enhanced hierarchical layouter. It now supports interleaving of nodes. Sibling nodes (the nodes on the same  level) are placed now in a checkerboard formation so every even node is put a bit higher than an odd one. This enhances the readability of the graph and the overall appearance if  nodes have text labels under them.&lt;/li&gt;&lt;li&gt;Added possibility to sort sibling nodes in a &lt;span&gt;specified&lt;/span&gt; order. This again enhances readability. Suppose that you have some text on your nodes. You can sort the siblings in the lexicographical order so you can more easily find the node you want with your eyes. Or you may want to display a certain type of nodes first. Plugging in your own sorting logic is tremendously easy.&lt;/li&gt;&lt;li&gt;Added a very cool feature: graph zooming. There was nothing like that in the library before. One could only try to tune some parameters of layouters in order  to achieve zooming effect but the real zooming for every layouter was impossible.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span&gt;In addition, we've been implementing numerous small fixes and improvements — and we are definitely going to continue this effort in the future.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;In general, supporting the open&lt;span&gt;-&lt;/span&gt;source library has the following notic&lt;span&gt;e&lt;/span&gt;able peculiarity: as with other source management models, it is always needed to keep compatibility with those who already use your library in their applications. But when &lt;span&gt;a need to make significant and incompatible changes to the library appears, one can always commit the changes into a separate branch.&lt;/span&gt; It turns out to be a rather common practice in the open-sourced world. Although this is not as convenient as just committing the changes directly to the trunk, the approach has advantages. It allows you to not break the compatibility and let other developers test and review the new functionality. We've been maintaining a separate branch for quite a long time, partly because of tensions with the maintainers, partly because of a lack of time to perform all the necessary merges and testing. However, not long ago we decided that this will likely cause the branches to diverge in some point of time — definitely that will not add value to the library, but rather subtract from it. So we've consolidated our efforts with the maintainer of the library and&lt;span&gt; presented a &lt;a href="http://flexvizgraphlib.googlegroups.com/web/Demo.swf"&gt;demo&lt;/a&gt; of the new features. The guys were very collaborative and accepted our changes into the trunk with just a couple of minor changes.&lt;/span&gt;&lt;div align="left"&gt;&lt;span&gt;&lt;br /&gt;As we going to use the library further we will definitely continue to put effort in. So our next step is going be reviewing the &lt;i&gt;FVG&lt;/i&gt;'s architecture and proposing plans for refactoring the code. On the features side, we're going to have a hierarchical layouter that will be able to support multiple root nodes, a zooming engine that will preserve label and node size, node renderer that supports overlay icons, improved edge-node connections... lots of fun things to come.&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div align="left"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div align="left"&gt;Stay tuned!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-5847730442849246030?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/5847730442849246030/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=5847730442849246030" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5847730442849246030?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5847730442849246030?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/blyY-PDL1KE/choosing-graph-manipulation-library-for.html" title="Choosing graph manipulation library for your Flex app" /><author><name>IvanBulanov</name><uri>http://www.blogger.com/profile/05720205714226318572</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06761332474760822788" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/04/choosing-graph-manipulation-library-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEENR3czfCp7ImA9WxdTEEw.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-676234938511704740</id><published>2008-05-05T08:52:00.000-07:00</published><updated>2008-05-05T11:38:16.984-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-05T11:38:16.984-07:00</app:edited><title>Partnership with GridGain</title><content type="html">Today we announced a new partnership with &lt;a href="http://www.gridgain.com/"&gt;GridGain&lt;/a&gt; (see the &lt;a href="http://enterpriseapps.itbusinessnet.com/articles/viewarticle.jsp?id=376803"&gt;press release here&lt;/a&gt;). I am extremely pleased to be launching this alliance and hope it will accelerate the already impressive adoption of GridGain's new and exciting open source Java platform for high-performance grid applications.&lt;br /&gt;&lt;br /&gt;At Grid Dynamics we see GridGain as a simple, elegant, extensible, open-source, pure-Java platform that makes  traditional high-performance computing  and all modern map/reduce applications significantly simpler and cheaper to develop and deploy than it has ever been possible before. The platform's extensibility also allows GridGain to be used for a wider set of applications and enables the integration with other tools, systems and frameworks.&lt;br /&gt;&lt;br /&gt;The partnership gives GridGain's customers an integrated Software + Service offering, enhancing GridGain's innovative technology with Grid Dynamics' expertise and track record in designing complex, scale-out applications. Customers are getting best-of-breed solutions from the industry leaders in their respective areas and should expect a seamless experience working across both organizations. Grid Dynamics and GridGain share the same core values, highly regarded by their mutual customers:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Both are fundamentally engineering companies, nearly obsessed with the performance, scalability and quality of applications we write.&lt;/li&gt;&lt;li&gt;Both recognize the importance of the Open Source as a medium for cost-effective and open  software products with almost "organic" properties, which thrive and evolve in the marketplace under a watchful eye and the collective efforts of their designers and users.&lt;/li&gt;&lt;li&gt;Both are cost-efficient, global-from-the-cradle organizations with significant R&amp;amp;D operations in Eastern Europe and headquarters in the Silicon Valley.&lt;/li&gt;&lt;/ul&gt;Under the terms of the relationship, Grid Dynamics is creating a "Center of Excellence" around the GridGain product and extending its design patterns for scalable high-performance applications to include mappings to GridGain technology. Both companies are collaborating on the joint R&amp;amp;D projects, including the planned release of a GridGain plug-in  for Grid Dynamics' open source project &lt;a href="http://www.openspaces.org/display/CVG/Convergence"&gt;Convergence&lt;/a&gt;, designed to enable interoperability between the leading compute and data grid platforms. Together, Grid Dynamics and GridGain simplify high-performance computing, lower the barrier of adoption of map/reduce paradigm for thousands of customers and ultimately enable a better scalability of a wide range of applications, networks and web sites.&lt;br /&gt;&lt;br /&gt;I am personally looking forward to a lasting relationship between our companies that benefits GridGain users and the entire open source high-performance computing community.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-676234938511704740?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/676234938511704740/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=676234938511704740" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/676234938511704740?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/676234938511704740?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/nO3HHVVLZOY/partnership-with-gridgain.html" title="Partnership with GridGain" /><author><name>Victoria Livschitz</name><uri>http://www.blogger.com/profile/12264301035182704078</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="07316905052902410928" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/05/partnership-with-gridgain.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEHSHo9fip7ImA9WxZbFk8.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7328923381976762682</id><published>2008-04-03T06:57:00.000-07:00</published><updated>2008-04-19T09:47:19.466-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-19T09:47:19.466-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grid dynamics" /><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="~Eugene Steinberg" /><category scheme="http://www.blogger.com/atom/ns#" term="binary calculator" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><category scheme="http://www.blogger.com/atom/ns#" term="grid consulting" /><title>Binary Calculator Project - What is the footprint of my GigaSpaces Entries?</title><content type="html">In the initial stages of every Data Grid project it is always essential to get good estimates of memory requirements. How much memory will my domain objects converted to Entries consume and what will be the indexing overhead? The answer to this question defines what JVM heap size to choose and how many of JVMs will be needed to store the intended dataset - or determine how much data can be stored within a given hardware footprint.&lt;br /&gt;&lt;br /&gt;For GigaSpaces, it is hard to provide accurate theoretical estimates of your Entry size. Here are the reasons:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Space doesn't store entries as heap objects - they are stored decomposed to fields&lt;/li&gt;&lt;li&gt;String uid is generated and stored along with each entry&lt;/li&gt;&lt;li&gt;Index overhead is dependent on type of index (ordered or unordered ) and on a field dataset cardinality.&lt;/li&gt;&lt;/ul&gt;For these reasons it is far more practical to take an experimental approach in measuring entry footprint than trying to apply a theoretical formula. The goal of the &lt;a href="http://www.openspaces.org/display/OBC/OpenSpaces+Binary+Calculator"&gt;Binary Calculator project&lt;/a&gt; is to build a convenient toolkit for this problem. The main idea is quite simple:&lt;br /&gt;&lt;br /&gt;First, collect the basic statistics on the efficiency of storage of the individual entities:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Connect to remote space&lt;/li&gt;&lt;li&gt;Get the batch of tested entries from some entry source&lt;/li&gt;&lt;li&gt;Write a batch to remote space&lt;/li&gt;&lt;li&gt;Perform remote garbage collecting&lt;/li&gt;&lt;li&gt;Measure memory usage&lt;/li&gt;&lt;li&gt;Repeat step 2&lt;/li&gt;&lt;/ol&gt;After a sufficient number of iterations is done, we will get a number of data points in the format &lt;span style="font-style: italic;"&gt;(entriesWritten, memoryUsage)&lt;/span&gt;. Performing a linear approximation (e.g. min square linear fit) we receive the approximation of single entry footprint (including index overhead).&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Implementing this idea, we have built an initial version of the Binary Calculator, which can be used as a toolkit for measuring arbitrary entry footprint. It has a very simple GUI that shows progress of the memory experiment.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_6Xw_KFI7ZPs/R_TqJBCJyyI/AAAAAAAABKk/Onpmui9wwCc/s1600-h/bincalc-0.1.0-screenshot.jpg"&gt;&lt;img style="cursor: pointer; display: block;" src="http://bp3.blogger.com/_6Xw_KFI7ZPs/R_TqJBCJyyI/AAAAAAAABKk/Onpmui9wwCc/s400/bincalc-0.1.0-screenshot.jpg" alt="" id="BLOGGER_PHOTO_ID_5185026511627471650" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;We are planning to turn this simple toolkit into a much more powerful tool, which will generate entries on the fly, based on user-supplied meta data. This way, the user can specify an Entry Description as a simple table in a GUI:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="border: 1px solid black; margin: 0px; width: 70%;"&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Indexed&lt;/th&gt;&lt;th&gt;Number of fields&lt;/th&gt;&lt;th&gt;Avg Length&lt;/th&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Long&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;1000&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;String&lt;/td&gt;&lt;td&gt;Yes&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;5000&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Integer&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;BinaryCalculator will generate Entries at runtime based on this description, populate it with random data, perform memory experiments and show estimated entry size.&lt;br /&gt;&lt;br /&gt;Also, we are planning to build a lightweight plugin system to supply a custom &lt;span style="font-style: italic;"&gt;EntrySource&lt;/span&gt;,&lt;br /&gt;for example, your own random entry generator or JDBC or Hibernate data source. Consequently, performing full fledged capacity experiments loading real data from the database will be much easier.&lt;br /&gt;&lt;br /&gt;We hope that this tool will be quite useful for GigaSpaces implementors in the field.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7328923381976762682?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7328923381976762682/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7328923381976762682" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7328923381976762682?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7328923381976762682?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/PtGo-jb9I1U/binary-calculator-project-what-is.html" title="Binary Calculator Project - What is the footprint of my GigaSpaces Entries?" /><author><name>Eugene Steinberg</name><uri>http://www.blogger.com/profile/06887960894636399710</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09277193071639676635" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_6Xw_KFI7ZPs/R_TqJBCJyyI/AAAAAAAABKk/Onpmui9wwCc/s72-c/bincalc-0.1.0-screenshot.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/04/binary-calculator-project-what-is.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkAAQnY-eSp7ImA9WxZUFUg.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-2998531681389602866</id><published>2008-04-01T07:12:00.000-07:00</published><updated>2008-04-07T01:59:03.851-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-07T01:59:03.851-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexander Kusnetsov" /><category scheme="http://www.blogger.com/atom/ns#" term="PackRat" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="grid consulting" /><category scheme="http://www.blogger.com/atom/ns#" term="openspaces.org" /><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><title>Introducing the PackRat Project</title><content type="html">Remember the legendary &lt;a href="http://en.wikipedia.org/wiki/Fallout_2"&gt;Fallout 2&lt;/a&gt; game? One of its cool features was perks. You could increase the number of action points, strength, critical strike percentage, etc. One of the most useful perks for those who wanted to carry as much as possible was the perk called Pack Rat.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.gamebanshee.com/fallout2/perks/images/packrat.jpg"&gt;&lt;img fix="fixed" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.gamebanshee.com/fallout2/perks/images/packrat.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But how does it relate to &lt;a href="http://en.wikipedia.org/wiki/Data_grid"&gt;Data Grids&lt;/a&gt;? The answer is very simple: it is possible to be more efficient at storing the data in the data grid by "packing" the objects. That's the goal of the &lt;a href="http://openspaces.org/display/PRT/PackRat"&gt;PackRat&lt;/a&gt; project, released yesterday on OpenSpaces.org. The initial idea came out of a customer project with &lt;a href="http://tunewiki.com/wiki/index.php/Main_Page"&gt;TuneWiki&lt;/a&gt;, a lyrics distribution site developed with &lt;a href="http://gigaspaces.com/pr_xap.html"&gt;GigaSpaces XAP 6.0&lt;/a&gt; where it was important to pack as many lyrics as possible in a space without noticeable loss of search and retrieval performance.&lt;br /&gt;&lt;br /&gt;Let's say we want to develop a hypothetical lyrics distribution service. First, we need a simple mechanism that packs together all entities related to a single lyric:&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;import&lt;/span&gt; org.openspaces.packrat.annotations.*&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedClass&lt;/span&gt;(type = &lt;span style="color: rgb(163, 21, 21);"&gt;"entry"&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;class&lt;/span&gt; Lyrics {&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@IndexField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; Integer id;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@IndexField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String title;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@IndexField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String artist;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; Integer version;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String language;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String comment;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String album;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String year;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String genre;&lt;br /&gt;  &lt;span style="color: rgb(163, 21, 21);"&gt;@CompressedField&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String lyrics;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 128, 0);"&gt;// other stuff&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Let's say a song can be searched by artist and title (kind of a composite key). This means that all other non-searchable fields (like our &lt;code&gt;lyrics&lt;/code&gt; field) can be stored in compressed form in a &lt;code&gt;binary field&lt;/code&gt; and &lt;code&gt;unpacked on demand&lt;/code&gt;. The definition for such entry looks like this:&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;class&lt;/span&gt; LyricsPacked implement Entry{&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; Integer id;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String title;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; String artist;&lt;br /&gt;  &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;byte&lt;/span&gt;[] binary;&lt;br /&gt;&lt;br /&gt;  &lt;span style="color: rgb(0, 128, 0);"&gt;// other stuff&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;To pack and unpack entries we need to create an instance of &lt;code&gt;Packer&lt;/code&gt;. This class implements &lt;code&gt;Entry&lt;/code&gt; interface and has a method &lt;code&gt;pack&lt;/code&gt;, which packs a given object. This is how you may write a packed entry to a space:&lt;br /&gt;&lt;pre&gt;Packer packer = &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; Packer();&lt;br /&gt;IJSpace space = (IJSpace) SpaceFinder.find(&lt;span style="color: rgb(163, 21, 21);"&gt;"jini://*/*/mySpace"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;Lyrics lyric = &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; Lyrics();&lt;br /&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;// assign necessary fields&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;space.write(packer.pack(lyric), &lt;span style="color: rgb(0, 0, 255);"&gt;null&lt;/span&gt;, Lease.FOREVER);&lt;/pre&gt;&lt;br /&gt;At some point in time, you'll need to search the lyrics that are stored packed in a space. This code snippet shows how you'd do it using&lt;br /&gt;&lt;code&gt;Packer.packForTemplate(Object template)&lt;/code&gt;, which packs the template before searching for it:&lt;br /&gt;&lt;pre&gt;Lyrics templateLyrics = &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; Lyrics();&lt;br /&gt;Entry[] entries = space.readMultiple(packer.packForTemplate(templateLyrics), &lt;span style="color: rgb(0, 0, 255);"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(0, 0, 255);"&gt;1000&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (Entry entry:entries) {&lt;br /&gt;  Lyrics lyrics = packer.unpack(entry);&lt;br /&gt;  &lt;span style="color: rgb(0, 128, 0);"&gt;// process unpacked lyrics&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For more examples, check the  &lt;a href="http://www.openspaces.org/display/PRT/Project+Documentation"&gt;project documentation page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt; PackRat was submitted to the &lt;a href="http://openspaces.org/display/OS/OpenSpaces+Developer+Challenge"&gt;OpenSpaces Developer Challenge&lt;/a&gt;. It has won the Early Bird Draw.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-2998531681389602866?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/2998531681389602866/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=2998531681389602866" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2998531681389602866?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2998531681389602866?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/mNIif6-3FfY/packrat-project.html" title="Introducing the PackRat Project" /><author><name>Alexander</name><uri>http://www.blogger.com/profile/12758684695414200209</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="08497447863300918744" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/01/packrat-project.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MGQHw5fCp7ImA9WxZUEUw.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1122113902139730406</id><published>2008-03-31T20:43:00.000-07:00</published><updated>2008-04-01T23:57:01.224-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-01T23:57:01.224-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="grid dynamics" /><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="~Victoria Livschitz" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="data synapse" /><category scheme="http://www.blogger.com/atom/ns#" term="grid consulting" /><category scheme="http://www.blogger.com/atom/ns#" term="openspaces.org" /><title>April Fool's Day - Big OpenSpaces.org Release Date</title><content type="html">Late last year, our friends at GigaSpaces launched an open source community &lt;a href="http://www.openspaces.org/" rel="nofollow"&gt;OpenSpaces.org&lt;/a&gt; with the following mission (quote from the community web site):&lt;br /&gt;&lt;br /&gt;"OpenSpaces.org is a website sponsored by &lt;a href="http://www.gigaspaces.com/" rel="nofollow"&gt;GigaSpaces Technologies&lt;/a&gt; and dedicated to creating and serving a community that develops and shares open source software for the OpenSpaces development framework."&lt;br /&gt;&lt;br /&gt;For a company like ours this was a very good news. As an independent consulting firm with deep expertize in grid technologies and a whole practice dedicated to the popular GigaSpaces XAP technology, we constantly create tools, utilities and frameworks that make GigaSpaces product better and easier to use for our customers. Once the tool is created, we want to give it to the hands of all GigaSpaces users, and ideally let the users help us - and everyone else - to refine and improve the tool. OpenSpaces.org is a perfect venue for such projects.&lt;br /&gt;&lt;br /&gt;Let's take an example - project Gigapult. If you ever had to write a bunch of scripts that start up a cluster on your Windows-based development environment, then re-write them to work on a corporate Linux-based testing lab and then do this again for a differently configured production environment, you know how frustrating and counter-productive this is. We had to do something like this last summer for a customer where the production environment wasn't even known to the developers who were creating the deployment scripts. This script-porting business led to hard-to-find bugs and delays in the production roll out.&lt;br /&gt;&lt;br /&gt;Kirill Ishanov, the project lead, finally had enough and suggested an idea: &lt;span class="blog-text"&gt;let's make Gigaspaces configuration and bootstrapping work cross-platform, and in the process simplify the API and make the configuration files more maintainable and readable. After all, if everything else executes in the JVM, why should deployment logic be any different? Kirill explains his motivation in more details in his two blog postings, &lt;a href="http://griddynamics.blogspot.com/2008/02/updated-ive-finally-moved-gigapult.html" rel="nofollow"&gt;Project Gigapult&lt;/a&gt; and &lt;a href="http://griddynamics.blogspot.com/2008/02/gigaspaces-cluster-bootstrapping-and.html" rel="nofollow"&gt;GigaSpaces Cluster Bootstrapping and Automated Testing&lt;/a&gt;&lt;/span&gt;&lt;span class="blog-text"&gt;, but this is basically how project Gigapult was born. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Today &lt;a href="http://www.openspaces.org/display/GPT/Gigapult" rel="nofollow"&gt;Gigapult&lt;/a&gt; is a JRuby-based domain-specific language designed to specify all aspects of grid configurations in a simple and intuitive way. For more information and to download the code, please, visit the project's &lt;a href="http://www.openspaces.org/display/GPT/Gigapult" rel="nofollow"&gt;homepage&lt;/a&gt;. We've used Gigapult internally on several projects now, and the technology does make life easier.&lt;br /&gt;&lt;br /&gt;Now, along comes OpenSpaces.org and offers Gigapult the vehicle to release the technology into the hands of developers who need it most and can contribute to its enhancements going forward. Since the launch of OpenSpaces.org, Grid Dynamics opened three more active projects:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.openspaces.org/display/CVG/Convergence" rel="nofollow"&gt;Convergence&lt;/a&gt;: a pluggable architecture for interoperability between computational grids and in-memory data grids capable of data-aware scheduling, with initial bindings for GigaSpaces XAP and Data Synapse GridServer&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.openspaces.org/display/PRT/PackRat" rel="nofollow"&gt;PackRat&lt;/a&gt;: a library that helps increase the space capacity by efficiently packing a non-indexed part of entities in binary format&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.openspaces.org/display/OBC/OpenSpaces+Binary+Calculator" rel="nofollow"&gt;OpenSpaces Binary Calculator&lt;/a&gt;: a tool to accurately estimate memory size required to store objects in cache&lt;br /&gt;&lt;br /&gt;At the launch of OpenSpaces.org, GigaSpaces announced the &lt;a href="http://www.openspaces.org/display/OS/OpenSpaces+Developer+Challenge" rel="nofollow"&gt;OpenSpaces Developer Challenge&lt;/a&gt;. Naturally, our four projects entered the competition. And since the challenge ends today, tonight was the first beta release for all four! Nothing like a little competition to encourage the respect for deadlines... Despite today being April 1st, this is no joking matter. We want to win!&lt;br /&gt;&lt;br /&gt;On more serious note, over the next few days I expect project leads to blog in more details about their respective projects. Meanwhile,  please visit the projects, download the technology and give us the feedback - the good, the bad and the ugly so that we can make these tools better, for you and everyone else.&lt;br /&gt;&lt;br /&gt;And please cheer for us as we await the results of the competition!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1122113902139730406?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1122113902139730406/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1122113902139730406" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1122113902139730406?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1122113902139730406?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/aozc7w6FMQ4/april-fools-day-big-openspacesorg.html" title="April Fool's Day - Big OpenSpaces.org Release Date" /><author><name>Victoria Livschitz</name><uri>http://www.blogger.com/profile/12264301035182704078</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="07316905052902410928" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/03/april-fools-day-big-openspacesorg.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YCSXo9eyp7ImA9WxZUE00.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6133561742819170602</id><published>2008-03-16T23:43:00.000-07:00</published><updated>2008-04-04T02:26:08.463-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-04T02:26:08.463-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="~Victoria Livschitz" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="grid consulting" /><category scheme="http://www.blogger.com/atom/ns#" term="convergence" /><title>Notes from MS Developer Conference for Financial Services</title><content type="html">Last week a few folks from our company attended MS Developer Conference for Financial Services in Manhattan. The event was targeting Wall Street developers that came to learn what Microsoft is doing in the area of HPC. It is exciting to see Microsoft get serious about  performance and scale-out computing and have a broad plan to address the needs of this already vast and rapidly expanding space.&lt;br /&gt;&lt;br /&gt;I will not get into the details of technologies being showcased in this blog. Rather, I'd like to talk a little bit - selfishly - about what we were doing there, and then share one discovery - a grid company we didn't know about that has an interesting data caching solution for .NET community.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;1. Excel-on-the-Grid&lt;/h3&gt;We were showing a demo of Excel application acting as a client for a grid-based processing. This is a powerful concept that is gaining wide spread on Wall Street. Excel is traditionally used in financial applications for heavy-duty data aggregation, analysis and visualization, all of which requires local data and processing on the desktop. This approach has serious limitations:&lt;br /&gt;&lt;br /&gt;- If you wanted realtime data embedded in Excel app, how'd you deliver that data to the spreadsheet?&lt;br /&gt;- If you wanted &lt;em&gt;really&lt;/em&gt; computationally intensive spreadsheets, where'd you take the resources?&lt;br /&gt;- If you wanted to share your application with others, how'd you do that?&lt;br /&gt;&lt;br /&gt;Turns out, grid computing offers an elegant answer:&lt;br /&gt;&lt;br /&gt;Step 1: Move the data from spreadsheet to Data Grid&lt;br /&gt;Step 2: Move the computations from spreadsheet to Compute Grid&lt;br /&gt;Step 3: Instrument Excel to both push the computations to the Grid and pull the results off the Grid as appropriate.&lt;br /&gt;Step 4: Share the "dumb client" easily, it's now light-weight&lt;br /&gt;&lt;br /&gt;Many grid vendors - and their Excel customers - are recognizing the business benefits and building solutions that makes Excel-on-the-Grid work better, ideally someday out-of-the-box. Amongst such vendors are Microsoft, GigaSpaces, Data Synapse, and others. We at Grid Dynamics were asked to develop a demo that showed Microsoft Windows Compute Cluster Server 2008 as  a computational engine behind Excel-on-the-Grid, backed by GigaSpaces XAP 6.0 as in-memory data grid.&lt;br /&gt;&lt;br /&gt;The demo works as follows:&lt;br /&gt;&lt;br /&gt;1. Excel sends the job to MS WCCS&lt;br /&gt;2. The job is directed to &amp;amp; executed on the server that runs the right local data cache by XAP&lt;br /&gt;3. Excel gets a notification when the job is finished and displays the results&lt;br /&gt;&lt;br /&gt;The main points of the demo are three-fold:&lt;br /&gt;&lt;br /&gt;a. Excel-on-the-Grid is COOL&lt;br /&gt;b. One can mix-and-match various compute and data grid solutions to achieve business objectives&lt;br /&gt;c. Data-aware job scheduling (which is the ability of job scheduler to co-locate job execution local to the cached data) gives 2x - 3x performance boost to data-hungry jobs. What's especially important to point out is that the job itself is a "black box" to the  grid - no changes are done to the algorithm itself, it may be considered a legacy code for all intents and purposes.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;2. ScaleOut Software&lt;/h3&gt;An interesting discovery of the conference for our team had been a vendor, &lt;a href="http://www.scaleoutsoftware.com/"&gt;ScaleOut Software&lt;/a&gt;, who has a pure .NET implementation of data grid with seemingly good architecture and nice features.&lt;br /&gt;&lt;br /&gt;Traditionally, Java community had been way ahead of the game on Data Grids. GigaSpaces, Tangosol and GemStone - the three big mature commercial players in data grid space - are all Java-based technologies. Yet the applications that require data grid access are a good mix between Java and .NET these days (there is always some C/C++ and other varieties, of course). While these Java technologies are supporting .NET clients in various ways, it makes sense for pureplay .NET caching and data grid solutions to be available on the market as well.&lt;br /&gt;&lt;br /&gt;We weren't aware of such solutions when we ran into ScaleOut Software last week. They offer replicated data grid with a lot of nice features. They don't have two big ticket items that leading Java caching vendors do:  data partitioning and strong out-of-the-box DB persistence. Still, for application session data, and many other stateful application needs in Windows environments, I can see ScaleOut providing a good solution for developers.  We haven't really had a chance to do anything with ScaleOut software yet, but I hope to try it out soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-6133561742819170602?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6133561742819170602/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6133561742819170602" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6133561742819170602?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6133561742819170602?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/LZlp9EXxLd8/notes-from-ms-developer-conference.html" title="Notes from MS Developer Conference for Financial Services" /><author><name>Victoria Livschitz</name><uri>http://www.blogger.com/profile/12264301035182704078</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="07316905052902410928" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/03/notes-from-ms-developer-conference.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YMRXkyeCp7ImA9WxZWEks.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-2211018977758265025</id><published>2008-03-10T04:12:00.000-07:00</published><updated>2008-03-11T11:46:24.790-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-11T11:46:24.790-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gigaspaces" /><category scheme="http://www.blogger.com/atom/ns#" term="filesystems" /><category scheme="http://www.blogger.com/atom/ns#" term="~Kirill Uvaev" /><category scheme="http://www.blogger.com/atom/ns#" term="grid computing" /><category scheme="http://www.blogger.com/atom/ns#" term="convergence" /><title>DataGridFS - let your legacy code store data into IMDG</title><content type="html">The one of the most discussed topics on grid computing here in &lt;a href="http://www.griddynamics.com/"&gt;Grid Dynamics&lt;/a&gt; is bringing Computational Grids and In Memory Data Grids together. And DataGridFS concept was born in such discussions.&lt;br /&gt;&lt;br /&gt;First of all, let me describe where it applies most efficiently. There are a lot of systems, which are built around Computational Grid where jobs produce files as result of computations. These files stored to NFS, so they are accessible locally after mounting on every node and client. &lt;a href="http://gridengine.sunsource.net/"&gt;Sun Grid Engine&lt;/a&gt; and &lt;a href="http://www.platform.com/Products/platform-lsf-family/platform-lsf/product"&gt;Platform LSF&lt;/a&gt; are examples of such Computational Grids. Imagine that such system needs enhancement and such enhancement is based on bringing IMDG in this system. So, the codebase will consist of legacy code which saves results to files and modern code which uses IMDG API to get initial values and store results too. More over, these two parts should communicate with each other somehow. For example, results calculated by legacy code are initial values for new codebase jobs. It is clear, that we need the way to make new jobs able to process results stored in files on file system. There are several ways to achieve that. One is to build daemon process which scans directory on filesystem with results, parse them and stores data into IMDG using it's provided API. This approach has few cons. At least you should be able that this process is always alive and so on. The second way which is to use DataGridFS.&lt;br /&gt;&lt;br /&gt;DataGridFS is filesystem which stores files transparently in IMDG itself. So, this filesystem inherits most features of used IMDG. For example, if IMDG allows partitioning then filesystem automatically becomes distributed and so on. So, when job process writes file to filesystem object (or set of objects) appears in IMDG. This object can be accessed using regular IMDG API or DataGridFS API which just "wrappers" for IMDG API calls. "What is about file content?", you may ask, "Is it still to be parsed in object model?" Yes, but this can be done by workers inside IMDG, which is more convenient and flexible way than separate process.&lt;br /&gt;&lt;br /&gt;I've managed to code very simple prototype to illustrate idea. It is just read-only filesystem built using &lt;a href="http://fuse.sourceforge.net/"&gt;FUSE&lt;/a&gt; and &lt;a href="http://sourceforge.net/projects/fuse-j"&gt;FUSE-J&lt;/a&gt;. File data stored with &lt;a href="http://www.gigaspaces.com/pr_xap.html"&gt;GigaSpaces XAP&lt;/a&gt;. On the &lt;a href="http://www.griddynamicsconsulting.com/upload/blog/spacefs-experiment1.png"&gt;screenshot&lt;/a&gt; you can see space content via Space Browser, and the same content via UNIX command line  utils.&lt;br /&gt;&lt;br /&gt;&lt;span style="display: block; text-align: center"&gt;&lt;a href="http://www.griddynamicsconsulting.com/upload/blog/spacefs-experiment1.png" target="_blank"&gt;&lt;img src="http://www.griddynamicsconsulting.com/upload/blog/spacefs-experiment1.png" title="Screenshot" alt="Screenshot" height="350" width="503" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;(Click to enlarge)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-2211018977758265025?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/2211018977758265025/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=2211018977758265025" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2211018977758265025?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2211018977758265025?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/Wldsg5u6WlQ/datagridfs-let-your-legacy-code-store.html" title="DataGridFS - let your legacy code store data into IMDG" /><author><name>Kirill Uvaev</name><uri>http://www.blogger.com/profile/00360201692259660350</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="16926792326225647122" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/03/datagridfs-let-your-legacy-code-store.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGQHs7fip7ImA9WxZXFUo.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8344989838492452867</id><published>2008-03-03T01:15:00.000-08:00</published><updated>2008-03-03T11:13:41.506-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-03T11:13:41.506-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Kirill Ishanov" /><category scheme="http://www.blogger.com/atom/ns#" term="deployment" /><category scheme="http://www.blogger.com/atom/ns#" term="maven 2" /><category scheme="http://www.blogger.com/atom/ns#" term="gigapult" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><category scheme="http://www.blogger.com/atom/ns#" term="convergence" /><title>GigaSpaces Cluster Bootstrapping and Automated Testing</title><content type="html">In projects which use GigaSpaces XAP it's often needed to have a set of functional tests which verify the interaction of your code and GigaSpaces cluster. For example, if an application makes initial data loading it's good to have a test that verifies that the client's code really found a space and loaded all necessary data.&lt;br /&gt;&lt;br /&gt;To implement such tests we need to bootstrap a cluster with an appropriate configuration and to run a set of tests for this cluster. It can be achieved by following the next steps:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Use a testing framework which allows to run some set up code before running group of tests (looks like &lt;a href="http://testng.org/doc"&gt;TestNG&lt;/a&gt; is the most appropriate choice for it cause it allows to group tests and has a sexy @BeforeGroups annotation)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Put all the code which starts a cluster to the set up method (kinda of prerequisites for tests)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Implement a functional test which uses the standard assertion mechanism to verify the cluster's state&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;This approach looks very useful, but the 2nd point is very tricky cause GigaSpaces (5.* and 6.0*) doesn't provide a mechanism, which will allow to start a cluster from code without black magic and dances with tambourine.&lt;br /&gt;&lt;br /&gt;Here is a tricky workaround (which we've used on a &lt;a href="http://www.openspaces.org/display/CVG/Convergence"&gt;Convergence&lt;/a&gt; project for testing purposes). It assumes the usage of &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt; as a build tool (sorry Maven folks, I know that it's project management framework, but this definition sounds too mysterious :) ) and the project is a multi-module.&lt;br /&gt;&lt;br /&gt;The idea behind it is very simple: to perform a cluster bootstrapping via Maven plugin before testing phase. I haven't found the appropriate plugin in Maven's repository so I wrote my own using Gigapult (check the &lt;a href="http://www.openspaces.org/display/GPT/Maven+Gigapult+Plugin+Usage+Guide"&gt;usage&lt;/a&gt; and &lt;a href="http://www.openspaces.org/display/GPT/Maven+Gigapult+Plugin+Installation+Guide"&gt;installation instructions&lt;/a&gt; on OpenSpaces.org).&lt;br /&gt;&lt;br /&gt;Such approach allows to write the functional tests using a testing framework of your choice without putting cluster configuration and bootstrapping code into the setup methods. Moreover, it simplifies the creation of different build configurations on &lt;a href="http://en.wikipedia.org/wiki/Continuous_integration"&gt;Continuous Integration server&lt;/a&gt;, cause it turns the configuration to the simple enumeration of Maven goals.&lt;br /&gt;&lt;br /&gt;But putting the cluster bootstrapping to the build lifecycle and a functional tests, which can take much more time, then an impatient developer can wait, leads to the skipping of these phases. To avoid it, all time-consuming tests can be put to the separate module and run on demand using Maven's profiles. To create such configuration add a submodule to the Maven project (it can be done using the &lt;a href="http://maven.apache.org/plugins/maven-archetype-plugin/"&gt;Maven Archetype Plugin&lt;/a&gt;) and adding the following section to the parent pom.xml:&lt;br /&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff"&gt;profiles&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff"&gt;profile&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff"&gt;id&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;functional-tests&lt;font color="#0000ff"&gt;&amp;lt;/id&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff"&gt;modules&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000ff"&gt;module&lt;/font&gt;&lt;font color="#0000ff"&gt;&amp;gt;&lt;/font&gt;functional-tests&lt;font color="#0000ff"&gt;&amp;lt;/module&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;/modules&amp;gt;&lt;/font&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#0000ff"&gt;&amp;lt;/profile&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;&amp;lt;/profiles&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;After that, Maven will add the sub-module called "functional-tests" only if &lt;span style="font-family: monospace;"&gt;-Pfunctinal-tests&lt;/span&gt; was specified. Assuming that CI server supports Maven now we can specify goals for two build configurations:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;&lt;span style="font-family: monospace;"&gt;clean install&lt;/span&gt; - for running all unit test and packaging&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;span style="font-family: monospace;"&gt;gigapult:gsm gigapult:gsc gigapult:pudeploy install -Pfunctional-tests&lt;/span&gt; - for running all unit tests, packaging, bootstrapping cluster and running functional tests (gigapult goals depend on cluster configuration)&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8344989838492452867?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8344989838492452867/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8344989838492452867" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8344989838492452867?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8344989838492452867?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/pzZHhdmX4nM/gigaspaces-cluster-bootstrapping-and.html" title="GigaSpaces Cluster Bootstrapping and Automated Testing" /><author><name>kylichuku</name><uri>http://www.blogger.com/profile/14008911434054389383</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10293433558291559807" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2008/02/gigaspaces-cluster-bootstrapping-and.html</feedburner:origLink></entry></feed>
