<?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:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0cEQHwzeip7ImA9WhVUGE0.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308</id><updated>2012-05-23T13:30:01.282-07:00</updated><category term="Mockito" /><category term="Waters" /><category term="binary calculator" /><category term="~Eugene Steinberg" /><category term="amazon ec2" /><category term="coherence" /><category term="~Kirill Shileev" /><category term="Amazon" /><category term="~Kirill Ishanov" /><category term="convergence" /><category term="~Alexey Bokov" /><category term="gogrid" /><category term="open source" /><category term="RIA" /><category term="PackRat" /><category term="HTTP" /><category term="grid dynamics" /><category term="~Alexey Kharlamov" /><category term="~Victoria Livschitz" /><category term="EC2" /><category term="~Dmitry Korotkov" /><category term="Powermock" /><category term="~Olga Kudryavtseva" /><category term="~Max Martynov" /><category term="~Andrey Klochkov" /><category term="visualization" /><category term="scalability" /><category term="QA" /><category term="~Alexander Tivelkov" /><category term="semantic web" /><category term="~Alexey Ragozin" /><category term="~Roman Bogorodskiy" /><category term="Hyper-V" /><category term="memory" /><category term="gemfire" /><category term="cloud" /><category term="gigaspaces" /><category term="~Andrey Brindeyev" /><category term="flex" /><category term="data grid" /><category term="LDAP" /><category term="~Sylvia Kainz" /><category term="POF" /><category term="enterprise applications" /><category term="~Max Gorbunov" /><category term="grid computing" /><category term="~Kirill Uvaev" /><category term="data synapse" /><category term="testing" /><category term=".NET" /><category term="Microsoft HPC" /><category term="hpc" /><category term="capacity" /><category term="Velocity" /><category term="distributed cache" /><category term="CI" /><category term="data aware routing" /><category term="graph" /><category term="maven 2" /><category term="~Alexander Kusnetsov" /><category term="jclouds" /><category term="filesystems" /><category term="python" /><category term="GridGain" /><category term="~Victor Samoylov" /><category term="Hadoop" /><category term="Conference" /><category term="RabbitMQ" /><category term="Spring" /><category term="~Shravan Kumar" /><category term="gigapult" /><category term="~Mikhail Khludnev" /><category term="Networks" /><category term="~Stan Klimoff" /><category term="~Dmitri Babaev" /><category term="~Max Morozov" /><category term="~Oleg Malakhov" /><category term="~Ivan Bulanov" /><category term=".Net 4.0" /><category term="openstack" /><category term="~Arseny Kaplun" /><category term="rackspace" /><category term="cloud computing" /><category term="deployment" /><category term="lucene" /><category term="Sun Grid Engine" /><category term="~Eugene Kirpichev" /><category term="indexing" /><category term="Open Source Grid and Cluster Conference" /><category term="Java" /><category term="grid consulting" /><category term="C#" /><category term="Pig" /><category term="Remoting" /><category term="search" /><category term="Hessian" /><category term="openspaces.org" /><category term="Solr" /><category term="management" /><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="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><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>68</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;D0cEQHY6eip7ImA9WhVUGE0.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7832207577379613268</id><published>2012-05-23T13:30:00.000-07:00</published><updated>2012-05-23T13:30:01.812-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-23T13:30:01.812-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="QA" /><category scheme="http://www.blogger.com/atom/ns#" term="CI" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><title>Ignoring test failures at CI</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;&lt;/b&gt;&lt;br /&gt;
&lt;h2 dir="ltr"&gt;


&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;Problem&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Today, I want to talk about one obvious issue which occurs when your code and tests are written by the different people and you have a properly established &lt;a href="http://en.wikipedia.org/wiki/Continuous_integration"&gt;CI&lt;/a&gt; process. In this scenario, tests appear in VCS first, because without a test the code &lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Continuous_integration#Make_the_build_self-testing"&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;can’t be committed&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;, but this test breaks the build. Obviously, test author skips it or disables it from CI test suite until this functionality is actually implemented. I believe that this is not the best practice, because it leads to a lot of wasted efforts from both dev and QA teams. Let’s look at what’s going on in typical project team:&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;h2 dir="ltr"&gt;

&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;
&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;Commit&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;
&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Developer checks out the disabled test for his new feature from VCS, runs it, and checks that the code is ready. Now he’s able to commit the code. He does it, but unfortunately makes two usual mistakes: he performs one-line-improvement right before commit without full test run (of course, what can possibly go wrong?); and he forgets to commit one property file. Doesn’t it happen to you? Really? &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;h2 dir="ltr"&gt;
&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;

&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;Test&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;b id="internal-source-marker_0.6568898633122444" style="text-align: -webkit-auto;"&gt;
&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Then he pings the test’s author, - Hey! I’ve done it. Check your test pls. Tester needs to run a private build to verify that all code changes have been committed, and then enables the test for CI. If tester skips the private build phase, which can include pulling snapshot or build and creating deployment, you’ll have CI failure without genuine code issue. &lt;/span&gt;&lt;br /&gt;&lt;h2 dir="ltr"&gt;


&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;What it should be &lt;/span&gt;&lt;/h2&gt;
&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;Just free tester from the unnecessary private build and testing cycle. Let CI work for you. Don’t skip test from CI suite, let it run and fail without impacting the build status. Tester sets the expectation for functionality, and let developers reach it, without a necessity to verify an uncommitted code. &lt;/span&gt;&lt;br /&gt;&lt;h2 dir="ltr"&gt;


&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;Tooling&lt;/span&gt;&lt;/h2&gt;
&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;JUnit&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt; has only one workaround - &lt;/span&gt;&lt;a href="http://junit.sourceforge.net/javadoc/org/junit/Assume.html#assumeTrue(boolean)"&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;assumeTrue&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;, which allows to mark failed test as skipped. To introduce a fancier way you need to &lt;/span&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;a href="http://stackoverflow.com/questions/4055022/mark-unit-test-as-an-expected-failure-in-junit"&gt;write your Runner&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;TeamCity&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt; has nice looking &lt;b id="internal-source-marker_0.6568898633122444" style="font-family: 'Times New Roman'; font-size: medium; white-space: normal;"&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt; &lt;/span&gt;&lt;a href="http://confluence.jetbrains.net/display/TCD65/Muting+Test+Failures"&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;“mute” feature&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;. Nice work, JetBrains!&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;TestNG&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt; has &lt;b id="internal-source-marker_0.6568898633122444" style="font-family: 'Times New Roman'; font-size: medium; white-space: normal;"&gt;&lt;a href="http://testng.org/javadoc/org/testng/annotations/Test.html#successPercentage()"&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;something&lt;/span&gt;&lt;/a&gt;&lt;/b&gt; along these lines. I&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;t works fine, but surefire doesn’t support it &lt;/span&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;a href="http://jira.codehaus.org/browse/SUREFIRE-654"&gt;doesn’t support it&lt;/a&gt;.&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;"&gt;JBehave&lt;/span&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt; has &lt;a href="http://jbehave.org/reference/stable/running-stories.html"&gt;ignoreFailureInView&lt;/a&gt; property, but it belongs to whole suite not for paticular test. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;h2 dir="ltr"&gt;


&lt;span style="font-family: Arial; font-size: 19px; vertical-align: baseline; white-space: pre-wrap;"&gt;Credits&lt;/span&gt;&lt;/h2&gt;
&lt;span style="font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;I realized that some time ago but decide to post after found the same concern in the &lt;/span&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;a href="http://mail-archives.apache.org/mod_mbox/lucene-dev/201205.mbox/%3Calpine.DEB.2.00.1205041516210.3541@bester%3E"&gt;mail thread&lt;/a&gt;.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;b style="text-align: -webkit-auto;"&gt;&lt;span style="color: #1155cc; font-family: Arial; font-size: 15px; font-weight: normal; vertical-align: baseline; white-space: pre-wrap;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7832207577379613268?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7832207577379613268/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7832207577379613268" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7832207577379613268?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7832207577379613268?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/w06t7tY0J18/ignoring-test-failures-at-ci.html" title="Ignoring test failures at CI" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2012/05/ignoring-test-failures-at-ci.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMBSXczfCp7ImA9WhdaFUs.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8194295765385379678</id><published>2011-10-25T10:28:00.000-07:00</published><updated>2011-10-25T10:40:58.984-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-25T10:40:58.984-07:00</app:edited><title>Highlights from our OpenStack-specific blog</title><content type="html">&lt;p&gt;A few highlights from our &lt;a href="http://openstackgd.wordpress.com/"&gt;OpenStack blog&lt;/a&gt;:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://openstackgd.wordpress.com/2011/10/06/how-we-build-packages-in-grid-dynamics-using-gear-mock/"&gt;How our RHEL port is built and tested, using Gear + Mock&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://openstackgd.wordpress.com/2011/10/03/cloudpipe-setting-up-vpn-for-projects/"&gt;Setting up VPN for projects with CloudPipe&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://openstackgd.wordpress.com/2011/10/06/using-nova-instead-of-eucatools-while-working-with-keypairs/"&gt;Using SSH keys with novaclient&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://openstackgd.wordpress.com/2011/10/12/improving-novaclient-cli-flexibility-with-ssh-keys-while-booting-server/"&gt;Improving novaclient CLI: boot a server with specific SSH key&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Also, for those who do not follow our OpenStack blog closely, OpenStack Diablo release is out for both &lt;a href="http://openstackgd.wordpress.com/2011/10/03/openstack-2011-3-release/"&gt;RHEL&lt;/a&gt; and &lt;a href="http://openstackgd.wordpress.com/2011/10/04/diablo-centos-build/"&gt;CentOS&lt;/a&gt; (version 6, as usual). &lt;a href="http://openstackgd.wordpress.com/2011/10/05/source-code-for-diablo-packages/"&gt;Sources&lt;/a&gt; are available as well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8194295765385379678?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8194295765385379678/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8194295765385379678" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8194295765385379678?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8194295765385379678?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/wDj8rEy2fZk/highlights-from-our-openstack-specific.html" title="Highlights from our OpenStack-specific blog" /><author><name>Stan Klimoff</name><uri>http://www.blogger.com/profile/14586894425559474017</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/10/highlights-from-our-openstack-specific.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIHQX4zeCp7ImA9WhdUFkU.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-573639735676487931</id><published>2011-10-03T01:16:00.001-07:00</published><updated>2011-10-03T16:28:50.080-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-03T16:28:50.080-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Solr" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="lucene" /><category scheme="http://www.blogger.com/atom/ns#" term="~Oleg Malakhov" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="search" /><title>Solr Experience: search parent-child relations. Part III</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div&gt;In the previous posts (&lt;a href="http://blog.griddynamics.com/2011/06/solr-experience-search-parent-child.html"&gt;part I&lt;/a&gt; and &lt;a href="http://blog.griddynamics.com/2011/07/solr-experience-search-parent-child.html"&gt;part II&lt;/a&gt;)  I presented &amp;nbsp;challenges in searching parent-child relations by Solr, a  couple of workarounds and handsome final solution - SpanQueries.&lt;br /&gt;&lt;br /&gt;In  this post I will describe the infrastructure for SpanQueries we’ve  built inside Solr . It includes indexing, query parsing (creating  SpanQueries), caching filter queries, faceting and sorting.&lt;br /&gt;&lt;h2&gt;Indexing&lt;/h2&gt;Fist  of all I should say that we use SolrJ - embedded Solr server, and this  section is about adding documents into Solr by its’ Java API only.&lt;br /&gt;&lt;br /&gt;If you put a collection of values into &lt;a href="http://lucene.apache.org/solr/api/org/apache/solr/common/SolrInputDocument.html#addField%28java.lang.String,%20java.lang.Object%29"&gt;SolrInputDocument.addField(“field”, values)&lt;/a&gt; with &lt;i&gt;termPositions=”true”&lt;/i&gt; in schema.xml, Solr will interpret them as several different terms for one field and for each value it sets position to 0.&lt;br /&gt;&lt;br /&gt;The straightforward approach is adding all values as one text string (e. g. “red blue green”) and using analyzer (&lt;a href="http://lucene.apache.org/java/3_3_0/api/core/org/apache/lucene/analysis/standard/StandardAnalyzer.html"&gt;StandardAnalyzer&lt;/a&gt;  works fine), which adds proper term positions into the index. In this  case, if we want to index several numbers, we have to add them as one  string, e. g. “123.45 42.15 98.27”. It’s not useful, so we implemented  field types for String, Integer, Double and Float. They create Field  instance with special &lt;a href="http://lucene.apache.org/java/3_3_0/api/core/org/apache/lucene/analysis/TokenStream.html"&gt;TokenStream&lt;/a&gt;, which uses List as a source and saves &amp;nbsp;positions (indexes in List). &lt;br /&gt;&lt;h2&gt;Parsing SpanQueries&lt;/h2&gt;By default Solr uses &lt;a href="http://lucene.apache.org/solr/api/org/apache/solr/search/LuceneQParserPlugin.html"&gt;LuceneQParser&lt;/a&gt;  plugin &amp;nbsp;to parse user queries and create Lucene Queries. We created a  wrapper for it - SpanQParserPlugin - which transforms regular  BooleanQueries and TermQueries into SpanQueries. Then we registered it  in solrconfig.xml:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;queryParser name="span" class="com.griddynamics.solr.spans.SpanQParserPlugin"/&amp;gt;&lt;br /&gt;&lt;br /&gt;This plugin transforms BooleanQuery with AND clause into SpanNearQuery(...) and BooleanQuery with OR clause into SpanOrQuery.&lt;br /&gt;As result the query ”&lt;i&gt;fq={!span tag=spanFQ}+color:Red +size:XL&lt;/i&gt;” is parsed into:&lt;br /&gt;SpanNearQuery(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SpanTermQuery("color", "Red”),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FieldMaskingSpanQuery(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SpanTermQuery("size", "XL"),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; “color”&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ), -1, false&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;Here &lt;i&gt;{!span}&lt;/i&gt; is &lt;a href="http://wiki.apache.org/solr/SolrPlugins#QParserPlugin"&gt;defType local param&lt;/a&gt;. It says to Solr to use SpanQParserPlugin and spanFQ is a &lt;a href="http://wiki.apache.org/solr/SimpleFacetParameters#Tagging_and_excluding_Filters"&gt;tag&lt;/a&gt; we will use for faceting later.&lt;br /&gt;Please be informed that there are a couple of better ways to extend query parsing. &lt;br /&gt;&lt;h2&gt;Filter queries caching&lt;/h2&gt;Solr  caches docSets (materialized FilterQuery results, which are intersected  on searching) and docLists (ranked query results that store document  lists). But they are not enough for us, because for faceting we need  spans, which passed the filter.&lt;br /&gt;&lt;br /&gt;We’ve created SpanQueryFilterCache for this - it’s similar to &lt;a href="http://lucene.apache.org/java/3_3_0/api/core/org/apache/lucene/search/SpanFilterResult.html"&gt;SpanFilterResult&lt;/a&gt;  but uses primitives and arrays instead wrappers and collections. It  stores spans which were found by SpanQuery in the user cache provided by  Solr. To get spans we call SpanQueryFilterCache.getSpans(spanQuery,  solrIndexSearcher) that initializes the cache lazily and gets spans by  spanQuery key. &lt;br /&gt;&lt;h2&gt;Faceting&lt;/h2&gt;I suppose it’s the most interesting part of this article. &lt;br /&gt;Standard  field faceting mechanism calculates counts of documents that contain  field value. It doesn’t fit for us, because we need to count facets on  the matched spans only (parts of a document).&lt;br /&gt;&lt;br /&gt;To count span facets we made a special component SpanFacetComponent, which is activated with the parameter &lt;i&gt;span.facet.field&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;The query for searching Red sweaters and count facets for size and color fields looks like this:&lt;br /&gt;&lt;div dir="ltr" style="margin-bottom: 0pt; margin-top: 0pt; text-align: center;"&gt;q={!span tag=spanFQ}+color:Red&amp;amp;facet=true&amp;amp;&lt;i&gt;span.facet.field={!by=spanFQ aggOp=unique}color&amp;amp;span.facet.field={!by=spanFQ aggOp=unique}size&lt;/i&gt;&lt;/div&gt;And we have a Product, which passes the filter:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fbxHxhYoqV4/TolxlJPWjHI/AAAAAAAAABE/bmmx9tXYQBg/s1600/picture_p3_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-fbxHxhYoqV4/TolxlJPWjHI/AAAAAAAAABE/bmmx9tXYQBg/s1600/picture_p3_01.png" /&gt;&lt;/a&gt;&lt;/div&gt;Only  two of its’ Items pass the filter and must be counted for faceting. The  tag “spanFQ” (see above) gets SpanQuery instance and uses  SpanQueryFilterCache to enumerate matched spans. It works for &lt;i&gt;color&lt;/i&gt; and &lt;i&gt;size&lt;/i&gt; fields, because span doesn’t have a field and we can count &lt;i&gt;size&lt;/i&gt; facet by spans matched by &lt;i&gt;color&lt;/i&gt; filter. For counting facets we need field values on matched spans. We get from the use &lt;i&gt;forward view of data&lt;/i&gt; - UnInvertedSpans (it’s allusion to &lt;a href="https://issues.apache.org/jira/browse/SOLR-475"&gt;UnInvertedField&lt;/a&gt;; it stores mapping {(docId, spanNum) -&amp;gt; {termNum}}).&lt;br /&gt;&lt;br /&gt;We  have two Items, which passed the filter, but we have a constraint that a  single document increases facet count for a value only once i.e.  document gives a &lt;i&gt;set&lt;/i&gt; of values (not a bag&lt;i&gt;)&lt;/i&gt; for facet counts. The match above gives {Red,XL,XXL}. To determine which span should be counted we use &lt;i&gt;aggOp&lt;/i&gt; (aggregation operation) parameter that can be one of three values:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;unique - each unique value increases facet count;&lt;/li&gt;&lt;li&gt;first - only first span value increases facet count;&lt;/li&gt;&lt;li&gt;last - only last span value increases facet count.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The last two operations are used for calculating min/max price (here we use &lt;i&gt;natural ordering&lt;/i&gt; enforced during indexing, instead honest query time min/max). It’s worth to implement min/max operations also. &lt;br /&gt;&lt;h2&gt;Sorting&lt;/h2&gt;Our  Product can have several prices. To sort by price we need to use  different values depending on sorting direction: for ascending - min  price, for descending - max price.&lt;br /&gt;The  solution is store prices aligned by positions and SpanQueries to get a  price values for sorting. During indexing we put prices in the Product  document in ascending order. In query time we use SpanQuery and  UnInvertedSpans to get spans with prices and then our  MultiValueFieldComparatorSource uses value from first (on asc) or last  (on desc) span for sorting. For example, our query with additional price  filter and sorting by price field will be:&lt;br /&gt;&lt;div dir="ltr" style="margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt;"&gt;&lt;i&gt;q={!span tag=spanFQ}+color:Red&lt;/i&gt;&lt;/div&gt;&lt;div dir="ltr" style="margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;i&gt;&amp;amp;fq={!span tag=priceFQ}+price:[5 TO 15]&lt;/i&gt;&lt;/div&gt;&lt;div dir="ltr" style="margin-bottom: 0pt; margin-left: 36pt; margin-top: 0pt; text-indent: 36pt;"&gt;&lt;i&gt;&amp;amp;sort.field={!bySpanFQ=priceFQ}price ASC&lt;/i&gt;&lt;/div&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;That’s  all. We hope our experience and ideas will help someone to resolve his  or her issues about parent-child relations. In future we want to try  storing two or more terms for one field in one position - by this way we  want to handle the same issues with multi-valued field.&lt;br /&gt;We  also work on deeper understanding of the problem and building a  powerful model of nested documents on inverted lists. One of the last  findings is that ‘&lt;i&gt;false positive matching on multi-value fields&lt;/i&gt;’ is well-known &lt;a href="http://db.grussell.org/section005.html"&gt;Fan Trap&lt;/a&gt; in ER-modelling.&lt;br /&gt;&lt;br /&gt;There is a considerable alternative approach &lt;a href="https://issues.apache.org/jira/browse/LUCENE-3171"&gt;LUCENE-3171&lt;/a&gt;. It’s a little bit raw at the moment, but the idea is promising.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-573639735676487931?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/573639735676487931/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=573639735676487931" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/573639735676487931?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/573639735676487931?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/QjOU1Sh64ww/solr-experience-search-parent-child.html" title="Solr Experience: search parent-child relations. Part III" /><author><name>Oleg Malakhov</name><uri>http://www.blogger.com/profile/11727670030574361153</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-fbxHxhYoqV4/TolxlJPWjHI/AAAAAAAAABE/bmmx9tXYQBg/s72-c/picture_p3_01.png" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/10/solr-experience-search-parent-child.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IGQXk8eCp7ImA9WhdSGEU.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6343873243968971608</id><published>2011-07-27T23:32:00.001-07:00</published><updated>2011-07-28T14:45:20.770-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T14:45:20.770-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="indexing" /><category scheme="http://www.blogger.com/atom/ns#" term="Solr" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="lucene" /><category scheme="http://www.blogger.com/atom/ns#" term="~Oleg Malakhov" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="search" /><title>Solr Experience: search parent-child relations. Part II</title><content type="html">In  the &lt;a href="http://blog.griddynamics.com/2011/06/solr-experience-search-parent-child.html"&gt;previous post&lt;/a&gt; I presented an e-Commerce site that sells sweaters. I  showed how we tried to implement Faceted Navigation with Solr, found  the problem with the multi-valued field for searching parent-child  relations. I also proposed a workaround that solves the problem but that  is far from perfect.&lt;br /&gt;&lt;br /&gt;In this post I’ll describe the ultimate solution - SpanQueries.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;SpanQuery&lt;/h2&gt;SpanQueries are purposed for &lt;a href="http://en.wikipedia.org/wiki/Proximity_search_%28text%29"&gt;proximity search&lt;/a&gt;,  which considers terms’ positions inside text. Lucene can index terms’  positions in addition to terms. For example, “crazy cat and crazy dog”  gives us the following inverted index:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-5f-fIwGigRw/TjED9RCVeaI/AAAAAAAAAA4/8YQVxeKI3Ig/s1600/picture_p2_01.png" /&gt;&lt;/div&gt;Word “and” is excluded as stop word.&lt;br /&gt;&lt;br /&gt;SpanQuery considers that terms’ positions during searching. &lt;a href="http://lucene.apache.org/java/3_0_3/api/all/org/apache/lucene/search/spans/package-summary.html"&gt;Span&lt;/a&gt; - is a term position range or tuple that contains document ID and start and end  positions. A term can have several spans per document. There is a  basement method SpanQuery.getSpans(...), which returns iterator for  matched documents and spans.&lt;br /&gt;&lt;br /&gt;SpanQuery - is an abstract class, there are several its descendants. You can find their description in &lt;a href="http://www.lucidimagination.com/blog/2009/07/18/the-spanquery/"&gt;the post &amp;nbsp;in the Lucid Imagination blog&lt;/a&gt; and &lt;a href="http://www.amazon.com/Lucene-Action-Second-Covers-Apache/dp/1933988177"&gt;"Lucene In Action" book&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We are interested in three of them:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://lucene.apache.org/java/2_9_0/api/core/org/apache/lucene/search/spans/SpanTermQuery.html"&gt;SpanTermQuery&lt;/a&gt; - finds all spans by the term;&lt;/li&gt;&lt;li&gt;&lt;a href="http://lucene.apache.org/java/2_9_0/api/core/org/apache/lucene/search/spans/SpanNearQuery.html"&gt;SpanNearQuery&lt;/a&gt; - combines several SpanQueries considering the distance between matched spans;&lt;/li&gt;&lt;li&gt;&lt;a href="http://lucene.apache.org/java/2_9_0/api/core/org/apache/lucene/search/spans/FieldMaskingSpanQuery.html"&gt;FieldMaskingSpanQuery&lt;/a&gt; - masks SpanQuery by one field as query by another field.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Now let’s take a look at how do we use this SpanQueries to search parent-child relations.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Parent-child relations with SpanQueries&lt;/h2&gt;We index Products in a way when attributes of each Item are located on the same position:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-wgc-KOeKx9M/TjED_TTYOJI/AAAAAAAAAA8/Q_EyzHd8i5o/s1600/picture_p2_02.png" /&gt;&lt;/div&gt;&lt;br /&gt;Combining  the SpanTermQueries with FiledMaskingSpanQuery and putting them inside  SpanNearQuery allows searching the intersections of the terms'  positions, and properly find the Product, which contains the specified  Item (color:Red and size:XL):&lt;br /&gt;SpanNearQuery(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SpanTermQuery("color", "Red”),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; FieldMaskingSpanQuery(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SpanTermQuery("size", "XL"),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; “color”&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ), -1, false&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;This query returns the only documents, which have color:Red and size:XL at the same position i.e. belonging to the same Item:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-kujNds_ptH4/TjED_6oTuBI/AAAAAAAAABA/6hY-95AAWEs/s1600/picture_p2_03.png" /&gt;&lt;/div&gt;The third product (Style&amp;amp;co.) is not returned, because its' terms "Red" and "XL" are located in different positions.&lt;br /&gt;&lt;br /&gt;We've  got what we want out-of-the box. But there is another problem: Solr  doesn't have any infrastructure for supporting SpanQueries. In the next  post I will tell about how do we bring SpanQueries into the Solr,  including interesting issues of caching, faceting and sorting.&lt;br /&gt;&lt;br /&gt;P. S.: recently we found the &lt;a href="http://www.slideshare.net/MarkHarwood/proposal-for-nested-document-support-in-lucene"&gt;similar approach had been proposed&lt;/a&gt; and ongoing work in Lucene core (see &lt;a href="https://issues.apache.org/jira/browse/LUCENE-2454"&gt;LUCENE-2454&lt;/a&gt;, &lt;a href="https://issues.apache.org/jira/browse/LUCENE-3133"&gt;LUCENE-3133&lt;/a&gt;, &lt;a href="https://issues.apache.org/jira/browse/LUCENE-3171"&gt;LUCENE-3171&lt;/a&gt;). Looking forward for incorporating this feature in Solr.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-6343873243968971608?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6343873243968971608/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6343873243968971608" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6343873243968971608?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6343873243968971608?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/ZU9mdC54Nj8/solr-experience-search-parent-child.html" title="Solr Experience: search parent-child relations. Part II" /><author><name>Oleg Malakhov</name><uri>http://www.blogger.com/profile/11727670030574361153</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-5f-fIwGigRw/TjED9RCVeaI/AAAAAAAAAA4/8YQVxeKI3Ig/s72-c/picture_p2_01.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/07/solr-experience-search-parent-child.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04MRn8_cCp7ImA9WhRUE00.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1306114694043780707</id><published>2011-07-02T11:26:00.000-07:00</published><updated>2012-01-22T22:59:47.148-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-22T22:59:47.148-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring" /><title>Spring Nested - Part III</title><content type="html">&lt;div&gt;﻿In the previous posts &lt;a href="http://blog.griddynamics.com/2011/04/spring-nested-part-i-why.html"&gt;I&lt;/a&gt;, &lt;a href="http://blog.griddynamics.com/2011/04/spring-nested-part-ii-what.html"&gt;II&lt;/a&gt; I told you how we came up with our own Service Locator framework based on Spring. Frankly speaking, a root application context creates child application contexts and keeps a services registry, where the child contexts advertise and look up service beans by names. Today I will tell you about two vital features.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Handling Web Requests&lt;/b&gt;&lt;/div&gt;&lt;div&gt;We use &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html"&gt;Spring MVC&lt;/a&gt; to expose platform services via Web. To handle Web requests WAR should has &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping"&gt;handlers&lt;/a&gt; or &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-controller"&gt;controllers&lt;/a&gt; declared in Spring application context. In our platform all business logic resides in component contexts aka child contexts. Therefore, a component developer declares request handlers and controllers in component context, but Spring MVC’s &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-servlet"&gt;DispatcherServlet&lt;/a&gt; looks for request handlers in the root context only. So, we need to pass the request to these controller/handler beans declared in the target child context. We went through three approaches below one by one:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;the first was really explicit: child contexts publish their Web request handlers to the service registry. Root context contains a special request handlers, every of which delegates a request to a handler obtained from service registry by the specified name. So, we had to amend the root config xml when a new web handler appears in any component;&lt;/li&gt;&lt;li&gt;then, we introduced the handler mapping registry in the root context. Child contexts have factory beans register the child request handlers in that registry. Thus, the registry can handle a request by looking up a child handler by an URL and delegating request to it. That’s better than the first approach because we don’t need to update the root config xml on introducing a new request handler. But it was too far from non-invasive approach, i.e. we had to consider these declarations when add a new handler;&lt;/li&gt;&lt;li&gt;the final approach is completely implicit: root context has the same child handler mapping registry (url -&amp;gt; handler), but it’s populated automatically during scanning the child contexts for handler/controller beans. Then, this mapping registry handles requests by delegating them to particular child handlers found by an url. As result, component developer doesn’t care about the framework when he delivers a new Web request handler.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;In contrast to Spring DM way we have a single WAR with the single &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-servlet"&gt;DispatcherServlet&lt;/a&gt; contains the several Web components. &lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Component Initialization and Dependencies&lt;/b&gt;&lt;/div&gt;&lt;div&gt;It’s the most feature I am proud of. To instantiate all child contexts we need to know a correct initialization sequence - which child context goes after which. Initially we relied on the list of config XMLs explicitly provided in the root context. Then, we found problems with this straightforward approach, e.g.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;absence or fail of one export breaks the related lookup;&lt;/li&gt;&lt;li&gt;a looked up bean (which is actually a proxy) can be accessed before its’ context initialization.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;We decided to implement Dependency Analyzer that verifies dependencies across child contexts before any child context initialization. &lt;/div&gt;&lt;div&gt;How have we done it? We rejected the idea of parsing Spring context XMLs to analyze dependencies, just because we had two XML formats already. Spring has quite extensible and elegant design: &lt;a href="http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/xml/XmlBeanDefinitionReader.html"&gt;BeanDefinitionReader&lt;/a&gt; parses XML and passes &lt;a href="http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/config/BeanDefinition.html"&gt;BeanDefinitions&lt;/a&gt; to &lt;a href="http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/support/BeanDefinitionRegistry.html#registerBeanDefinition(java.lang.String, org.springframework.beans.factory.config.BeanDefinition)"&gt;BeanDefinitionRegistry&lt;/a&gt;. For default flow BeanDefinitionRegistry is an ApplicationContext, which creates singleton bean instances etc. But we can run this routine against a fake one: &lt;a href="http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/support/SimpleBeanDefinitionRegistry.html"&gt;SimpleBeanDefinitionRegistry&lt;/a&gt; that just keeps bean definitions in a map . Then analyzer can iterate through bean definitions, recognize exports and lookups, verify it, raise concerns and/or arrange initialization order. Here is the list of rules which analyzer enforces now:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;verifies that an every bean class is exist in classpath;&lt;/li&gt;&lt;li&gt;warns unnecessary exports (without any lookup);&lt;/li&gt;&lt;li&gt;prohibits imports without a matching export;&lt;/li&gt;&lt;li&gt;prohibit dependency cycles between contexts (a but allows to resolve them manually in “god mode”);&lt;/li&gt;&lt;li&gt;orders child context initialization considering exports before to imports;&lt;/li&gt;&lt;li&gt;finds a minimal list of the components which are required for running the given sub-set of services (transitively finds the dependent contexts);&lt;/li&gt;&lt;li&gt;skips the dependent contexts after a some context initialization failure;&lt;/li&gt;&lt;li&gt;outputs the derived component dependencies graph into debug log in &lt;a href="http://www.graphviz.org/"&gt;Graph Viz&lt;/a&gt; format.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Some of these features just spot the trivial errors and reduce the number of log lines to look through. Remaining features provide a flexible and robust container for our platform.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally I’d like to spot a significant difference between Spring DM and Spring Nested. Spring DM has an &lt;a href="http://static.springsource.org/osgi/docs/2.0.0.M1/reference/html/bnd-app-ctx.html"&gt;asynchronous ad-hoc initialization&lt;/a&gt; which is too complex and inconvenient sometimes. Spring Nested proposes a single thread deterministic initialization. It’s rigid enough - prohibits cycles, but flexible - you code against services, don’t care about a component initialization sequence. And it’s developer friendly: you shouldn't change you Spring habits much; troubleshooting is easy as possible with the reduced logs and the preliminary checks. &lt;/div&gt;&lt;div&gt;If you accept some simplifications, which has been made in Spring Nested design this framework can help you with your large Spring application.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;The Real Life Application&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Here is the modules dependencies graph of our application that is built with Spring Nested. This graph is derived from the services references by the dependency analyzer and logged in Graph Viz text format on startup.&lt;/div&gt;&lt;div&gt;&lt;a href="http://3.bp.blogspot.com/-b-uP89ncdQ4/Tg9yd4GGS2I/AAAAAAAAADM/sVGT8sY-mMQ/s1600/universe_grey.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 78px;" src="http://3.bp.blogspot.com/-b-uP89ncdQ4/Tg9yd4GGS2I/AAAAAAAAADM/sVGT8sY-mMQ/s400/universe_grey.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5624840317208775522" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I smudged the component names at this picture just to avoid NDA aspects. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Further Plans&lt;/b&gt;&lt;/div&gt;&lt;div&gt;We want to open its’ source. Please let us know if you are interested in it or leave a valuable feedback and ideas.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1306114694043780707?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1306114694043780707/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1306114694043780707" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1306114694043780707?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1306114694043780707?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/5jmo-FaiEfE/spring-nested-part-iii.html" title="Spring Nested - Part III" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-b-uP89ncdQ4/Tg9yd4GGS2I/AAAAAAAAADM/sVGT8sY-mMQ/s72-c/universe_grey.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/07/spring-nested-part-iii.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUADSH48cCp7ImA9WhZbFUQ.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-2688718753579819198</id><published>2011-06-06T07:15:00.000-07:00</published><updated>2011-06-20T11:16:19.078-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-20T11:16:19.078-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="indexing" /><category scheme="http://www.blogger.com/atom/ns#" term="Solr" /><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="lucene" /><category scheme="http://www.blogger.com/atom/ns#" term="~Oleg Malakhov" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="search" /><title>Solr Experience: search parent-child relations. Part I</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Typical e-Commerce sites provide a catalog of products with filtration (or search by criteria). We implement such catalog with&amp;nbsp;&lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; search server based on &lt;a href="http://lucene.apache.org/"&gt;Apache Lucene&lt;/a&gt; library.&lt;br /&gt;&lt;br /&gt;A catalog entries usually have parent-child relations and search must consider these relations. Unfortunately Solr documents are flat and some straightforward approaches e.g. several indexes, denormalization have been rejected because of efficiency and implementation efforts.&lt;br /&gt;&lt;br /&gt;In this post I describe the problem and some possible approaches.&lt;br /&gt;&lt;h2&gt;E-Commerce site&lt;/h2&gt;&lt;b&gt;Product&lt;/b&gt;&amp;nbsp;is the model of any goods which are sold on the site. A product has attributes like Brand, Occasion etc. You can’t buy a Product, you can buy an &lt;b&gt;Item&lt;/b&gt;&amp;nbsp;- a concrete instance of the Product, which has such attributes like Color, Size, Length, etc. Also every Item shares Product’s attributes.&lt;br /&gt;&lt;br /&gt;For example, if you &lt;a href="http://www.shopadidas.com/search/index.jsp?kwCatId=&amp;amp;kw=nizza%20hi&amp;amp;origkw=Nizza%20Hi&amp;amp;sr=1"&gt;search "Nizza Hi" on www.shopadidas.com site&lt;/a&gt;, you see different sneakers of the single model ("Men's Originals Nizza Hi Shoes"). They have different colors, therefore they are Items. Then&amp;nbsp;&lt;a href="http://www1.macys.com/search/index.ognc?SearchTarget=*&amp;amp;Keyword=Nizza+Hi&amp;amp;KEYWORD_GO_BUTTON.x=0&amp;amp;KEYWORD_GO_BUTTON.y=0&amp;amp;KEYWORD_GO_BUTTON=KEYWORD_GO_BUTTON"&gt;search the same on Macys.com&lt;/a&gt; - you see the only pair of sneakers. If you look to its' page, you see that there are several colors available. The Macys.com search result contains Product, not Items.&lt;br /&gt;&lt;br /&gt;Let's have a site, where we sell sweaters with different colors and sizes (Items). There are three brands and each brand is presented as separate Product. The list of all available Items:&lt;span class="BRAND"&gt;&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;i&gt;&lt;span class="BRAND"&gt;Alfani&lt;/span&gt;&lt;/i&gt;:&lt;ul type="disc"&gt;&lt;li&gt;Red - XL&lt;/li&gt;&lt;li&gt;Red - XXL&lt;/li&gt;&lt;li&gt;Blue - XL&lt;/li&gt;&lt;li&gt;Green - L&lt;/li&gt;&lt;li&gt;Green - XXL&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;span class="BRAND"&gt;Calvin Klein&lt;/span&gt;&lt;/i&gt;:&lt;ul type="disc"&gt;&lt;li&gt;Red - XL&lt;/li&gt;&lt;li&gt;Blue - M&lt;/li&gt;&lt;li&gt;Blue - L&lt;/li&gt;&lt;li&gt;Green - M&lt;/li&gt;&lt;li&gt;Green - XL&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;span class="BRAND"&gt;Style&amp;amp;co.&lt;/span&gt;&lt;/i&gt;:&lt;ul type="disc"&gt;&lt;li&gt;Red - M&lt;/li&gt;&lt;li&gt;Blue - XXL&lt;/li&gt;&lt;li&gt;Blue - XL&lt;/li&gt;&lt;li&gt;Green - S&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;To provide a better usability we need to show three Products instead of twelve Items, and allow&amp;nbsp;to filter them by color and size i.e. to provide &lt;a href="http://www.lucidimagination.com/Community/Hear-from-the-Experts/Articles/Faceted-Search-Solr"&gt;Faceted Navigation&lt;/a&gt;.&lt;br /&gt;&lt;ol&gt;&lt;/ol&gt;For example, a client need Red shoes with XL size. Therefore, the site must show Products that contain Items with &lt;i&gt;color:Red and size:XL&lt;/i&gt; only:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;&lt;span class="BRAND"&gt;Alfani&lt;/span&gt;&lt;/b&gt;:&lt;ul type="disc"&gt;&lt;li&gt;&lt;b&gt;Red - XL&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Red - XXL&lt;/li&gt;&lt;li&gt;Blue - XL&lt;/li&gt;&lt;li&gt;Green - L&lt;/li&gt;&lt;li&gt;Green - XXL&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;span class="BRAND"&gt;Calvin Klein&lt;/span&gt;&lt;/b&gt;:&lt;ul type="disc"&gt;&lt;li&gt;&lt;b&gt;Red - XL&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Blue - M&lt;/li&gt;&lt;li&gt;Blue - L&lt;/li&gt;&lt;li&gt;Green - M&lt;/li&gt;&lt;li&gt;Green - XL&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="BRAND"&gt;Style&amp;amp;co.&lt;/span&gt;:&lt;ul type="disc"&gt;&lt;li&gt;Red - M&lt;/li&gt;&lt;li&gt;Blue - XXL&lt;/li&gt;&lt;li&gt;Blue - XL&lt;/li&gt;&lt;li&gt;Green - S&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;I’ve highlighted with bold font Items and Products passed the filter. The third Product (&lt;span class="BRAND"&gt;Style&amp;amp;co.&lt;/span&gt;) doesn’t match the filter. Although it has Items with Red color and XL size, but it doesn’t contain any Item with both Red color and XL size we are looking for.&lt;br /&gt;&lt;h2&gt;Attemt #1: Two indexes&lt;/h2&gt;The first intention is using Solr as database: to create separate indexes for Items and Products. Thus we can get the result with two Solr-queries:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;find all Items passed the filter;&lt;/li&gt;&lt;li&gt;find all Products that contain Items we got on the previous step.&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;/ol&gt;The logic seems working, but further investigation has shown two problems:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Pagination - usually we want to show not the whole result, but only 10, 30, 50, or 100 Products. But it's very expensive to query all Items (number of them can be huge) and than pass them inside the second query for getting first N Products;&lt;/li&gt;&lt;li&gt;Faceting -&amp;nbsp; we have to write a lot of custom code around Solr to calculate all facet counts from the result of the first query. Also the first query result must contain product ID, which is expensive.&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;/ol&gt;Thus this approach was rejected.&lt;br /&gt;&lt;h2&gt;Attempt #2: Denormalization&lt;/h2&gt;Denormalization is creating the only index for Items. It's similar to the previous approach, but there are two differences:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;productID field is not stored field, because we need it only for querying;&lt;/li&gt;&lt;li&gt;Faceting requires custom code too, but it can be placed inside Solr within own Components. They use Solr/Lucine internal data structures and much faster than post-processing the result.&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;/ol&gt;There is another problem - result collapsing. We need Products as final result, not Items. Solr’s FiledCollapsing can be used for this but it has a little bit different purpose. We ended up with our own collapser.&lt;br /&gt;&lt;br /&gt;Thid approach is not flexible: small requirements changes impact the codebase a lot.&lt;br /&gt;We've got that the document granularity should match the search result.&lt;br /&gt;&lt;h2&gt;Attempt #3: Item Attributes' Promotion&lt;/h2&gt;Then we came back to the Product index. The question was how to index Items inside Product documents with keeping their identity for filtering. Here we come to the attributes’ promotion approach: item’s attributes (sub-documents) are promoted into the multi-value document fields.&lt;br /&gt;But doing it straightforward we met the &lt;i&gt;false&lt;/i&gt; &lt;i&gt;positive multi-value field match problem&lt;/i&gt;. Let's look to Lucene documents:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mvLF7SQv2WY/TeeF21MKPGI/AAAAAAAAAAU/vVNIM7z4yc0/s1600/picture_01_v2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-mvLF7SQv2WY/TeeF21MKPGI/AAAAAAAAAAU/vVNIM7z4yc0/s1600/picture_01_v2.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&amp;nbsp; &lt;/div&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;I highlighted with bold font the result for query &lt;i&gt;color:Red and size:XL&lt;/i&gt;. The third Product “&lt;span class="BRAND"&gt;Style&amp;amp;co.&lt;/span&gt;” is presented in the result table, but it must be filtered out (see our example above), because it doesn’t contain any Items with both Red color and XL size we are looking for.&lt;br /&gt;&lt;br /&gt;After we realized this problem, we moved to...&lt;br /&gt;&lt;h2&gt;Attempt #4: Term Encoding&lt;/h2&gt;The solution was quite brave - we solved it with an accurate term encoding. We introduced a composite terms for keeping an Item identity. For example:&lt;br /&gt;&lt;br /&gt;&lt;span class="BRAND"&gt;Alfani&lt;/span&gt;:&lt;br /&gt;&lt;ul type="disc"&gt;&lt;li&gt;Red - XL : &lt;i&gt;RedXL&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Red - XXL : &lt;i&gt;RedXXL&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Blue - XL : &lt;i&gt;BlueXL&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Green - L : &lt;i&gt;GreenL&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Green - XXL : &lt;i&gt;GreenXXL&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;As result you can find a document by an item attributes combination and avoid a false match for absent items like RedXL. We also had to generate all subsets of attribute values. Thus the full list of generated terms for our example looks like:&lt;br /&gt;&lt;div style="text-align: center;"&gt;Red, XL, RedXL, XXL,  RedXXL, Blue, BlueXL, Green, L, GreenL, GreenXXL.&lt;/div&gt;The findability is solved (because &lt;span class="BRAND"&gt;Style&amp;amp;co.&lt;/span&gt; doesn't have term RedXL, which we are looking for), but we still needed a proper faceting. Honestly speaking we faceted such composite fields with Tokenizer and  HashMap (a kind of brute force).&lt;br /&gt;&lt;br /&gt;We knew that this approach is far from perfect due to performance and scalability issues and the complex processing in query time. That's why we continued to find a more robust approach.&lt;br /&gt;&lt;h2&gt;Part I: Conclusion&lt;/h2&gt;Keep in mind that the described issue takes place with almost any case, when your search result contains the documents with any form of hierarchy. We actually met two instances of that:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;product document has an item sub-documents (which is not presented as a separate documents itself);&lt;/li&gt;&lt;li&gt;product documents are grouped by another documents reside in the index;&lt;/li&gt;&lt;li&gt;document has associations with another entity encoded by a term (it seems like relation sub-document).&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;/ol&gt;In the next part I will introduce the silver bullet - SpanQueries. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-2688718753579819198?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/2688718753579819198/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=2688718753579819198" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2688718753579819198?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2688718753579819198?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/9G1ULxLl9jQ/solr-experience-search-parent-child.html" title="Solr Experience: search parent-child relations. Part I" /><author><name>Oleg Malakhov</name><uri>http://www.blogger.com/profile/11727670030574361153</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-mvLF7SQv2WY/TeeF21MKPGI/AAAAAAAAAAU/vVNIM7z4yc0/s72-c/picture_01_v2.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/06/solr-experience-search-parent-child.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUcBSXg7eSp7ImA9WhZUEEs.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6808317930895353577</id><published>2011-06-02T19:09:00.000-07:00</published><updated>2011-06-02T19:10:58.601-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-02T19:10:58.601-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Understanding GC pauses in JVM, HotSpot's CMS collector.</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;
&lt;div class="MsoNormal"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(previous artictle "&lt;a href="http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots.html"&gt;Understanding GC pauses in JVM, HotSpot's minor GC&lt;/a&gt;")&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;Concurrent Mark Sweep (CMS) is one of HotSpot JVM low pause garbage collectors. CMS can do most of its work for reclaiming memory concurrently with application (without stopping it). But still it requires few stop-the-world pauses to make its work. This article will explain nature of these pauses and how to minimize them.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;b&gt;Basics of concurrent mark sweep&lt;/b&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;HotSpot’s CMS is a generational collector, it means that heap is separated into young and old (tenured) space and these spaces are collected independently. For young space collection usual HotSpot’s copy collector is use (see &lt;a href="http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots.html"&gt;previous article&lt;/a&gt; about HotSpot’s young space collector). Concurrent Mark Sweep is used only to collect old space.&amp;nbsp;&lt;span style="font-size: 11pt; line-height: 115%;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;To enable of using CMS collector you have to specify&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New'; font-size: 15px; line-height: 17px;"&gt;–&lt;/span&gt;&lt;span style="font-family: 'Courier New'; font-size: 11pt; line-height: 115%;"&gt;XX:&lt;/span&gt;&lt;span style="font-family: 'Courier New'; font-size: 11pt; line-height: 115%;"&gt;+UseConcMarkSweepGC&lt;/span&gt;&lt;span style="font-size: 11pt; line-height: 115%;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt; in JVM’s command line.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;CMS collection cycle has following phases:&lt;/div&gt;&lt;ul style="margin-top: 0in;" type="disc"&gt;&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;Initial mark – this is      stop-the-world phase while CMS is collecting root references.&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;&amp;nbsp;Concurrent mark – this phase is done      concurrently with application, garbage collector traverses though object      graph in old space marking live objects.&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;Concurrent pre clean –      this is another concurrent phase, basically it is another mark phase which      will try to account references changed during previous mark phase. Main      reason for this phase is reduce time of stop-the-world remark phase.&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;Remark – once concurrent      mark is finished, garbage collector need one more stop-the-world pause to      account references which have been changed during concurrent mark phase.&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;Concurrent sweep – garbage      collector will scan through whole old space and reclaim space occupied by      unreachable objects.&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;Concurrent reset – after      CMS cycle is finished, some structures have to be reset before next cycle      can start.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="MsoNormal"&gt;Unlike most other garbage collectors, CMS does not do compaction of heap space. Instead of moving objects to make unoccupied space continuous, CMS keeps lists of all fragments of free memory. This way CMS is avoiding cost associated with relocating of live objects (and relocating of objects is expensive operation which require stop-the-world pause), but as down size of this heap space is prone to fragmentation. To minimize risk of fragmentation CMS is doing statistical analysis of object’s sizes and have separate free lists for objects of different sizes.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;b&gt;Length of CMS pauses&lt;/b&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;CMS itself has only two pauses, but your application will also experience pauses of young space collector which is working in conjunction with CMS. See previous article about pauses of young space collector.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;Initial mark&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;During&amp;nbsp;&amp;nbsp; initial mark CMS should collect all root references to start marking of old space. This includes:&lt;/div&gt;&lt;ul style="margin-top: 0in;" type="disc"&gt;&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;References from thread      stacks,&lt;/li&gt;
&lt;li class="MsoNormal" style="mso-list: l0 level1 lfo1;"&gt;References from young space.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="MsoNormal" style="text-align: justify;"&gt;References from stacks are usually collected very quickly (less than 1ms), but time to collect references from young space depends on size of objects in young space. Normally initial mark starts right after young space collection, so Eden space is empty and only live objects are in one of survivor space. Survivor space is usually small and initial mark after young space collection often takes less than millisecond. But if initial mark is started when Eden is full it may take quite long (usually longer than young space collection itself).&lt;/div&gt;&lt;div class="MsoNormal"&gt;Once CMS collection is triggered, JVM may wait some time for young collection to happen before it will start initial marking. JVM configuration option &lt;span style="font-family: 'Courier New';"&gt;–XX:CMSWaitDuration=&lt;t&gt;&lt;/t&gt;&lt;/span&gt; can be used to set how long CMS will wait for young space collection before start of initial marking. If you want to avoid long initial marking pauses, you should configure this time to be longer than typical period of young collections in your application.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;Remark&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Most of marking is done in parallel with application, but it may not be accurate because application may modify object graph during marking. When concurrent marking is finished; garbage collector should stop application and repeat marking to be sure that all reachable objects marked as alive. But collector doesn’t have to traverse through whole object graph; it should traverse only reference modified since start of marking (actually since start pre clean phase). Card table (see card marking write barrier) is used to identify modified portions of memory in old space, but thread stacks and young space should be scanned once again.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&amp;nbsp;Usually most time of remark phase is spent of scanning young space. This time will be much shorter if we collect garbage in young space before starting of remark. We can instruct JVM to always force young space collection before CMS remark. Use JVM parameter &lt;span style="font-family: 'Courier New';"&gt;–XX:+CMSScavengeBeforeRemark&lt;/span&gt; to enable this option.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Even is young space is empty, remark phase still have to scan through modified references in old space, this usually takes time close to normal young collection pause (due scanning of old space done during young collection is similar to scanning required for remark).&amp;nbsp;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;b&gt;When CMS collection starts?&lt;/b&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Unlike stop-the-world old space collectors, CMS collection cycle should start before old space become full. CMS collection is triggered when amount of free memory in old space falls below certain threshold (this threshold can be chosen by JVM based of runtime statistics or set via parameters) and actual start of CMS collection cycle may be delayed until next young collection.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Normally objects are allocated in old space only during young space collection (which may promote some objects to old space). So CMS cycle usually starts right after young space collection, which is good because init mark pause will be very small.&lt;/div&gt;&lt;span style="font-size: 11pt; line-height: 115%;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;But in certain cases object may be allocated directly in old space and CMS cycle could start while Eden has lots of objects. In this case initial mark can be 10-100 times slower which is bad. Usually this is happening due to allocation of very large objects (few megabyte arrays). &amp;nbsp;To avoid these long pauses you should configure reasonable &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: 'Courier New'; font-size: 11pt; line-height: 115%;"&gt;–XX:CMSWaitDuration&lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="color: #666666; font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b&gt;&lt;i&gt;Configuring fixed threshold for CMS start&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="line-height: 17px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;You can set fixed threshold for olds space occupation for triggering CMS cycle by using JVM options&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt; &lt;span style="font-family: 'Courier New';"&gt;‑XX:+UseCMSInitiatingOccupancyOnly ‑XX:CMSInitiatingOccupancyFraction=70&lt;/span&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;(this will force CMS cycle to start when more than 70% of old space is used).&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="color: #666666; font-size: 15px;"&gt;&lt;i&gt;&lt;b&gt;Explicitly invoking CMS cycle&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;You can also configure JVM to start CMS cycle by invocation of System.gc() by &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span style="font-family: 'Courier New';"&gt;‑XX:+ExplicitGCInvokesConcurrent&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;command line option.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;Full GC with CMS&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal" style="font-size: 15px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;If CMS cannot free enough in old space, JVM may fallback to compacting collector. Compacting collector will force stop-the-world pause so it can be considered emergency case. Normally you would like to avoid full GC and long stop-the-world pause associated with it. Full GC may happen either if CMS is not fast enough for dealing with garbage (or collection cycle has been started too late) or due to fragmentation of old space (there is no large enough continuous space for object to be allocated). Also it is possible that you just didn’t give JVM enough memory and after full GC it will through &lt;span style="font-family: 'Courier New';"&gt;OutOfMemoryExpection&lt;/span&gt; anyway.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;Permanent generation collection&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;One of reasons why CMS may end up in full GC is garbage in permanent space. By default CMS does not reclaim unused space in permanent space. If your application is using multiple class loaders and/or reflection you may need to enable collecting of garbage in permanent space. JVM option &lt;span style="font-family: 'Courier New';"&gt;‑XX:+CMSClassUnloadingEnabled&lt;/span&gt; will allow CMS collector to clean permanent space. Remember that objects in permanent space may have references to normal old space thus even if permanent space is not full itself, references from perm to old space may keep some dead objects unreachable for CMS if class unloading is not enabled.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;&lt;i&gt;&lt;b&gt;Utilizing multiple cores&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;CMS has multiple phases. Some of them are concurrent; others are stop-the-world pauses but may be executed in parallel to compressed application freeze time.&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;  &lt;/span&gt;&lt;br /&gt;
&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span style="font-family: 'Courier New';"&gt;‑XX:+CMSConcurrentMTEnabled&lt;/span&gt; – allows CMS to use multiple cores for concurrent phase.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span style="font-family: 'Courier New';"&gt;‑XX:+ConcGCThreads=&lt;n&gt;&lt;/n&gt;&lt;/span&gt; – specifies number of thread for concurrent phases.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span style="font-family: 'Courier New';"&gt;‑XX:+ParallelGCThreads=&lt;n&gt;&lt;/n&gt;&lt;/span&gt; – specifies number of thread for parallel work during stop-the-world pauses (by default it equals to number of physical cores).&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;span style="font-family: 'Courier New';"&gt;‑XX:+UseParNewGC&lt;/span&gt; – instructs JVM to use parallel collector for young space collections in conjunction with CMS.&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;&lt;b&gt;Comming soon:&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;&lt;b&gt;Tuning CMS collector for large IMDG storage nodes&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span class="Apple-style-span" style="font-family: inherit;"&gt; &lt;/span&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&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-6808317930895353577?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6808317930895353577/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6808317930895353577" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6808317930895353577?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6808317930895353577?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/qHJp0lRIyVM/understanding-gc-pauses-in-jvm-hotspots_02.html" title="Understanding GC pauses in JVM, HotSpot's CMS collector." /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots_02.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08NR3Y5eyp7ImA9WhZUE0g.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7584924187610960896</id><published>2011-06-01T03:04:00.000-07:00</published><updated>2011-06-06T04:31:36.823-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-06T04:31:36.823-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Understanding GC pauses in JVM, HotSpot's minor GC.</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Stop-the-world pauses of JVM due to the work of garbage collector are known foes of java-based applications. HotSpot JVM has a set of very advanced and tunable garbage collectors, but to find optimal configuration it is very important to understand an exact mechanics of garbage collection algorithms. This article is first of the series explaining how exactly GC spends our precious CPU cycles during stop-the-world pauses. An algorithm for young space garbage collection in HotSpot is explained in this post.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Structure of heap&lt;/b&gt;&lt;br /&gt;
Most of modern GCs are generational. That means that java heap memory is separated into few "spaces". Spaces are usually distinguished by “age” of resident objects. Objects are allocated in young space, then eventually copied to old (or tenured) space, if they survive long enough. This principle is based on hypothesis that most object “die young”, i.e. majority of objects become garbage shortly after being allocated. All HotSpot garbage collectors separate memory into 5 spaces (though for G1 collector spaces may be not continuous).&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-NwrMpaA2Wf8/TeYGgmdzLXI/AAAAAAAAI0c/GeBQSgDhXQE/s1600/blog-6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-NwrMpaA2Wf8/TeYGgmdzLXI/AAAAAAAAI0c/GeBQSgDhXQE/s1600/blog-6.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Eden are space there objects are allocated,&lt;br /&gt;
•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Survivor spaces are used to receive object during young (or minor GC),&lt;br /&gt;
•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Tenured space is for long lived objects,&lt;br /&gt;
•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Permanent space is for JVM own objects (like classes and JITed code), it is behaves just like tenured space so we will ignore it for rest of article.&lt;br /&gt;
Eden and 2 survivor spaces together are called young space.&lt;br /&gt;
&lt;div&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;HotSpot GC algorithms overview&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;HotSpot JVM is implementing few algorithms for GC which are combined in few possible GC profiles.&amp;nbsp;&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Serial generational collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseSerialGC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Parallel for young space, serial for old space generational collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseParallelGC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Parallel young and old space generational collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseParallelOldGC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Concurrent mark sweep with serial young space collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseConcMarkSweepGC&lt;/span&gt;&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;–XX:-UseParNewGC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Concurrent mark sweep with parallel young space collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseConcMarkSweepGC&lt;/span&gt; &lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;–XX:+UseParNewGC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;G1 garbage collector (&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+UseG1GC&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;All profiles except G1 are using almost same young space collection algorithms (with serial vs parallel variations).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Write barrier&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Key point of generational GC is what it does need to collect entire heap each time, but just portion of it (e.g. young space). But to achieve this JVM have to implement special machinery called “write barrier”. There 2 types of write barriers implemented in HotSpot: dirty cards and snapshot-at-the-beginning (SATB). SATB write barrier is used in G1 algorithms (which is not covered in this article). All other algorithms are using dirty cards.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #444444;"&gt;Dirty cards write barrier&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Principle of dirty card write-barrier is very simple. Each time when program modifies reference in memory, it should mark modified memory page as dirty. There is a special card table in JVM and each 512 byte page of memory has associated byte in card table.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-4BSXuryn7Ss/TeYHvOqwltI/AAAAAAAAI0g/kfH9vN0KgrI/s1600/blog-7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-4BSXuryn7Ss/TeYHvOqwltI/AAAAAAAAI0g/kfH9vN0KgrI/s1600/blog-7.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;Young space collection algorithm&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Almost all new objects (there are few exception when new object can be allocated directly in old space) are allocated in Eden space. To be more effective HotSpot is using thread local allocation blocks (TLAB) for allocation of new objects, but TLAB themselves are allocated in Eden. Once Eden becomes full minor GC is triggered. Goal of minor GC is to clear fresh garbage in Eden space. Copy-collection algorithm is used (live objects are copied to another space, and then whole space is marked as free memory). But before start collecting live objects, JVM should find all root references. Root references for minor GC are references from stack and all references from old space.&lt;/div&gt;&lt;div&gt;Normally collection of all reference from old space will require scanning through all objects in old space. That is why we need write-barrier. All objects in young space have been created (or relocated) since last reset of write-barrier, so non-dirty pages cannot have references into young space. This means we can scan only objects in dirty pages.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-JeoPvpns3II/TeYILJO5mnI/AAAAAAAAI0k/rIuloiOSZ-I/s1600/blog-8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-JeoPvpns3II/TeYILJO5mnI/AAAAAAAAI0k/rIuloiOSZ-I/s1600/blog-8.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Once initial reference set is collected, dirty cards are reset and JVM starts coping of live objects from Eden and one of survivor spaces into other survivor space. JVM only need to spend time on live objects. Relocating of object also requires updating of references pointing to it.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ooT_iuZ694I/TeYIcAQrbgI/AAAAAAAAI0o/x4dy6cb2dyA/s1600/blog-9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-ooT_iuZ694I/TeYIcAQrbgI/AAAAAAAAI0o/x4dy6cb2dyA/s1600/blog-9.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Finally we have Eden and one survivor space clean (and ready for allocation) and one survivor space filled with objects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #444444;"&gt;Object promotion&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;If object is not cleared during young GC it will be eventually copied (promoted) to old space. Promotion occurs in following situations:&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:+AlwaysTenure&lt;/span&gt; &amp;nbsp;makes JVM to promote objects directly to old space instead of survivor &amp;nbsp;space (survivor spaces are not used in this case).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;once survivor space is full, all remaining live object are relocated directly to old space.&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;If object has survived certain number of young space collections, it will be promoted to old space (required number of collections can be adjusted using &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;–XX:MaxTenuringThreshold&lt;/span&gt; option and &lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;–XX:TargetSurvivorRatio&lt;/span&gt; JVM options).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #444444;"&gt;&lt;i&gt;&lt;b&gt;Allocation of new objects in old space&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;It would be beneficial if we could possibly allocate long lived objects directly in old space. Unfortunately there is no way to instruct JVM to do this for particular object. But there are few cases when object can be allocated directly in old space.&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;Option &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;-XX:PretenureSizeThreshold=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&amp;nbsp;instructs JVM what all objects larger &amp;nbsp;than &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&amp;nbsp;bytes should be allocated directly in old space (though if object size fits TLAB, JVM will allocate it in TLAB and thus young space, so you should also limit TLAB size).&lt;/div&gt;&lt;div&gt;•&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;If object is larger than size of Eden space it also will be allocated in old space.&lt;/div&gt;&lt;div&gt;Unlike application objects, system objects are always allocated by JVM directly in permanent space.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #444444;"&gt;Parallel execution&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Most of task during young space collection can be done in parallel. If there are several CPUs available, JVM can utilize them to compress duration of stop-the-world pause during collection. Number of threads can be configured in HotSpot JVM by &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;–XX:ParallelGCTreads=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&amp;nbsp;parameter. By default JVM will choose number of thread by number of available CPU. As expected, serial version of collector will ignore this parameter because it can use only one CPU. Using parallel collection reduces time of stop-the-world pause by factor close to number of physical cores.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Measuring stop-the-world pause for young collection&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Young space collection happens during stop-the-world pause (all non-GC-related threads in JVM are suspended). Wall clock time of stop-the-world pause is very important factor for applications (especially applications requiring fast response time). Parallel execution affects wall clock time of pause but not work effort to be done.&amp;nbsp;&lt;/div&gt;&lt;div&gt;Let’s summarize components of young GC pause. Total pause time can be written as:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="MsoNormal"&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;young&lt;/sub&gt; = T&lt;sub&gt;stack_scan&lt;/sub&gt; +&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 21px;"&gt;T&lt;sub&gt;card_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;&amp;nbsp;+ T&lt;sub&gt;old&lt;/sub&gt;_&lt;sub&gt;scan&lt;/sub&gt;+ T&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt; &lt;/span&gt;; there &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;young&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt; &lt;/span&gt;is total time of young GC pause, &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;stack_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt; &lt;/span&gt;is time to scan root in stacks, &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;old&lt;/sub&gt;_&lt;sub&gt;scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt;&amp;nbsp; &lt;/span&gt;is time to scan roots in old space and &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; is time to copy live objects &lt;span style="font-size: 14pt; line-height: 115%;"&gt;(1)&lt;/span&gt;.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;Thread stack are usually very small, so major factors affecting time of young GC is &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;old&lt;/sub&gt;_&lt;sub&gt;scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt; &lt;/span&gt;and &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;.&lt;/div&gt;&lt;div class="MsoNormal"&gt;Another important parameter is frequency of young GC. Period between young collections is mainly determined by application allocation rate (bytes per second) and size of Eden space.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;P&lt;sub&gt;young&lt;/sub&gt; = S&lt;sub&gt;eden&lt;/sub&gt; / R&lt;sub&gt;alloc&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;sub&gt;&lt;span style="font-size: 14pt; line-height: 115%;"&gt; &lt;/span&gt;&lt;/sub&gt;; there &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;P&lt;sub&gt;young&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&amp;nbsp; is period between young GC, &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;S&lt;sub&gt;eden&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; is size of Eden and &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;R&lt;sub&gt;alloc&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; is rate of memory allocations (bytes per second) &lt;span style="font-size: 14pt; line-height: 115%;"&gt;(2)&lt;/span&gt;.&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;stack_scan &lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;– can be considered application specific constant.&lt;br /&gt;
&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-ansi-language: EN-US; mso-bidi-font-size: 11.0pt; mso-bidi-language: EN-US; mso-fareast-font-family: &amp;quot;Times New Roman&amp;quot;; mso-fareast-language: EN-US;"&gt;T&lt;sub&gt;card_scan &lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11.0pt; line-height: 115%; mso-ansi-language: EN-US; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: EN-US; mso-fareast-font-family: &amp;quot;Times New Roman&amp;quot;; mso-fareast-language: EN-US;"&gt;– is proportional to size of old space. Literally, JVM have to check single byte of table for each 512 bytes of heap (e.g. 8G of heap -&amp;gt; 16m to scan).&lt;/span&gt;&lt;!--EndFragment--&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;old&lt;/sub&gt;_&lt;sub&gt;scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 14pt; line-height: 115%;"&gt;&amp;nbsp; &lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;– is proportional to number of dirty cards in old space at the moment of young GC. If we assume that references to young space are distributed randomly in old space, then we can provide following formula for time of old space scanning.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://1.bp.blogspot.com/-D9UacWPh_x4/TeYKoHMc-EI/AAAAAAAAI0s/3YWMMlhNOjA/s1600/blog-10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-D9UacWPh_x4/TeYKoHMc-EI/AAAAAAAAI0s/3YWMMlhNOjA/s1600/blog-10.png" /&gt;&lt;/a&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;; there &lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;S&lt;sub&gt;old&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; is size of old space and &lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;D&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;, &lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;card&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; and &lt;/span&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;n&lt;sub&gt;card&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; are coefficients specific for application &lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 14pt; line-height: 115%;"&gt;(3)&lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;copy &lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;– is proportional to number of live objects in heap. We can approximate it by formula:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-3YjJgH1l3Gc/TeYK9r5iNPI/AAAAAAAAI0w/nYXtPAliYys/s1600/blog-11.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-3YjJgH1l3Gc/TeYK9r5iNPI/AAAAAAAAI0w/nYXtPAliYys/s1600/blog-11.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-weight: bold;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;There &lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;sub&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; &lt;/span&gt;&lt;/sub&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;is effort to copy object, &lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;R&lt;sub&gt;long_live&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; is rate of allocation of long lived objects,&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;"&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 21px;"&gt;k&lt;sub&gt;survive&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;"&gt;&amp;nbsp;=&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 21px;"&gt;R&lt;sub&gt;long_live&amp;nbsp;&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;"&gt;/&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 21px;"&gt;R&lt;sub&gt;alloc&amp;nbsp;&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif; font-size: 15px; line-height: 17px;"&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;(&lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;survive&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; usually very small), and &lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;tenure&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; is a coefficient to approximate aging of object in young space before tenuring (&lt;/span&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;tenure&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt; ≥ 1) &lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 14pt; line-height: 115%;"&gt;(4)&lt;/span&gt;&lt;span style="font-family: Calibri, sans-serif; font-size: 11pt; line-height: 115%;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;Now we can analyze how various JVM options may affect time and frequency of young GC.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;b style="font-weight: bold;"&gt;Size of old space.&lt;/b&gt; Size of old space is affecting &lt;i&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"&gt;T&lt;sub&gt;card_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; and &lt;i&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"&gt;T&lt;sub&gt;old_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; part of young GC pause time according to formulas above. So we as we are increasing size of old space (read total heap size) time of young GC pauses will grow and it can be helped. After certain size of heap (usually 4-8 Gb) time of young collection is dominated by &lt;i&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"&gt;T&lt;sub&gt;card_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; (technically &lt;i&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"&gt;T&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; can be even greater than &lt;i&gt;&lt;span style="font-family: &amp;quot;Times New Roman&amp;quot;,&amp;quot;serif&amp;quot;; font-size: 14.0pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"&gt;T&lt;/span&gt;&lt;/i&gt;&lt;i&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 21px;"&gt;&lt;sub&gt;card_scan&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;, bur it usually can be controlled by tuning of GC options).&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;HotSpot JVM options: &lt;/u&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;-Xmx=&lt;i&gt;n&lt;/i&gt;, -Xms=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Size of Eden space.&lt;/b&gt; Period between young GC is proportional to size of Eden. &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;copy&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; is also proportional to size of eden but in practice &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;survive&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; can be so small that for some applications we can forget about Tcopy. Unfortunately time between young GC will also affect coefficient &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;D&lt;/span&gt;&lt;/i&gt; in equation (4). Though dependency between &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;D&lt;/span&gt;&lt;/i&gt; and &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;P&lt;sub&gt;young&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; is very application specific, increasing &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;P&lt;sub&gt;young&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; will increase &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;D&lt;/span&gt;&lt;/i&gt; and as a consequence &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;T&lt;sub&gt;scan_old&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;HotSpot JVM options: &lt;/u&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;-XX:NewSize=&lt;i&gt;n&lt;/i&gt;, -XX:MaxNewSize=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Size of survivor space.&lt;/b&gt; Size of survivor space puts hard limit of how much objects can stay in young space between collections. Changing size of survivor space may affect &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;tenure &lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;(or mat not, e.g. if &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;tenure &lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;is already 1).&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;HotSpot JVM options: &lt;/u&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;-XX:SurviorRatio=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Max tenuring threshold &lt;/b&gt;and&lt;b style="mso-bidi-font-weight: normal;"&gt; target survivor ratio.&lt;/b&gt; These two JVM options also allow artificially adjust &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;tenure&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;HotSpot JVM options: &lt;/u&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;-XX:TargetSurviorRatio=&lt;i&gt;n&lt;/i&gt;, -XX:MaxTenuringThreshold=&lt;i&gt;n&lt;/i&gt; , -XX:+AlwaysTenure, -XX:+NeverTenure&lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;b style="mso-bidi-font-weight: normal;"&gt;Pretenuring threshold.&lt;/b&gt; For some applications using pretenuring threshold could reduce &lt;i style="mso-bidi-font-style: normal;"&gt;&lt;span style="font-family: 'Times New Roman', serif; font-size: 14pt; line-height: 115%;"&gt;k&lt;sub&gt;survive&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; due to allocation of long lived object directly in old space.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="MsoNormal"&gt;&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;HotSpot JVM options: &lt;/u&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;-XX:PretenureThreshold=&lt;i&gt;n&lt;/i&gt;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;u&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;span style="font-family: inherit;"&gt;&lt;i&gt;(Next article "&lt;a href="http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots_02.html"&gt;Understanding GC pauses in JVM, HotSpot's CMS collector.&lt;/a&gt;")&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Calibri, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;i&gt;&lt;br /&gt;
&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;span style="color: #0b5394; font-family: inherit;"&gt;&lt;i&gt;&lt;b&gt;Comming soon:&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: 15px; line-height: 17px;"&gt;&lt;i&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394; font-family: inherit;"&gt;Tuning CMS collector for large IMDG storage nodes&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7584924187610960896?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7584924187610960896/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7584924187610960896" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7584924187610960896?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7584924187610960896?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/sGD0iiQgl6g/understanding-gc-pauses-in-jvm-hotspots.html" title="Understanding GC pauses in JVM, HotSpot's minor GC." /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-NwrMpaA2Wf8/TeYGgmdzLXI/AAAAAAAAI0c/GeBQSgDhXQE/s72-c/blog-6.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/06/understanding-gc-pauses-in-jvm-hotspots.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4CQ38zcCp7ImA9WhZVGEg.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6101106840079275370</id><published>2011-05-31T02:18:00.000-07:00</published><updated>2011-05-31T09:06:02.188-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-31T09:06:02.188-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="openstack" /><category scheme="http://www.blogger.com/atom/ns#" term="~Andrey Brindeyev" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud computing" /><title>Running 200 VM instances on OpenStack Compute</title><content type="html">&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;&lt;a href="http://openstack.org/projects/compute/"&gt;OpenStack Compute&lt;/a&gt; is an exciting piece of software. It is open, it is evolving rapidly and the community is terrific. However, as with any software that is new to the market, there’s little understanding and hard data on its performance. It’s scalability, for instance, is something that is only known through anecdotes around the watercooler. This post tells a story of a “baby cloud” running in one of our labs.&lt;/p&gt;&lt;p&gt;Our goal is to see how much we can stretch the software until it rips. In this installment, we’ll start with a very basic test — launching 200 virtual machines in parallel.&lt;/p&gt;&lt;h2&gt;Setup and first steps&lt;/h2&gt;&lt;p&gt;The test stand consists of three blades (two X5570 and 48G RAM each). All blades are diskless and SAN-backed. The exact hardware configuration is not relevant, since performance of individual VMs is not relevant for this kind of test.&lt;/p&gt;&lt;p&gt;Test image that was used for test is a stripped installation of RHEL 5.6, packed using QCOW2 (153Mb).&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;All the tests were performed using KVM-based RHEL 6.0 &lt;a href="http://yum.griddynamics.net/"&gt;version of OpenStack Compute&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Here is our /etc/nova/nova.conf for cloud controller node: &lt;script src="https://gist.github.com/996182.js?file=nova.conf.sh"&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;We used the following script to run the VMs: &lt;script src="https://gist.github.com/996182.js?file=run200.sh"&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;We started with a trunk build 1058 of OpenStack Compute.&lt;/p&gt;&lt;h2&gt;First try&lt;/h2&gt;&lt;p&gt;After firing up the script for the first time, we noticed that 3-5% of all machines were not coming up — that is, showing as down when listing instances. This was not completely unexpected, yet still discouraging. Having ten machines out of two hundred failing on the spot is not a good thing.&lt;/p&gt;&lt;p&gt;The investigation showed that connections to Rabbit are frequently timing out. Turned out that we stumbled upon a known bug in the eventlet library: &lt;a href="https://bitbucket.org/which_linden/eventlet/issue/87/socket-connects-are-incorrectly-reported"&gt;socket connects are incorrectly reported as timed out&lt;/a&gt;. Patch to eventlet and &lt;a href="https://code.launchpad.net/~cbehrens/nova/rpc-improvements"&gt;improvements in RPC code&lt;/a&gt; helped us to eliminate the Rabbit timeout issue and bring down the error rate significantly. Kudos to Chris Behrens and Soren Hansen for the solution.&lt;/p&gt;&lt;h2&gt;Second try&lt;/h2&gt;&lt;p&gt;The error rate went down, but it was still above zero. Looked like we’ve stumbled on a race condition. Logs showed traces of exceptions about releasing locks. It turned out that the problem was in synchronization while creating VLANs. Simply adding a lock on the VLAN creation (&lt;a href="http://bazaar.launchpad.net/~hudson-openstack/nova/trunk/revision/1097"&gt;bzr1097&lt;/a&gt;) made the problem go away — kudos to Vish Ishaya.&lt;/p&gt;&lt;h2&gt;Third try&lt;/h2&gt;&lt;p&gt;Now all instances show up as running, but are they actually usable?&lt;/p&gt;&lt;p&gt;“Usable” may mean many things, depending on how thorough you are. We have some pretty sophisticated test suites that can verify if a cloud instance is healthy for most practical purposes. But in this case, a simple  ping of the VMs from outside to see if they respond was sufficiently informative.&lt;/p&gt;&lt;p&gt;The result was somewhat unexpected and bizarre: we could ping only 150 instances on network while API was indicating that all 200 were running. Run 150 instances… all 150 are responding. 180… 150 are responding. 151… again only 150 are responding. Looked like we stumbled on some sort of a limit.&lt;/p&gt;&lt;p&gt;Investigation showed that the problem is in dnsmasq, which has default DHCP lease cap at 150. Took some time to figure this one out, but very straightforward to fix — &lt;a href="http://bazaar.launchpad.net/~hudson-openstack/nova/trunk/revision/1100"&gt;bzr1100&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Finally, the two hundred nodes were able to run without a hitch. Here’s one for the team!&lt;/p&gt;&lt;h2&gt;Some random data&lt;/h2&gt;&lt;p&gt;For those who want more data, here go a couple pretty graphs.&lt;/p&gt;&lt;p&gt;We ran two different configurations — one with two compute nodes, another with three (the third one being co-located with CC).&lt;/p&gt;&lt;p&gt;&lt;em&gt;Fig 1. Two compute nodes, dedicated cloud controller.&lt;/em&gt;&lt;a href="http://1.bp.blogspot.com/-TLeBzRVFlik/TeAVcH_WAmI/AAAAAAAABOc/8BgAwp8w2KY/s1600/two_nodes.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="display: block;cursor:pointer; cursor:hand;width: 320px; height: 178px;" src="http://1.bp.blogspot.com/-TLeBzRVFlik/TeAVcH_WAmI/AAAAAAAABOc/8BgAwp8w2KY/s320/two_nodes.png" border="0" id="BLOGGER_PHOTO_ID_5611508708628890210" /&gt;&lt;/a&gt;Total startup time: 12 minutes 6 seconds.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Fig 2. Three compute nodes, co-located cloud controller.&lt;/em&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-dT7SNGLxnVE/TeAVvJcQcZI/AAAAAAAABOk/QTLJNs4zpbY/s1600/three_nodes.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="display: block;cursor:pointer; cursor:hand;width: 320px; height: 178px;" src="http://3.bp.blogspot.com/-dT7SNGLxnVE/TeAVvJcQcZI/AAAAAAAABOk/QTLJNs4zpbY/s320/three_nodes.png" border="0" id="BLOGGER_PHOTO_ID_5611509035436110226" /&gt;&lt;/a&gt;&lt;br /&gt;Total startup time: 8 minutes 20 seconds.&lt;/p&gt;&lt;p&gt;Though this is hardly conclusive, co-locating cloud controller with one of the compute nodes is not necessary a bad idea, at least from the performance standpoint.&lt;/p&gt;&lt;h2&gt;Some random observations&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;Final success rate is 100%, reproducible;&lt;/li&gt;&lt;li&gt;Most of startup time is spent injecting SSH keys through libguestfs;&lt;/li&gt;&lt;li&gt;To run one hundred VMs per host from the same image, only 24Gb of RAM and 3.4GB in /var/lib/nova is needed. Thanks to &lt;a href="http://www.linux-kvm.org/page/KSM"&gt;KSM&lt;/a&gt; and QCOW2!&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Next steps&lt;/h2&gt;&lt;p&gt;Obviously, we are not settling on two hundred VMs run in parallel. This is still very much a work-in-progress and we’re raising the bar higher every time. Stay tuned for the next report from the trenches.&lt;/p&gt;&lt;h2&gt;P.S.&lt;/h2&gt;&lt;p&gt;By the time this post was written, we were able to go past 400 VMs. The team is working around another race condition as we speak.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-6101106840079275370?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6101106840079275370/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6101106840079275370" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6101106840079275370?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6101106840079275370?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/9nzZMHpS6U8/running-200-vm-instances-on-openstack.html" title="Running 200 VM instances on OpenStack Compute" /><author><name>BK_man</name><uri>http://www.blogger.com/profile/09488438559047077413</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-TLeBzRVFlik/TeAVcH_WAmI/AAAAAAAABOc/8BgAwp8w2KY/s72-c/two_nodes.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/05/running-200-vm-instances-on-openstack.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04FRns8fip7ImA9WhZWFk4.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-5629743022470751090</id><published>2011-05-06T11:10:00.000-07:00</published><updated>2011-05-17T06:45:17.576-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-17T06:45:17.576-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="openstack" /><category scheme="http://www.blogger.com/atom/ns#" term="jclouds" /><category scheme="http://www.blogger.com/atom/ns#" term="~Dmitri Babaev" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud computing" /><title>Grid Dynamics Delivers JClouds support for OpenStack</title><content type="html">&lt;div&gt;&lt;h3&gt;&lt;span&gt;Overview&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;span&gt;Grid Dynamics teamed up with GigaSpaces to deliver JClouds support for the&lt;/span&gt;&lt;a href="http://www.openstack.org/projects/compute/"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OpenStack Compute&lt;/span&gt;&lt;/a&gt;&lt;span&gt; (Nova).  We have created a new JClouds provider called Nova, which is based on the existing Rackspace cloud servers provider created by Adrian Cole, the main author of JClouds library. OpenStack Compute, also known as Nova, is a community effort to create a cloud infrastructure suitable for both public and private clouds.&lt;/span&gt;&lt;a href="http://www.jclouds.org/"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JClouds&lt;/span&gt;&lt;/a&gt;&lt;span&gt; is one of the best open-source libraries to manage public and private clouds. It provides an abstraction on top of REST APIs for the cloud. And while there are many cloud platforms supported by JClouds, up until now there was no support for OpenStack Compute.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;&lt;span&gt;Details&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;span&gt;OpenStack supports two RESTful APIs. The first API is implemented to mimic that of Amazon EC2. The second one is Openstack's native API which is derived from the Rackspace Cloud Servers API.  The native API is developed by the community and will eventually allow access to all available features in the most simple and natural way. In contrast, Amazon-like API is not supported by the community and is, therefore, harder to extend. Taking these facts into account, we decided to use Openstack's native API in our JClouds provider.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;Our provider supports the 1.1 version of the&lt;/span&gt;&lt;a href="http://wiki.openstack.org/OpenStackAPI_1-1"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OpenStack API&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. It supports all core features of the JClouds compute service.  However, OpenStack itself does not support some of the JClouds features on certain hypervisors. You can see a detailed list of supported and unsupported features on&lt;/span&gt;&lt;a href="http://code.google.com/p/jclouds/wiki/QuickStartOpenStack"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;this wiki page&lt;/span&gt;&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;&lt;span&gt;Requirements and Locations&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;span&gt;Our provider requires the Cactus release of OpenStack, which supports the new 1.1 version of the API. We are using RHEL builds for our OpenStack installations. The packages for RHEL are available from our&lt;/span&gt;&lt;a href="http://yum.griddynamics.net/"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;yum repository&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. In addition, our provider should also work with Cactus packages for Ubuntu. You can get the artifact from JClouds Maven&lt;/span&gt;&lt;a href="https://oss.sonatype.org/content/repositories/snapshots/"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;snapshot repo&lt;/span&gt;&lt;/a&gt;&lt;span&gt; or get the JClouds source and build your own copy. The provider code is in snapshot-apis/nova folder.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;&lt;span&gt;Conclusion and call to action&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;&lt;span&gt;We are very excited about what OpenStack has to offer. And now with support from JClouds, it becomes much easier to manage OpenStack from Java applications.  Please, give our JClouds provider a try. And of course, any feedback is always welcome! You can find instructions on how to get started&lt;/span&gt;&lt;a href="http://code.google.com/p/jclouds/wiki/QuickStartOpenStack"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;here&lt;/span&gt;&lt;/a&gt;&lt;span&gt; and&lt;/span&gt;&lt;a href="http://code.google.com/p/jclouds/wiki/ComputeGuide"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;here&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. Feel free to ask any questions about the provider in JClouds&lt;/span&gt;&lt;a href="http://groups.google.com/group/jclouds"&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Google group&lt;/span&gt;&lt;/a&gt;&lt;span&gt; or here in comments.&lt;/span&gt;&lt;br /&gt;&lt;h3&gt;&lt;span&gt;Relevant Links&lt;/span&gt;&lt;/h3&gt;&lt;ul&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://anyweight.blogspot.com/2011/04/openstack-nova-ready-for-testing.html"&gt;Post about Nova provider in JClouds blog&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://natishalom.typepad.com/nati_shaloms_blog/2011/04/gigaspaces-openstack-explained.html"&gt;Nati Shalom's article about Openstack support in Gigaspaces&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://www.jclouds.org/"&gt;JClouds home page&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://code.google.com/p/jclouds/wiki/QuickStartOpenStack"&gt;Nova provider quick start article in JClouds wiki&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://code.google.com/p/jclouds/wiki/ComputeGuide"&gt;JClouds Compute Service guide&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;span&gt;&lt;a href="http://groups.google.com/group/jclouds"&gt;JClouds Google group&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;       &lt;li&gt;&lt;a href="http://www.openstack.org/projects/compute/"&gt;&lt;span&gt;Openstack Compute home page&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;/li&gt;&lt;li&gt;&lt;a href="http://yum.griddynamics.net/"&gt;&lt;span&gt;Openstack packages for RHEL&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;&lt;a href="http://wiki.openstack.org/OpenStackAPI_1-1"&gt;OpenStack API v 1.1 page in Openstack wiki&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-5629743022470751090?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/5629743022470751090/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=5629743022470751090" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5629743022470751090?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/5629743022470751090?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/jQk3Ztu48ck/grid-dynamics-delivers-jclouds-support.html" title="Grid Dynamics Delivers JClouds support for OpenStack" /><author><name>Dmitri Babaev</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-WKjhT7Fzdyc/AAAAAAAAAAI/AAAAAAAAAT0/H_oAH9H6rKY/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/05/grid-dynamics-delivers-jclouds-support.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8FSHgzcSp7ImA9WhZUEE0.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-148668307565995805</id><published>2011-04-27T01:19:00.000-07:00</published><updated>2011-06-02T01:20:19.689-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-02T01:20:19.689-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="indexing" /><category scheme="http://www.blogger.com/atom/ns#" term="lucene" /><category scheme="http://www.blogger.com/atom/ns#" term="search" /><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Indexes: RDBMS vs Coherence vs Lucene</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;
Most people are familiar with concept of “index” in SQL database. But indexes are widely used far beyond relational databases. There are even dedicated products, like search engines, which are specializing in indexing of data stored elsewhere. This article will give a high level comparison of capabilities and performance aspects of typical indexes in three different types of technologies: SQL database, in-memory-data-grid (&lt;a href="http://www.oracle.com/technetwork/middleware/coherence/overview/index.html"&gt;Oracle Coherence&lt;/a&gt;) and full text search engine (&lt;a href="http://lucene.apache.org/"&gt;Apache Lucene&lt;/a&gt;).&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;b&gt;Query use-case – multiple attribute filter&lt;/b&gt;&lt;br /&gt;
While working with large number of objects (e.g. execution messages from stock exchange or product records from e-commerce web site), we often need to select subset of them using values of few attributes. A simple example would be ‘find all red women’s shoes of 9 inch size’. In pseudo SQL this query may look like:&lt;br /&gt;
&lt;span class="Apple-style-span" style="background-color: #eeeeee; color: #0b5394; font-family: 'Courier New', Courier, monospace;"&gt;select * from product where type=’shoes’, color=’red’, size=’9”’, gender=’W’&lt;/span&gt;&lt;br /&gt;
Let’s use this query further to compare different technologies.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Inverted index&lt;/b&gt;&lt;br /&gt;
I believe most of you are familiar with inverted indexes, but I would like to give a short overview anyway.&amp;nbsp;Idea behind inverted index, which is used in all three technologies covered by this article, is very simple. Imagine we have record with fields A, B and C and we want to execute queries like “select * from records where A=x”. Instead of scanning all records in table, we can create additional data structure (index), which will track for each possible value of attribute A list to all records having this value.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-LpUYvUz9dzo/TbUlUSG7VNI/AAAAAAAAI0E/QLy5zUAFAK8/s1600/blog-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="248" src="http://2.bp.blogspot.com/-LpUYvUz9dzo/TbUlUSG7VNI/AAAAAAAAI0E/QLy5zUAFAK8/s320/blog-1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;So if we need all record which have A=1 we will find “1” entry point in index (by attribute A) and get list of all records which conforms that criterion. Sounds simple, but devil is in details. How to store index? &amp;nbsp;How to handle queries which have multiple criteria? Different technologies have different answers and these answers have significant impact on performance of queries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;b&gt;RDBMS – BTree based inverted indexes&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Btree"&gt;BTree&lt;/a&gt; is most common implementation of inverted index in RDBMS (world of RDBMS is diverse, so I’m sure there are alterative implementations but let’s stick with BTrees here). BTree is good for disk based storages and has been used in relational databases for decades. Typical SQL database will allow you to create index using one or more attributes and you can create multiple indexes for same table. If you are creating index for multiple attributes, order of attributes is important.&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Normally &lt;span class="Apple-style-span" style="color: blue; font-style: italic; font-weight: bold;"&gt;RDBMS can use only one BTree index for particular table during execution of query&lt;/span&gt;. That’s an very important point!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;How RDBMS will handle our “shoes query” then? RDBMS have to choose single best index (usually using statistics). Then it will use this index to select super set of query result and filter this super set record by record testing remaining query criteria. E.g. RDBMS may choose that index by color field is best, so it will find all red products using index and then check every such product to throw away everything which is not a women’s shoes of 9 inch size. In other words, RDBMS is still required to do a lot of work even if it is using index.&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Actually our “shoes query” is very bad for RDBMS to handle. Whatever single-attribute index RDBMS may choose (color, type, size or gender) it will likely have to check few thousands of records to finish query. &amp;nbsp;It is still better than full table scan though.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Is it possible to use index more efficiently for multiple attribute criteria queries in RDBMS? – It is.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;We can create compound index, e.g. index by [size, color].Using this index RDBMS will be able to scan only though all red products which have size=9”. This way we have less record to check. We can tune indexes in RDBMS to match our specific queries. But for different query e.g. “find all red women’s shoes of brand X” index [size, color] will be useless.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;b&gt;&lt;br /&gt;
&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;Update:&lt;/span&gt; &lt;/b&gt;&lt;i&gt;Though BTree indexes are most common in RDBMS they are not necessary only choice. Some databases, including Oracle, can use bitmap indexes (the way similar to Lucence, see below). Also Oracle can do BTree index intersection (similar to Coherence, see below) though query analyzer rarely choose this strategy.&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;b&gt;Indexes in Oracle Coherence (in-memory-data-grid)&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;In-memory-data-grids also may use indexes to speed up query execution. Instead of BTree grids usually prefer in-memory data structures (either hashtables or sorted trees). Let’s take Oracle Coherence as example. In Coherence (and in data grids in general) data are distributed across cluster nodes (processes participating in grid), and each object has its owner node. Indexes are also distributed across nodes; each node is responsible for indexing objects which belongs to node.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;When you query Oracle Coherence, query is broadcasted among cluster nodes, each node is executing query over its local data and sends back a result set. Result sets from all nodes are aggregated to produce final result of query.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Each node holds just a portion of overall data and all this data are in memory (not on disk). This makes grids use slightly different approach for using indexes compared to RDBMS. Unlike RBMS, Oracle Coherence can use multiple indexes to execute simple query.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Let’s go back to our “shoes query”. Assuming what we have indexes for every attribute, Coherence will retrieve [set of all shoes], [set of all red products], [set of all products for women] and [set of all products of size 9”] (each from corresponding attribute index). Once it has all four sets, Coherence will calculate an intersection and that will be result of query (all red women’s shoes of size 9”). Important point here is that Coherence doesn’t have to check objects itself as long as it has indexes for every attribute used in query. Sets of objects in Coherence index are implemented as hash sets (using object’s key to reference object). To intersect two hash sets, Coherence has to loop over one set and test every entry against second set. If one of set is small (few dozen of objects) this is very fast, but if both lists have few thousands of objects intersection may take significant time.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;This approach also has its limitations. In our “shoes query” all four product sets produced indexes will be quite long, so set intersection operation will take significant time. Sometime removing index may actually speed up query (e.g. [list of products for women] is probably very long), also order of criteria in query (filter in terms of Coherence) in important because Coherence doesn’t do global query optimization. While this approach is generally better for multiple criteria queries than RDBMS one, “shoes query” is still quite unpleasant use case even for in-memory-data-grid.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;div&gt;&lt;b&gt;Lucene and bit set indexes&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://lucene.apache.org/"&gt;Apache Lucene&lt;/a&gt;&amp;nbsp;is a full text search framework built in Java. Surprisingly full text search and multiple criteria search are very similar and Lucene can handle our “shoes query” out of box.&lt;br /&gt;
Lucene is using compressed bitsets to store inverted index (instead of BTrees or hash tables). Compressed bitsets has two very important features: they are very compact and it’s possible to perform binary operations (e.g. intersection) over compressed bitsets without decompression. Similar to Coherence, Lucene will try to use all four indexes to execute our “shoes query”. But unlike Coherence, using compressed bitsets Lucene can intersect all four product sets mentioned in Coherence examples very fast. Even if individual lists can have thousands of elements, it is a piece of cake for bitsets to handle.&lt;br /&gt;
Using compressed bitsets makes Lucene very powerful tool for multiple criteria queries, in practice Lucene can be orders of magnitude faster for that type of queries compared to RDBMS or Coherence.&lt;/div&gt;&lt;div&gt;But using bitsets comes at price. In particular update of compressed bitsets requires rewrite of whole set.&amp;nbsp;Update cost of bitset based index is quite high. Apache Lucene is doing spectacular work to compensate this fundamental limitation (e.g. &lt;a href="http://lucene.apache.org/java/2_3_2/fileformats.html#Segments%20File"&gt;using segmentation of index&lt;/a&gt; and &lt;a href="http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html"&gt;logarithmic merging&lt;/a&gt; under hood), but still &amp;nbsp;index update cost for Lucene is generally much higher compared to RDBMS or Coherence.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Best of both worlds: Coherence + Lucence&lt;/b&gt;&lt;br /&gt;
If you are working with Orcale Coherence and starting filling envy for power of Lucene’s search capabilities, you may want to try&amp;nbsp;&lt;a href="http://code.google.com/p/gridkit/wiki/GridSearch4Coherence"&gt;grid4search&lt;/a&gt;&amp;nbsp;project which allows using Lucene as replacement for built-in Coherence indexes. See more details in project page.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-148668307565995805?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/148668307565995805/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=148668307565995805" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/148668307565995805?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/148668307565995805?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/ha0CVcZhd6w/indexes-rdbms-vs-coherence-vs-lucene.html" title="Indexes: RDBMS vs Coherence vs Lucene" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-LpUYvUz9dzo/TbUlUSG7VNI/AAAAAAAAI0E/QLy5zUAFAK8/s72-c/blog-1.png" height="72" width="72" /><thr:total>11</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/04/indexes-rdbms-vs-coherence-vs-lucene.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIAQHo_fSp7ImA9WhZWFEU.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-560833131441832220</id><published>2011-04-15T13:47:00.000-07:00</published><updated>2011-05-15T12:09:01.445-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-15T12:09:01.445-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring" /><title>Spring Nested - Part II - What?</title><content type="html">&lt;div&gt;In &lt;a href="http://blog.griddynamics.com/2011/04/spring-nested-part-i-why.html"&gt;the previous post&lt;/a&gt; I described the problem. This post will describe the solution. &lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Solution&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Spring provides &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/context/ApplicationContext.html#getParent()"&gt;parent context&lt;/a&gt; feature. It allows us to build a context hierarchy by declaring the special children context creator bean in the Web application context, and specify the children context config XML paths:&lt;/div&gt;&lt;div&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;lt;&lt;/font&gt;bean id&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;root&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt; class&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;com.griddynamics.springnested.ContextParentBean&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;lt;&lt;/font&gt;property name&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;configLocation&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;br /&gt;value&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;classpath:META-INF/spring/authenticator.context.xml&lt;/font&gt;&lt;font&gt;&lt;b&gt;&lt;i&gt; &lt;/i&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;            classpath:META-INF/spring/datasource.context.xml&lt;/font&gt;&lt;font style="color: rgb(128, 0, 0); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;/&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;/&lt;/font&gt;bean&lt;font style="color: rgb(128, 128, 48); "&gt;&amp;gt;&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;No magic at all - it just creates children contexts in the loop, and sets the root application context as the parent for them. Look, we already solved &lt;a href="http://blog.griddynamics.com/2011/04/spring-nested-part-i-why.html"&gt;all issues&lt;/a&gt;: we have separated and isolated contexts; application can run without any particular context's failure just by ignoring an exception on child context initialization;but it doesn’t allow children contexts to call to each other, nor handle Web requests. Let’s address these too. &lt;/div&gt;&lt;div&gt;That “root” bean (as well as other bean from the root application context) will be accessible from the children contexts. It allows us to implement ServiceLocator based upon the Spring features. Let’s add two methods: one explicitly publishes bean into the root scope, and the second one finds the published reference. Then these methods can be invoked via Spring xml as a factory methods inside of the children contexts:&lt;/div&gt;&lt;div&gt;&lt;font class="Apple-style-span" style="color: rgb(105, 105, 105); font-family: monospace; font-size: 14px; white-space: pre; "&gt;// the "root" bean implements &lt;/font&gt;&lt;/div&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(128, 0, 0); font-weight: bold; "&gt;interface&lt;/font&gt; BeanRegistry&lt;font style="color: rgb(128, 0, 128); "&gt;{&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;Void&lt;/font&gt; export&lt;font style="color: rgb(128, 128, 48); "&gt;(&lt;/font&gt;ExportRef ref&lt;font style="color: rgb(128, 128, 48); "&gt;,&lt;/font&gt; &lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;Class &lt;/font&gt;interface&lt;font style="color: rgb(128, 128, 48); "&gt;)&lt;/font&gt;&lt;font style="color: rgb(128, 0, 128); "&gt;;&lt;/font&gt;&lt;/pre&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="font-weight: bold; "&gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(128, 0, 0); font-weight: bold; "&gt;class&lt;/font&gt; ExportRef&lt;font style="color: rgb(128, 0, 128); "&gt;{&lt;/font&gt;&lt;br /&gt;ApplicationContext childCtx&lt;font style="color: rgb(128, 0, 128); "&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;String&lt;/font&gt; beanName&lt;font style="color: rgb(128, 0, 128); "&gt;;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(128, 0, 128); "&gt;}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;Object&lt;/font&gt; lookup&lt;font style="color: rgb(128, 128, 48); "&gt;(&lt;/font&gt;&lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;String&lt;/font&gt; name&lt;font style="color: rgb(128, 128, 48); "&gt;,&lt;/font&gt; &lt;font style="color: rgb(187, 121, 119); font-weight: bold; "&gt;Class &lt;/font&gt;interface&lt;font style="color: rgb(128, 128, 48); "&gt;)&lt;/font&gt; &lt;font style="color: rgb(128, 0, 128); "&gt;;&lt;/font&gt;&lt;/pre&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(128, 0, 128); "&gt;}&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;The most interesting points of implementation are:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;to publish reference (export) you need to store bean name, class and provided application context;&lt;/li&gt;&lt;li&gt;context can export the bean before the actual bean initialized (you can tune it by depends-on= attributes);&lt;/li&gt;&lt;li&gt;ExportRef obtains the holding application context &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/context/ApplicationContextAware.html#setApplicationContext(org.springframework.context.ApplicationContext)"&gt;quite easy&lt;/a&gt;. Honestly speaking it's the only reason for its' existence; &lt;/li&gt;&lt;li&gt;lookup() returns &lt;b&gt;proxies &lt;/b&gt;&lt;i&gt;always&lt;/i&gt; (which is quite easy to implement with the &lt;a href="http://static.springsource.org/spring/docs/1.2.x/api/org/springframework/aop/framework/ProxyFactoryBean.html"&gt;Spring support&lt;/a&gt;);&lt;/li&gt;&lt;li&gt;we've chosen validate references by the classes provided into the both calls (the interfaces are supported only);&lt;/li&gt;&lt;li&gt;references are names only, which meets the Spring familiar developer expectations;&lt;/li&gt;&lt;li&gt;exports and lookups don't introduce any eager initialization, everything is lazy as possible.  &lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;The most advantage is the short learning curve for Spring aware developers. When the team crafts the service we just let the client team know the interface class and reference name. They are able to copy-paste several xml lines of the lookup() factory-method bean (see &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-class"&gt;3.2.3.2.3&lt;/a&gt;) - voilà it’s just a Sping singleton for the regular injection:&lt;/div&gt;&lt;div&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(105, 105, 105); "&gt;&amp;lt;!--&lt;/font&gt;&lt;font style="color: rgb(105, 105, 105); "&gt; child context, root bean is visible from the parent context &lt;/font&gt;&lt;font style="color: rgb(105, 105, 105); "&gt;--&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color: rgb(95, 80, 53); "&gt;bean&lt;/font&gt; &lt;font style="color: rgb(39, 71, 150); "&gt;id&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;theService&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font style="color: rgb(39, 71, 150); "&gt;factory-bean&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;root&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;/pre&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;&lt;/font&gt;&lt;font&gt;&lt;font class="Apple-style-span"&gt;&lt;font class="Apple-style-span" style="font-size: 16px; "&gt; &lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font class="Apple-style-span" style="color: rgb(39, 71, 150); "&gt; &lt;/font&gt;&lt;font&gt;&lt;font class="Apple-style-span"&gt;factory-method&lt;/font&gt;&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;lookup&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;gt;&lt;/font&gt;&lt;/pre&gt;&lt;pre style="background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: rgb(255, 255, 255); background-position: initial initial; background-repeat: initial initial; "&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color: rgb(95, 80, 53); "&gt;constructor-arg&lt;/font&gt; &lt;font style="color: rgb(39, 71, 150); "&gt;value&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"sampleService&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color: rgb(95, 80, 53); "&gt;constructor-arg&lt;/font&gt; &lt;font style="color: rgb(39, 71, 150); "&gt;value&lt;/font&gt;&lt;font style="color: rgb(128, 128, 48); "&gt;=&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;com.griddynamics.springnested.SampleService&lt;/font&gt;&lt;font style="color: rgb(0, 0, 230); "&gt;"&lt;/font&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;lt;/&lt;/font&gt;&lt;font style="color: rgb(95, 80, 53); "&gt;bean&lt;/font&gt;&lt;font style="color: rgb(166, 87, 0); "&gt;&amp;gt;&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;I’d like to spot that this is close to the plain Spring. In contrast to this, OSGi references identified by the interfaces mostly, instead of names, and the only additional &lt;a href="http://www.osgi.org/javadoc/r4v42/org/osgi/framework/BundleContext.html#getServiceReferences(java.lang.String, java.lang.String)"&gt;‘filter’&lt;/a&gt; feature allows to treat OSGi services as a named beans. The interesting thing is &lt;a href="http://static.springsource.org/osgi/docs/1.1.x/reference/html/service-registry.html#service-registry:refs:singular:bean-name"&gt;how SpringSource adopts&lt;/a&gt;  this OSGi “feature” to be more intuitive for Spring users.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;The context configs structure&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The good practice we've found is keeping the service config and the integration config separated: the first one should be imported into the latter one (by the intrinsic Spring &lt;import&gt;&lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-xml-import"&gt; ability&lt;/a&gt;). &lt;/import&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;service-core.xml - contains the service singleton bean definition (container independent):&lt;/div&gt;&lt;div&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;bean&lt;/font&gt; &lt;font style="color:#274796; "&gt;name&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;theService&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;class&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;com.your.ServiceImpl&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;property&lt;/font&gt; &lt;font style="color:#274796; "&gt;name&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;dao&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;ref&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;theDAO&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;/&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;bean&lt;/font&gt;&lt;font style="color:#a65700; "&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#696969; "&gt;&amp;lt;!--&lt;/font&gt;&lt;font style="color:#696969; "&gt; there is no "theDAO" bean declared here &lt;/font&gt;&lt;font style="color:#696969; "&gt;--&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;service-nested-refences.xml - integrates the service into the application wired by Spring Nested:&lt;/div&gt;&lt;div&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;import&lt;/font&gt; &lt;font style="color:#274796; "&gt;resource&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;service-core.xml&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#696969; "&gt;&amp;lt;!--&lt;/font&gt;&lt;font style="color:#696969; "&gt; spring nested magic goes here &lt;/font&gt;&lt;font style="color:#696969; "&gt;--&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;bean&lt;/font&gt; &lt;font style="color:#274796; "&gt;name&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;theDAO&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;factory-bean&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;root&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;factory-method&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;lookup&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#696969; "&gt;&amp;lt;!--&lt;/font&gt;&lt;font style="color:#696969; "&gt; the reference name and an interface are specified here &lt;/font&gt;&lt;font style="color:#696969; "&gt;--&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;/&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;bean&lt;/font&gt;&lt;font style="color:#a65700; "&gt;&amp;gt;&lt;/font&gt;&lt;/pre&gt; &lt;/div&gt;&lt;div&gt;service-test-references.xml - provides DAO stub for testing:&lt;/div&gt;&lt;div&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;import&lt;/font&gt; &lt;font style="color:#274796; "&gt;resource&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;service-core.xml&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;bean&lt;/font&gt; &lt;font style="color:#274796; "&gt;name&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;theDAO&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;class&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;com.your.StubDAO&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can see the separation of concepts in action - no vendor lock-in! Your components can be integrated into any container, even in unit test by providing a stub.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;XML authoring (or sugar)&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Initially we deal with the several line xml declarations for the service import and exports (factory-method bean). Then, we introduced fancy xml syntax by &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/extensible-xml.html"&gt;XML authoring&lt;/a&gt; facility it took about 200 LOC. Now the declarations look like:&lt;/div&gt;&lt;div&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#666616; "&gt;nested&lt;/font&gt;&lt;font style="color:#800080; "&gt;:&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;export&lt;/font&gt; &lt;font style="color:#274796; "&gt;ref&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;sampleService&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;interface&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;com.griddynamics.springnested.SampleService&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="color:#a65700; "&gt;&amp;lt;&lt;/font&gt;&lt;font style="color:#666616; "&gt;nested&lt;/font&gt;&lt;font style="color:#800080; "&gt;:&lt;/font&gt;&lt;font style="color:#5f5035; "&gt;import&lt;/font&gt; &lt;font style="color:#274796; "&gt;id&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;sampleService&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt; &lt;font style="color:#274796; "&gt;interface&lt;/font&gt;&lt;font style="color:#808030; "&gt;=&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;com.griddynamics.springnested.SampleService&lt;/font&gt;&lt;font style="color:#0000e6; "&gt;"&lt;/font&gt;&lt;font style="color:#a65700; "&gt;/&amp;gt;&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Quite close to Spring DM's XML. Isn't it? Right! It's worth to mention that there are no changes in the flow: these declarations produce the same factory-method beans which has been shown above.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Competitors&lt;/b&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;OSGi and EJB were criticized &lt;a href="http://blog.griddynamics.com/2011/04/spring-nested-part-i-why.html"&gt;before&lt;/a&gt;. Surprisingly the &lt;a href="http://www.osgi.org/blog/2011/04/osgi-lite.html"&gt;single classloader OSGi&lt;/a&gt; has been spotted by &lt;a href="http://blog.griddynamics.com/search/label/~Kirill%20Uvaev"&gt;Kirill&lt;/a&gt;. But it still pushes to additional build steps, and has OSGi API learning curve.&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Coda&lt;/b&gt;&lt;/div&gt;&lt;div&gt;That’s all for now, forthcoming post will tell you how the Web-requests successfully reache children contexts' beans; and how the tiny container becomes smart enough to handle complex children config dependencies and prevent its' cycles.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-560833131441832220?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/560833131441832220/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=560833131441832220" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/560833131441832220?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/560833131441832220?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/akhP_quqiic/spring-nested-part-ii-what.html" title="Spring Nested - Part II - What?" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/04/spring-nested-part-ii-what.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEESXg8fip7ImA9WhZRGUk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8893649116768948548</id><published>2011-04-14T04:05:00.000-07:00</published><updated>2011-04-16T01:46:48.676-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-16T01:46:48.676-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="data grid" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Data Grid Pattern - Snowflake data schema</title><content type="html">&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;b&gt;Evil of distributed joins&lt;/b&gt;&lt;br /&gt;
Traditionally data grids based solutions are using denormalized data models. Denormalized model allows reducing number of data lookups in storage and achieve low response time. Traditional normalized data models are no good for distributed key/value storages. Main argument against them is requirement to do multiple joins during typical data access operation. If your data are partitioned, joins are becoming prohibitively expensive. You have to join each partition from left join side with each partition on right side thus cost of join grows in quadratic proportion of your number of partitions.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-2VKrvxHg1Y4/TaMLsHd1wdI/AAAAAAAAIy4/1Epu8YKtgPw/s1600/blog-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="249" src="http://2.bp.blogspot.com/-2VKrvxHg1Y4/TaMLsHd1wdI/AAAAAAAAIy4/1Epu8YKtgPw/s320/blog-1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Even if you can narrow record set before actual join, your data is still may be located on different servers. Each join between partitioned tables will force your data to be moved across network, adding network latency to response time. More joins – more latency accumulated and you will find you out of your allowed response time very soon.&lt;br /&gt;
I other words, generally, in grid, you cannot use neither joins, nor normalized data model (though there may always be an exception).&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;Denormalization is evil&lt;/b&gt;&lt;/div&gt;&lt;div&gt;But data denormalization approach is far from perfect. It has its downsides and serious ones. Data redundancy is a side effect of denormalization. Redundancy increase memory consumption and cost of updates. Loosing consistency due to redundancy is another foe. It is a constant battle.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;Data warehousing experience&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Data warehousing industry has similar challenges to solve. They have huge amounts of data and also have to deal with distributed data storages. And they have an answer to this challenge for some time!&lt;/div&gt;&lt;div&gt;Analytic databases are usually using "snowflake" data model. Snowflake schema has single fact table (in center of schema) and several dimension tables. Size of fact table is huge, sizes of dimension tables are relatively small.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-uO_qyZODZu8/TaMMc9iK52I/AAAAAAAAIzA/9q4YdHs81Vs/s1600/blog-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="163" src="http://2.bp.blogspot.com/-uO_qyZODZu8/TaMMc9iK52I/AAAAAAAAIzA/9q4YdHs81Vs/s320/blog-2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Snowflake data model allows implementing joins across distributed data storage in smart way. While we still want to have &lt;i&gt;fact&lt;/i&gt; data to be partitioned across cluster, we can have a full copy of &lt;i&gt;dimension&lt;/i&gt; tables on each node executing queries. In other words we may use replication strategy for small &lt;i&gt;dimension&lt;/i&gt; tables while keeping large &lt;i&gt;fact&lt;/i&gt; data partitioned.&lt;/div&gt;&lt;div&gt;Now we can partially execute query using &lt;i&gt;dimensions&lt;/i&gt; which are available localy and then issue single query to distributed &lt;i&gt;fact&lt;/i&gt; table. As long as you do not need to join &lt;i&gt;facts&lt;/i&gt; table with itself of another &lt;i&gt;facts&lt;/i&gt; table query execution requires just one network round trip (and if you really need joins between facts wait for next article “Map/Reduce in data grid”).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;How can we you utilize snowflake schema with grid middleware?&lt;/b&gt;&lt;/div&gt;&lt;div&gt;First we have to decide how we are going to store &lt;i&gt;dimension&amp;nbsp;&lt;/i&gt;tables in memory. We can use in-memory data grid itself or we can use some in-memory database like Hypersonic or H2 database. Grid will support replication of &lt;i&gt;dimension &lt;/i&gt;data out of box and natural support for java object, but in-memory relational DB will offer better support for queries (many grids do not support joins even in replicated storage).&lt;/div&gt;&lt;div&gt;Next question is cluster topology, we may replicate &lt;i&gt;dimension&lt;/i&gt; data over all nodes or just few of them (query nodes). These query nodes can be either grid peer or remote grid client.&lt;/div&gt;&lt;div&gt;Functional separation between query nodes and data nodes (ones storing partitions of facts table) is probably most practical because they have different memory/CPU utilization. By separating them you can tune JVM memory options and scale each tier independently.&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-YXwW9-DGgqQ/TaMMxjE0uGI/AAAAAAAAIzE/WnV3StixRbI/s1600/blog-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="271" src="http://3.bp.blogspot.com/-YXwW9-DGgqQ/TaMMxjE0uGI/AAAAAAAAIzE/WnV3StixRbI/s320/blog-3.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Unfortunately this is just a pattern but not a feature of any data grid product I'm aware of. You still have to complete a lot of non trivial engineering to make it work, but this work worth an effort. This pattern allows to use IMDG in cases there denormalization is unable to solve problem. This approach is opening totally new horizons for using of in-memory-data-grid technology.&lt;/div&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;b&gt;UPDATE:&lt;/b&gt; Illustrations of snowflake schema&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;From financial industry&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-As4icMCfHV0/TalXSOrWo-I/AAAAAAAAIzc/Y9M4m20LPZY/s1600/blog-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="163" src="http://1.bp.blogspot.com/-As4icMCfHV0/TalXSOrWo-I/AAAAAAAAIzc/Y9M4m20LPZY/s320/blog-4.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;and from retail&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-E0VZyRQetDE/TalXZeApzTI/AAAAAAAAIzg/41TkJCqoHJA/s1600/blog-5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="118" src="http://3.bp.blogspot.com/-E0VZyRQetDE/TalXZeApzTI/AAAAAAAAIzg/41TkJCqoHJA/s320/blog-5.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8893649116768948548?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8893649116768948548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8893649116768948548" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8893649116768948548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8893649116768948548?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/07CCm4N2VhU/data-grid-pattern-snowflake-data-scheme.html" title="Data Grid Pattern - Snowflake data schema" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-2VKrvxHg1Y4/TaMLsHd1wdI/AAAAAAAAIy4/1Epu8YKtgPw/s72-c/blog-1.png" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/04/data-grid-pattern-snowflake-data-scheme.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8MRH87eCp7ImA9WhZXFU4.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7541462334462214242</id><published>2011-04-12T12:42:00.000-07:00</published><updated>2011-05-04T12:54:45.100-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-04T12:54:45.100-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring" /><title>Spring Nested - Part I - Why?</title><content type="html">&lt;b&gt;Yet Another one (Spring based) Service Locator Framework&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;It's a well known fact that an every Java developer builds his own framework monthly. We've done it too. Let’s have a look, at least it’s useful as a Spring internals guide.&lt;div&gt;&lt;br /&gt;&lt;b&gt;Context&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We deliver highload backend platform for one of the leadering US eCommerse sites. Technically the platform consists of a number of components, deployed to a cluster as a single Web Application (aka WAR-file) builds with &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html"&gt;Spring Web MVC&lt;/a&gt;. Components inside of the platform expose services for the frontend application(s) via remote interfaces (we are lucky to use Hessian for it). So, we have a trivial form of SOA implementation, when the platform's services access each other via Java in-process calls. The components are crafted by the isolated Teams and we are keen on reducing communication efforts between them. We need to avoid conflicts and/or blocking between teams, and try to achieve it via separation and formal collaboration procedure.&lt;div&gt;&lt;br /&gt;&lt;b&gt;Why not OSGi, EJB, etc…?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I know you loudly repeat this question ten times while reading the intro above. Particularly these two technologies were rejected due to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;multiple classloaders machinery, which we weren’t ready to take (i.e. we are happy with the single class loader);&lt;/li&gt;&lt;li&gt;maintenance efforts - we need to maintain descriptors and run additional build steps; &lt;/li&gt;&lt;li&gt;overwhelming and learning curve.&lt;/li&gt;&lt;/ul&gt;In addition to this we don’t need the partial hot redeploy. Just google “&lt;a href="http://www.google.com/search?q=OSGi+pain"&gt;OSGI pain&lt;/a&gt;“ and you'll find the most of our arguments. It looks like just we are not mature enough to carry on these expenses, and did micro OSGi ourseves.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Ok. Let’s come back to our attempt to utilize the vanilla &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html"&gt;Spring MVC&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Tiny Problems Appear&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We realized that out-of the box Spring Web MVC doesn’t fit for our needs. Let’s look to a sample component - it’s delivered as two jar files: &lt;i&gt;sample-service-api-1.0.jar&lt;/i&gt; and &lt;i&gt;sample-service-impl-1.0.jar&lt;/i&gt;. Both of these JARs contains the necessary class files, and the implementation JAR also contain Spring Web Application Context config XML. To allow services to access each other inside of the WAR we have to &lt;a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/FrameworkServlet.html#setContextConfigLocation(java.lang.String)"&gt;load all services’ config XMLs&lt;/a&gt; into the single Web Application Context instance (there is a possible alteration, but it doesn’t help us). It’s quite similar to using an intrinsic &lt;import&gt; Spring &lt;a href="http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-xml-import"&gt;ability&lt;/a&gt;:&lt;br /&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;beans&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;import&lt;/span&gt; resource&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;services.xml&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;import&lt;/span&gt; resource&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;messageSource.xml&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000; font-weight:bold; "&gt;import&lt;/span&gt; resource&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;themeSource.xml&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;bean id&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;bean1&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt; class&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;...&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;bean id&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;bean2&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt; class&lt;span style="color:#808030; "&gt;=&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#0000e6; "&gt;...&lt;/span&gt;&lt;span style="color:#800000; "&gt;"&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="color:#000000;background:#ffffff;"&gt;&lt;span style="color:#808030; "&gt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#808030; "&gt;/&lt;/span&gt;beans&lt;span style="color:#808030; "&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;In this case we have a single flat Spring beans namespace among all services i.e. ServiceA singleton is able to inject ServiceB singleton by a regular Spring injection. It’s something similar to the technique described &lt;a href="http://blog.sarathonline.com/2008/10/classpath-making-your-modular-spring.html"&gt;here&lt;/a&gt;. But as soon as we take this approach we find that the platform scarifies from the lack of the application contexts encapsulation.  The actual problems are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;internal beans are also exposed into the common beans namespace - so, we have to maintain distinguished bean names to avoid the situation when introducing an internal  "dateHelper" bean in your component’s context harms the other vendor’s component which is unlucky to use the same name;&lt;/li&gt;&lt;li&gt;some context-wide policies like aspects, autowiring, lazy-loading, bean postprocessors  etc introduced by one component impacts another i.e. we need to keep it separated;&lt;/li&gt;&lt;li&gt;sometimes we need partially working platform WAR i.e. when one of the context are failed to initialize, independent peers can work fine e.g. we have some security related service, which is not able to run without some crypt keys, even fake. In this case all developers have to be aware of this detail: obtain, and install the necessary files (the similar problem has place with the team specific resources like DB or backends, which isn't available for another locations). It can be definitely avoided by an alternate WAR configuration e.g. reduced WAR which has the problematic component excluded, but it doesn’t work in a real life due to organizational and technical issues.&lt;/li&gt;&lt;/ul&gt;We realized that all these things above impact our productivity. Then we decided to slightly modify the &lt;a href="http://blog.springsource.com/2007/06/11/using-a-shared-parent-application-context-in-a-multi-war-spring-application/"&gt;approach&lt;/a&gt; presents in Spring, and implement ServiceLocator upon Spring contexts hierarchy. See Part II&lt;/import&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7541462334462214242?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7541462334462214242/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7541462334462214242" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7541462334462214242?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7541462334462214242?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/4F0G7MSswCM/spring-nested-part-i-why.html" title="Spring Nested - Part I - Why?" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/04/spring-nested-part-i-why.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIBRHc4fyp7ImA9WhZXE0s.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-6912173975938033741</id><published>2011-04-12T08:51:00.000-07:00</published><updated>2011-05-02T13:19:15.937-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-02T13:19:15.937-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="Hessian" /><category scheme="http://www.blogger.com/atom/ns#" term="Remoting" /><category scheme="http://www.blogger.com/atom/ns#" term="HTTP" /><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="Networks" /><title>Fast Hessian methods leads to java.net.NoRouteToHostException: Cannot assign requested address</title><content type="html">Last week the old issue with the performance testing environment appears again - something happens with the network under high load, and the &lt;a href="http://hessian.caucho.com/"&gt;Hessian&lt;/a&gt; invocations start failing with java.net.NoRouteToHostException: Cannot assign requested address&lt;br /&gt;&lt;br /&gt;The first clue was googled &lt;a href="http://stackoverflow.com/questions/1572215/how-to-avoid-a-noroutetohostexception"&gt;easily&lt;/a&gt;. I checked it by netstat - yes, we have a huge amount of TIME_WAIT sockets, that exceeds the number of available ephemeral ports. How to solve it?  Initially I tried to hack Hessian with SocketFactory sets SO_REUSEADDR option for the underlying socket, then consider to provide an alternative http client which is able to cache connections. Who ever know how complex it seems?&lt;br /&gt;&lt;br /&gt;The actual resolution is  quite simple: Java has everything what ever you need &lt;a href="http://download.oracle.com/javase/1.4.2/docs/guide/net/properties.html"&gt;-Dhttp.maxConnections=100&lt;/a&gt; allows us to put much pressure to the fast Hessian service methods. Java runtime already has HTTP1.1 client supports &lt;a href="http://en.wikipedia.org/wiki/HTTP_persistent_connection"&gt;keep-alive&lt;/a&gt;, which utilized by Hessian underneath. So, we just need to allocate enough pool to prevent sockets closing and the following TIME_WAIT pollution.&lt;br /&gt;&lt;br /&gt;P.S. if you still unaware about &lt;a href="http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp"&gt;Hessian benefits&lt;/a&gt;, it's really worth to look at it, or ask me at the comments below.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-6912173975938033741?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/6912173975938033741/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=6912173975938033741" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6912173975938033741?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/6912173975938033741?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/XD0jkpJ0QFc/fast-hessian-methods-leads-to.html" title="Fast Hessian methods leads to java.net.NoRouteToHostException: Cannot assign requested address" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/04/fast-hessian-methods-leads-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UEQHo8fyp7ImA9Wx9aGEQ.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-2378850691616712240</id><published>2011-03-10T21:10:00.000-08:00</published><updated>2011-03-11T16:53:21.477-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-11T16:53:21.477-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="openstack" /><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="~Stan Klimoff" /><category scheme="http://www.blogger.com/atom/ns#" term="rackspace" /><title>Grid Dynamics and OpenStack</title><content type="html">&lt;div&gt;This week Rackspace &lt;a href="http://www.rackspace.com/blog/?p=2062"&gt;announced&lt;/a&gt; the creation of the new &lt;a href="http://www.rackspace.com/cloudbuilders/"&gt;Cloud Builders business unit&lt;/a&gt;, with the goal to provide commercial services around designing, building and supporting OpenStack installations, as well as provide training and certification services. We think that this is an excellent investment on behalf of Rackspace that could very well take the project to another level.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is even more exciting that Grid Dynamics is a part of this team, together with other Rackspace partners — Citrix, Dell, Opscode, Equinix and Cloudscaling.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With so many players that had announced their support for OpenStack, I am often asked what Grid Dynamics intends to do in this area. Well, we are obviously continuing doing what we did so far — providing state-of-the-art engineering services for the enterprises. In this perspective, OpenStack becomes the foundation for our solutions in the private cloud space.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why choose OpenStack? There are several reasons. We've been watching OpenStack development even before the Austin release came out, and here are the highlights:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Development model. True open-source (contrast with "open core" model of other vendors), very fast turnaround on incorporating patches. The progress of the last eight months is amazing.&lt;/li&gt;&lt;li&gt;Community. On the Bexar design summit, there were over two hundred people from about fifty different companies all around the globe. It seemed impressive at that time. Well, look at the size of the community today! If it's not exponential growth, then I do not know what exponential growth is.&lt;/li&gt;&lt;li&gt;Talent. OpenStack really gathered a star team — brilliant engineers from Anso Labs, Citrix, Canonical... Just hanging around with those guys is an experience in its own.&lt;/li&gt;&lt;li&gt;No license fees. This is the thing that is really important for service providers — confidence that the platform can scale with their business, not only from the technical standpoint, but from economical standpoint.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;With so many companies around, I am often asked — what exactly are we going to do with OpenStack? Well, from the business development standpoint, we will offer a range of solutions for the enterprises. One of them, OpenStack Jumpstart, is already announced — you can read more about it on our site. But since you are reading this blog, you are probably more interested in the technical aspect.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Let's see:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Support for enterprise hardware and operating systems. We are already actively maintaining &lt;a href="http://wiki.openstack.org/NovaInstall/RHEL6Notes"&gt;RHEL 6 port&lt;/a&gt;, which will be the basis for the ports to other versions. Also, our main lab is based on Cisco UCS — and we intend to continue working in this area to leverage unique features of UCS.&lt;/li&gt;&lt;li&gt;Advanced scheduling and placement. Enterprises and service providers often want to take the datacenter and network topology in account when placing virtualized resources — for the purposes of HA, DR, and providing different tiers of service. We started working in this direction by introducing &lt;a href="https://blueprints.launchpad.net/nova/+spec/instance-avail-zones"&gt;availability zones&lt;/a&gt; in Bexar, but a more sophisticated and complete solution is underway.&lt;/li&gt;&lt;li&gt;Network-as-a-service (NaaS). Network is a historically overlooked piece of infrastructure among cloud vendors, and sadly, this is the case with OpenStack today. What we are pushing for is treating network as a first-class citizen, allowing to provision software switches, load balancers, firewalls, tunnels and other gear. We are fixing top-priority holes by implementing features such as &lt;a href="https://blueprints.launchpad.net/nova/+spec/multinic-libvirt"&gt;multi-nic support&lt;/a&gt; (which will hopefully make its way in Cactus), but a complete overhaul is needed to support enterprise requirements to the network layer.&lt;/li&gt;&lt;li&gt;Integration and extendability. For OpenStack to be successful in the enterprise scenario, it has to play nice with its IT and business systems — orchestration, service catalogs, portals, billing, service desk etc. Of course, there's no single recipe to integrate with all the possible flavors of business systems. What can be done, however, is allowing OpenStack to be extended with vendor-specific modules. We are working in this direction; one tiny step is introducing pluggable schedulers in Bexar.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;We are confident in OpenStack future. With such an impressive start, brilliant team of developers and stellar portfolio of companies backing it, it's hard not to succeed. It's very exciting to be the part of the Next Big Thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;P.S. The engineering team keeps a separate blog on purely technical matters that is not syndicated here — http://openstackgd.wordpress.com/. If you are interested in our weekly progress, this is the place to go.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-2378850691616712240?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/2378850691616712240/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=2378850691616712240" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2378850691616712240?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/2378850691616712240?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/ZHYLGr6fgiY/grid-dynamics-and-openstack.html" title="Grid Dynamics and OpenStack" /><author><name>Stan Klimoff</name><uri>http://www.blogger.com/profile/14586894425559474017</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2011/03/grid-dynamics-and-openstack.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQFSX85eSp7ImA9Wx9RE0g.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8238287275508311076</id><published>2010-12-14T11:18:00.000-08:00</published><updated>2010-12-14T11:18:38.121-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-14T11:18:38.121-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="hpc" /><category scheme="http://www.blogger.com/atom/ns#" term="RabbitMQ" /><category scheme="http://www.blogger.com/atom/ns#" term="~Eugene Kirpichev" /><category scheme="http://www.blogger.com/atom/ns#" term="scalability" /><title>Lessons learnt on a 2000-core cluster</title><content type="html">A while ago we had the chance to test our product (embarassingly&lt;br /&gt;
parallel cluster computations in semiconductor industry) on a&lt;br /&gt;
2000-core cluster.&lt;br /&gt;
This, despite the rather simple-sounding problem statement, turned out&lt;br /&gt;
to pose a number of challenges and interesting insights into the&lt;br /&gt;
issues of, ehm, decently scaling at such scale.&lt;br /&gt;
&lt;br /&gt;
Below you can find a (rather lengthy) presentation from an internal&lt;br /&gt;
tech-talk held on the topic, summarizing these challenges and the&lt;br /&gt;
lessons or "morales" we learnt from coping with them.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="width:425px" id="__ss_6155957"&gt;&lt;object id="__sse6155957" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2000core-lessonslearnt-101214030228-phpapp02&amp;stripped_title=lessons-learnt-on-a-2000core-cluster&amp;userName=jkff" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse6155957" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2000core-lessonslearnt-101214030228-phpapp02&amp;stripped_title=lessons-learnt-on-a-2000core-cluster&amp;userName=jkff" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8238287275508311076?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8238287275508311076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8238287275508311076" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8238287275508311076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8238287275508311076?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/1-QBxzoLazQ/lessons-learnt-on-2000-core-cluster.html" title="Lessons learnt on a 2000-core cluster" /><author><name>jkff</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="27" height="32" src="http://4.bp.blogspot.com/_zdzLDOzl46w/TQfGQljIUKI/AAAAAAAAANA/UDMmdmP6j7Y/S220/a_4a99a9a6.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/12/lessons-learnt-on-2000-core-cluster.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08BSXc8eip7ImA9Wx5aEkk.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8627744409702036337</id><published>2010-11-08T10:44:00.000-08:00</published><updated>2010-11-08T10:44:18.972-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-08T10:44:18.972-08:00</app:edited><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>Data Grid Pattern - Network shared memory</title><content type="html">Using shared memory for inter-process communications is a very popular pattern in UNIX world. Many popular RDBMS (both open source and commercial) are implemented as sets of OS processes communicating via shared memory. Designing a system as a set of functionally specialized processes cooperating with each other helps to keep system more transparent and maintainable; yet, using shared memory as IPC provider keeps communication overhead very low. Shared memory is very efficient compared to other forms of IPC. Several processes can exchange or share information with each other via shared memory without involvement of OS (e.i. no syscalls, no context switching overheads). &lt;br /&gt;
&lt;br /&gt;
Unfortunately, shared memory is useful only if all communicating processes are hosted on same server (e.i. connected to same memory circuits). While we cannot use real shared memory when building a distributed system, idea of building system as a set of cooperating specialized processes still remains attractive. &lt;br /&gt;
&lt;br /&gt;
Key point of shared memory idea is that all processes can access and modify the same data; all processes have consistent view and can do atomic operations on data (e.g. compare-and-set). Data grid technologies allow us to achieve same shared memory features, but in network environment. &lt;br /&gt;
&lt;br /&gt;
Modern data grid products (e.g. Oracle Coherence, GemStone GemFire, etc) provide key features for shared-memory-like communication:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;shared data with strong consistency guaranties across processes in a cluster;&lt;/li&gt;
&lt;li&gt;atomic operations over single key in a shared storage.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Still, one can not drive this analogy too far. Data grids are very different from "networked shared memory". They have specific tradeoffs and it is impossible to just take an application (like PostgreSQL) and make it clustered using Oracle Coherence. But we can reuse and extend this architectural approach and develop a “network shared memory” pattern as a way to build distributed system.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;“Network shared memory” pattern&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
First, you need to separate data and processes in your mind. Next you should identify operations with data which are happening in your system. You may have operations such as serving request using data, updating, importing data, exporting data, transforming data, etc. Ideally, you should have a separate process dedicated for each operation (though it is not always possible in all cases due to various reasons, so be just reasonable). Once you finished with analyzing your data and designing processes, you can start to work on physical model and design a way the data grid will store your data. Remember, data model for grid should be always modeled with access pattern in mind. Blindly copying data model from RDBMS may produce disastrous results (data modeling for grid is another large topic).&lt;br /&gt;
&lt;br /&gt;
Why using multiple processes is better compared e.g. with multiple threads within a single process? Here are few reasons:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;You can distributed your processes between servers (e.g. for optimizing resource utilization)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;You can start/stop processes independently&lt;/li&gt;
&lt;li&gt;You can upgrade processes independently&lt;/li&gt;
&lt;li&gt;You have better failure isolation (e.g. memory leak in one process will not bring down whole system)&lt;/li&gt;
&lt;li&gt;You can use less heap per JVM, and have individual memory options for different processes&lt;/li&gt;
&lt;/ul&gt;Obviously, there are some drawbacks as well. A few of them:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;You will have more JVMs running and thus more overhead of JVM itself. &lt;/li&gt;
&lt;li&gt;All processes have to communicate over network and it is not as fast as using shared memory between threads.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;If your data is not partitionable, this approach may not work at all&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;b&gt;Advanced usages of “Network shared memory”&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Data grids have high availability built in. We can leverage this feature to achieve high availability for our processes. First pattern is a “hot standby”. We may have several instances of same process running (e.g. on different boxes) but only one of them active at a time. In a case of active process going down, grid middleware will detect process failure and one of the standby process will take over. Sounds simple, however even this simple approach requires “death detection”, “peer discovery” and “distributed consensus” features. &lt;br /&gt;
Believe me, all of these is not an easy task to implement. Fortunately, data grid already have all of this implemented, you just need to use its API. Data grid also can be used to reliably store internal state of process, thus you can implement failover even for stateful processes.&lt;br /&gt;
&lt;br /&gt;
A next evolutionary step of this approach is a load balancing between processes. Data grid can help coordinating processes by sharing routing table for request, state for stateful operations and/or using distributed locks for controlling access to resources.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Data grid is more than just distributed data store&lt;/b&gt;&lt;br /&gt;
While data grid technology is primarily designed for working with larger data sets, advanced features of modern data grid products may bring benefits to your system even if all your data fit a memory of single server. Their high availability and distributed coordination features may be invaluable for designing modular distributed saluting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8627744409702036337?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8627744409702036337/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8627744409702036337" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8627744409702036337?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8627744409702036337?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/4bI9s9Q0ldM/data-grid-pattern-network-shared-memory.html" title="Data Grid Pattern - Network shared memory" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><thr:total>5</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/11/data-grid-pattern-network-shared-memory.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQBQnY9eSp7ImA9Wx5UEkw.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-3657247143689548543</id><published>2010-10-13T17:35:00.000-07:00</published><updated>2010-10-16T01:22:33.861-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-16T01:22:33.861-07:00</app:edited><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>Data Grid pattern - Data flow mediator</title><content type="html">I'd like to start a series of articles about data grid oriented architectural patterns. First pattern I want to present is a “Data flow mediator”. Let me start with example.&lt;br /&gt;
Imagine you have a large ecommerce web application and want to do some real time analysis over user actions. You have a stream of simple events, (e.g clicks). You need to do real time aggregation by various dimensions: by user, by product, etc. At large scale this task is quite challenging: number of writes is enormous, different dimensions make sharding challenging and business want this analytics to happen as close to real time as possible (say few seconds delay). With or without data grid this task will remain challenging, but data grid technology have a strong advantages for this problem.&lt;br /&gt;
Let me now introduce “data flow mediator” pattern.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_CQV12Vs8lZ0/TLWujDVpcBI/AAAAAAAAItw/3CcV1h_Jdt4/s1600/mediator.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="150" src="http://1.bp.blogspot.com/_CQV12Vs8lZ0/TLWujDVpcBI/AAAAAAAAItw/3CcV1h_Jdt4/s320/mediator.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
In this pattern, data grid is used as a buffer between systems which produces events (clicks), and systems which consumes information (real time analysis modules). &lt;br /&gt;
&lt;br /&gt;
From producer point of view:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Data grid provides high and scalable throughput,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Data grid provides reasonable balance between durability/performance/cost. With data grid, we can store data in memory only, protected by multiple redundant copies. &lt;/li&gt;
&lt;/ul&gt;From consumers’ (RT analysis modules) point of view:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Advanced data grids (e.g. Coherence, GemFire, etc) provide required queering/aggregation tool (implementing efficient queries by multiple dimensions in grid still an art, but it is doable),&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;High and scalable read throughput. Different analysis modules may share same “mediator”&lt;/li&gt;
&lt;/ul&gt;From architect's point of view:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Mediator decouples data producer from data consumers, thus localizing impact of changes for each component,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Data grid is self managing. Imagine managing DB with 50 shards + HA replication + dynamic adding/removing servers to cluster and you will treasure this feature of data grid.&lt;/li&gt;
&lt;/ul&gt;I have demonstrated this pattern with ecommerce examples, but there are similar use cases in finance or telecom. Key prerequisites for this pattern are:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Large number of small updates,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Data loss is not fatal (either we can tolerate it or restore data from elsewhere),&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Large number of read queries,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Queries are reasonable simple but more complicated than just primary key gets,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Low response time required for both read and write,&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Scale is above scalability limits of single RDBMS&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
I hope this article will help you better understand data grid technology and its usage.&lt;br /&gt;
Next time I will present “distributed shared memory” pattern. &lt;br /&gt;
&lt;br /&gt;
Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-3657247143689548543?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/3657247143689548543/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=3657247143689548543" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/3657247143689548543?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/3657247143689548543?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/gadiEdWtcyQ/grid-pattern-data-flow-mediator.html" title="Data Grid pattern - Data flow mediator" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_CQV12Vs8lZ0/TLWujDVpcBI/AAAAAAAAItw/3CcV1h_Jdt4/s72-c/mediator.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/10/grid-pattern-data-flow-mediator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMHQnY8eyp7ImA9Wx5VGUs.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7980173187916533987</id><published>2010-10-11T00:41:00.000-07:00</published><updated>2010-10-13T03:40:33.873-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-13T03:40:33.873-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Coherence, magic trick with cache index</title><content type="html">Oracle Coherence has ability to query data in cache not only by key, but by values (or their attributes). Of course queering by secondary attributes is not as efficient as by primary key, but still can be very useful. Oracle Coherence also supports indexes which improve performance of value based queries significantly. &lt;br /&gt;
But some times index may not behave exactly as you expect. Here is an example:&lt;br /&gt;
&lt;script src="http://gist.github.com/620141.js?file=gistfile1.java"&gt;
&lt;/script&gt;&lt;br /&gt;
Program output:&lt;br /&gt;
&lt;script src="http://gist.github.com/620183.js?file=gistfile1.txt"&gt;
&lt;/script&gt;&lt;br /&gt;
So far there are no surprises. &lt;br /&gt;
&lt;br /&gt;
Now let’ s create an index and repeat exactly same query over exactly same data:&lt;br /&gt;
&lt;script src="http://gist.github.com/620186.js?file=gistfile1.java"&gt;
&lt;/script&gt;&lt;br /&gt;
Program output:&lt;br /&gt;
&lt;script src="http://gist.github.com/620187.js?file=gistfile1.txt"&gt;
&lt;/script&gt;&lt;br /&gt;
Magic :)&lt;br /&gt;
&lt;br /&gt;
Now let me demystify this situation.&lt;br /&gt;
Coherence use inverted index to speed up filter queries. Inverse index is a map which maps value of indexed attribute to a set of keys. E.g. for query like “give me keys of all entries, where attribute A = ‘B’ ” we can extract result directly from inverse index. Coherence will just retrieve key set associated with “B” from inverse index of attribute A (of cause index should be create explicitly). This is simple case. But what if attribute itself a collection (Coherence is storing objects, their attributes can be anything). Imagine you are storing articles and each article has a list of tags. Now you have a query like “give me all article tagged with ‘java’”. This is quite common case. Without index such query will be executed as full scan which may be terrible inefficient. To allow filters such as &lt;a href="http:///"&gt;ContainsAny&lt;/a&gt;/&lt;a href="http://download.oracle.com/docs/cd/E15357_01/coh.360/e15725/com/tangosol/util/filter/ContainsAllFilter.html"&gt;ContainsAll&lt;/a&gt; also benefit from index in case when attribute is a collection, Coherence will add all element of collection to inverse index also. Rule is simple: if attribute value is a collection or array its element will be added to index, otherwise attribute value itself will be indexed.&lt;br /&gt;
In example above Coherence inverse index will look like:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;“true” -&amp;gt; 1, 3&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;“false” -&amp;gt; 2, 3&lt;/li&gt;
&lt;/ul&gt;When equalsFilter is executed using index it doesn’t check real value (it save a lot on deserialization costs). This explain how we’ve got object which is “true” and “false” at same time (there were no real call to &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#equals%28java.lang.Object%29"&gt;Object.equals(...)&lt;/a&gt; if index is used).&lt;br /&gt;
In practice, you are not supposed to mix scalar and collection value in same index, so it shouldn’t be a problem. But be aware, using &lt;a href="http://download.oracle.com/docs/cd/E15357_01/coh.360/e15725/com/tangosol/util/filter/EqualsFilter.html"&gt;EqualsFilter&lt;/a&gt; is not necessary involving &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#equals%28java.lang.Object%29"&gt;Object.equals(...)&lt;/a&gt; invocation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7980173187916533987?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7980173187916533987/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7980173187916533987" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7980173187916533987?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7980173187916533987?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/dhLjk0dnObY/coherence-magic-trick-with-cache-index.html" title="Coherence, magic trick with cache index" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/10/coherence-magic-trick-with-cache-index.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUEFQX06cCp7ImA9WhZXE0s.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-7944382912698488040</id><published>2010-08-19T22:42:00.000-07:00</published><updated>2011-05-02T13:20:10.318-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-02T13:20:10.318-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Mikhail Khludnev" /><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><title>Coherence Production Checklist describes TTL expiry attack</title><content type="html">Recently I've found a curious contradiction between advice given by software experts and a real hardware. Let's have a look to &lt;a href="http://wiki.tangosol.com/display/COH33UG/Production+Checklist#ProductionChecklist-Network" target="_blank"&gt;Coherence Production Checklist&lt;/a&gt;  and &lt;a href="http://wiki.tangosol.com/display/COH35UG/multicast-listener#multicast-listener-ttl" target="_blank"&gt;TTL tuning for production&lt;/a&gt;. Does it make sense? At the first glance, yes it does - you secure production cluster from multicast  IP clashes by setting ttl to 1 or even 0.&lt;br /&gt;But there is some objections here. Have a look to &lt;a href="http://www.cisco.com/en/US/products/hw/switches/ps708/products_tech_note09186a00804916e0.shtml" target="_blank"&gt;Catalyst 6500/6000 Switch High CPU Utilization&lt;/a&gt; and &lt;a href="http://www.cisco.com/web/about/security/intelligence/ttl-expiry.html" target="_blank"&gt;TTL Expiry&lt;/a&gt;  . In two words setting ttl&lt;=1 lead to high load of switch/router  device, because router prefers to use hardware matrix to route packets. Instead of this, expired packets should be processed by CPU to issue  ICMP Type 11, Code 0 - "Time Exceeded", even such replies is disabled.  As result router goes crazy, and you have a really odd network behavior.&lt;br /&gt;That's what you should do instead: implement multicast assignment policy  in your datacenter; disable or properly control multicast routing -  just kill mcast packets at the network segments boundaries by the routing table;  and of course do not follow software experts advice when you deal with  the real hardware.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-7944382912698488040?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/7944382912698488040/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=7944382912698488040" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7944382912698488040?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/7944382912698488040?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/vtmI9KsE_ks/recently-ive-found-curious.html" title="Coherence Production Checklist describes TTL expiry attack" /><author><name>Mikhail Khludnev</name><uri>http://www.blogger.com/profile/03731629466352186647</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="30" src="http://1.bp.blogspot.com/-uhyb8mXvv-0/TaS4mQ59aoI/AAAAAAAAACI/dM0YMxJEwro/s220/khl.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/08/recently-ive-found-curious.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08FRHw_fCp7ImA9WxFaE0w.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-136054015836359025</id><published>2010-07-16T14:30:00.000-07:00</published><updated>2010-07-16T14:30:15.244-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-16T14:30:15.244-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="~Alexey Ragozin" /><title>Coherence, ReflectionPofSerializer now supports POF extractor</title><content type="html">&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;font class="Apple-style-span" face="Verdana, sans-serif" size="3"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;/span&gt;&lt;/font&gt;&lt;/p&gt;&lt;font class="Apple-style-span" face="Verdana, sans-serif" size="3"&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;A year ago I have implemented and open sourced &lt;font class="Apple-style-span" face="'courier new'"&gt;&lt;a href="http://code.google.com/p/gridkit/wiki/ReflectionPofSerializer"&gt;ReflectionPofSerializer&lt;/a&gt;&lt;/font&gt;. This class has saved me from implementing thousands of lines of boring serialization code for various &lt;font class="Apple-style-span" face="'courier new'"&gt;Filters&lt;/font&gt;, &lt;font class="Apple-style-span" face="'courier new'"&gt;EntryProcessors&lt;/font&gt;, &lt;font class="Apple-style-span" face="'courier new'"&gt;Aggregators &lt;/font&gt;, &lt;font class="Apple-style-span" face="'courier new'"&gt;Invocables &lt;/font&gt;and other mobile objects in Coherence.&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;Recently I was asked about &lt;a href="http://coherence.oracle.com/display/COH35UG/PofExtractors+and+PofUpdaters"&gt;POF extrator&lt;/a&gt;  support in  &lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofSerializer&lt;/font&gt;. My answer was no, it doesn't support extraction from POF directly. But it turns out what &lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofSerializer &lt;/font&gt;can be easily extended to support it. A bit of coding and woala, let me introduce &lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofExtrator&lt;/font&gt;.&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofExtractor&lt;/font&gt; is an &lt;a href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/util/ValueExtractor.html"&gt;extractor&lt;/a&gt; implementation which can be used in Coherence for filtering and indexing. It’s usage is very similar to standard &lt;font class="Apple-style-span" face="'courier new'"&gt;&lt;a href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/util/extractor/ReflectionExtractor.html"&gt;ReflectionExtractor&lt;/a&gt; &lt;/font&gt;(except it accessing attributes by field names not by calling methods). It can extract a field of stored object directly from POF binary, also it can parse simple paths to extracted attributes (e.g. path "instrument.exchange" will make extractor first extract filed "instrument" then extract field "exchange" from instrument and return it). If &lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofSerializer &lt;/font&gt;have been used to serialize object, &lt;font class="Apple-style-span" face="'courier new'"&gt;ReflectionPofExtractor &lt;/font&gt;can read value directly from binary POF format (what is it, without deserialization cost). If another type of serializer was used, object will be deserialized and field will be extracted via reflection.&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;It did some micro benchmarking, results are below:&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;For cache filled with 500k objects, a full scan filter is executed, below is filter execution time for different size of objects:&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;b&gt;Binary object size: 180 bytes&lt;/b&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ReflectionExtractor execution time: 20s&lt;/li&gt;
&lt;li&gt;ReflectionPofExtractor execution time: 14s&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;b&gt;Binary object size: 604 bytes&lt;/b&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ReflectionExtractor execution time: 23s&lt;/li&gt;
&lt;li&gt;ReflectionPofExtractor execution time:  24s&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;b&gt;Binary object size: 1804 bytes&lt;/b&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;ReflectionExtractor execution time: 150s&lt;/li&gt;
&lt;li&gt;ReflectionPofExtractor execution time: 117s&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;This result proves 2 things:&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Never relay on micro benchmark – do proper performance testing of your application.&lt;/li&gt;
&lt;li&gt;PofExtractor is not always a performance win, use advice above.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;p style="margin-top:1.35pt;margin-right:0in;margin-bottom:7.05pt;margin-left: 0in;mso-line-height-alt:7.05pt"&gt;But anyway now you can estimate effect of using PofExtractors before writing boiler plate of custom PofSerializer/PofNavigator.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/font&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-136054015836359025?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/136054015836359025/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=136054015836359025" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/136054015836359025?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/136054015836359025?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/tSDSan_ZJKY/coherence-reflectionpofserializer-now.html" title="Coherence, ReflectionPofSerializer now supports POF extractor" /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/07/coherence-reflectionpofserializer-now.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUESXs-fyp7ImA9WxFbE04.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-8918104414674159291</id><published>2010-07-02T13:13:00.000-07:00</published><updated>2010-07-05T05:50:08.557-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-05T05:50:08.557-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="~Arseny Kaplun" /><category scheme="http://www.blogger.com/atom/ns#" term="Hadoop" /><title>War story: optimizing one Hadoop job</title><content type="html">&lt;p&gt;Recently, we faced a problem of categorization of shopping items : applying a complex set of regular expressions to product description, figure out category of product and extract category-dependent fields. Since original data is a result of web crawling, majority of records do not change since previous crawl while 1% of records do actually change. This led to idea of incremental processing when we initially select altered records and then process only those that had changed.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Algorithm&lt;/h2&gt;&lt;br /&gt;Original algorithm was to run a set of map-reduce jobs:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;“&lt;b&gt;&lt;i&gt;Diff&lt;/i&gt;&lt;/b&gt;”. Compare older data and new data to fetch updated records. Create a 'diff' that contains input for updated / new records and list of deleted keys.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;“&lt;b&gt;&lt;i&gt;Extract&lt;/i&gt;&lt;/b&gt;”. Convert diff to hadoop MapFile format, along with fetching fields (desired processing) for updated &amp;amp; new records. Deleted records are mapped to deletion marker.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;“&lt;b&gt;&lt;i&gt;New&lt;/i&gt;&lt;/b&gt;”. Rip out new records to a separate output which along with output of step 4 forms final result.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;“&lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt;”. Go through previous processing results, using diff as a dictionary, replacing updated records and removing deleted ones.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;img style="margin: 0pt 0px 10px -40pt;" src="http://1.bp.blogspot.com/_umG7njH7Wmg/TC3fQVNgyeI/AAAAAAAAAZ4/QyigtuqZvh4/s1600/optimize-hadoop-for-blog.gif" alt="" id="BLOGGER_PHOTO_ID_5489288992499223010" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Optimization&lt;/h2&gt;&lt;br /&gt;Initial implementation performed really bad, it worked even longer than just processing of all fields on a single machine. So, we started optimization which included following steps:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;1. Use custom WritableComparable.&lt;/h2&gt;Initially, we used CSV text file as intermediate format. Now, we decided to implement custom Writable class (fig. 1) for values and WritableComparable (fig. 2) class for keys of intermediate data.&lt;br /&gt;&lt;p&gt;&lt;script src="http://gist.github.com/464315.js?file=gistfile1.java"&gt;&lt;/script&gt;&lt;span style="font-style: italic;"&gt;figure 1: RecordKeyWritable.java&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;script src="http://gist.github.com/464316.js?file=gistfile1.java"&gt;&lt;/script&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;figure 2: RecordWritable.java&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;Surprisingly, this optimization produced a little impact, about a 1% of total runtime, mostly by eliminating time for string splitting.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2. Adding combiner&lt;/h2&gt;Next, we decided to implement efficient combiner that will combine all records of the same product for both &lt;b&gt;&lt;i&gt;Diff&lt;/i&gt;&lt;/b&gt; and &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt; stages. See figure 3 for example of combiner for Diff stage.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/464319.js?file=gistfile1.java"&gt;&lt;/script&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;figure 3: RecordCombiner.java&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;After enabling combiner for &lt;b&gt;&lt;i&gt;Diff&lt;/i&gt;&lt;/b&gt; we won 15% of time, and Merge time decreased by 20%.  Data transfer volume decreased significantly (up to 2x).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3. Upgrade Hadoop 0.18.3 to 0.20.2. &lt;/h2&gt;We did not expected that, but just this cut total processing time by 30%, mainly because shuffle performance increased dramatically. At the time of our tests, Hadoop 0.20 could not be deployed on Amazon EC2 very easy, so we made a couple of fixes in scripts. Anyway this should be fixed in Hadoop repository by now.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;4. Enable GZIP compression for input, output and intermediate data.&lt;/h2&gt;We've tried to compress input data, providing input format compression, output compression and intermediate (sequence file) format compression. However, we could not notice impact of any of these optimizations&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Output:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;SequenceFileOutputFormat.setCompressOutput(conf, true);&lt;br /&gt;SequenceFileOutputFormat.setOutputCompressorClass(conf, GzipCodec.class);&lt;/code&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;or&lt;br /&gt;&lt;code&gt;&lt;br /&gt;FileOutputFormat.setOutputCompressorClass(conf, GzipCodec.class);&lt;br /&gt;FileOutputFormat.setCompressOutput(conf, true);&lt;/code&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;figure 4: Snippets enabling GZIP compression for M/R output&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Gzipped input is understood by fileInputFormat &amp;amp; SequenceFileInputFormat transparently&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;5. Enable LZO compression for intermediate data.&lt;/h2&gt;LZO compression achieves medium compression rate at a pretty good speed of compression and outstanding speed of decompresion. This makes LZO codec ideal for compression of intermediate data (Mapper's output) so it allows to highly reduce traffic between mappers and reducers at a low computational price. Additionally,  it supports independent block decompression. We tried LZOcodec from hadoop-0.18 pack and it allowed us to save 5% of total processing time. Unfortunately, LZO support was removed from hadoop-0.20 due to license restriction. There're several alternative projects in progress, but at the time of our tests there was no out-of-the-box solution.&lt;br /&gt;&lt;p&gt;&lt;code&gt;&lt;br /&gt;conf.setCompressMapOutput(true);&lt;br /&gt;conf.setMapOutputCompressorClass(LzoCodec.class);&lt;/code&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;figure 5: snippets enabling LZO compression for traffic between mappers &amp;amp; reducers&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;6. Tune number of mappers and reducers&lt;/h2&gt;After a set of experiments we found out that manual setting number of mappers and reducers can speed up M/R substantially. First, check that map tasks are small enough so all nodes are equally loaded and they are not too small to suffer from initialization overhead (map task execution time lower than 20 seconds is known to be bad).&lt;br /&gt;&lt;p&gt;Further optimization is achieved by tuning ratio of  number of mappers to number of reducers. Just by setting appropriate values via &lt;span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:'Courier New';font-size:100%;"  &gt;conf.setNumMapTasks()&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;/span&gt;and &lt;span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:'Courier New';font-size:100%;"  &gt;conf.setNumReduceTasks()&lt;/span&gt; we were able to cut total processing time by 30%! Unfortunately, optimal parameter values strongly depends on data size and distribution. It appears that taking &lt;span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;font-family:'Courier New';font-size:100%;"  &gt;3 * input size / block_size &lt;/span&gt; mappers and 1 reducer per slave node is a good point to start optimizing.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;7. Map side join&lt;/h2&gt;We have also tried map-side join for &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt;. In order to do this we have to get data for “&lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt;” step sorted and partitioned the same way. This allows us to perform &lt;i&gt;merge join&lt;/i&gt; – our mapper reads two input simultaneously matching records of the same key. This also required extra-map reduce to merge old results (as we did not merged results of update&amp;amp;delete with new before). Also we could not avoid sort &amp;amp; shuffle since we needed IdentityReducer to keep processing results in single file. So finally we could not achieve significant performance increase (5% of &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt; time savings) at a price of much higher complexity.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;8. Put diff map to local disk instead of HDFS&lt;/h2&gt;The next step was to put diff-file to each merging node in local file system, instead of sharing it by hdfs. This saved us 10% more of merge time. Anyway map-file lookup was still too slow taking 95% of merging time so we looked for keeping it as in-memory distributed hash map (DHT).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;9. Replace MapFile with in-memory cache&lt;/h2&gt;Instead of hadoop map file (which is intended to keep index in memory) we switched to use of in-memory hash map keeping both index and values in memory. Result was outstanding: &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt; step became 70% faster and &lt;b&gt;&lt;i&gt;New&lt;/i&gt;&lt;/b&gt; step got 60% faster. Since our diff was small enough to fit in memory of slave node, we used our own simple HT:&lt;br /&gt;&lt;ul style="list-style-type: none;"&gt;&lt;li&gt;-    it serves as a http-service&lt;/li&gt;&lt;li&gt;-    on start it reads the diff file and populates hash table with it&lt;/li&gt;&lt;li&gt;-    the service is terminted when Merge join is over&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If diff size gets bigger so it could not fit in memory of a single slave node, we will have to look up for more complicated solution. Probably one of available in-memory hash table implementation would fit, so this needs further investigation..&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;If you would face a problem of optimizing of map-reduce task here is our suggestions:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Start with tuning map-reduce tasks number.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Try latest hadoop version&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Avoid map-file as a dictionary data : try to put it in memory, reconsider algorithm, look for third-party solution.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add combiners and switch to custom record format.&lt;/li&gt;&lt;li&gt;Try replace reduce-side join with map-side one&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;h2&gt;P.S.&lt;/h2&gt;This table uncovers some details of optimizations tried and level of effort for each of those:&lt;br /&gt;&lt;br /&gt;&lt;table style="border-collapse: collapse;" border="0" cellpadding="0" cellspacing="0"&gt;&lt;thead&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; background: rgb(230, 255, 0) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"&gt;&lt;br /&gt;&lt;b&gt;Improvement&lt;/b&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; background: rgb(230, 255, 0) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"&gt;&lt;br /&gt;&lt;b&gt;Effect&lt;/b&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; background: rgb(230, 255, 0) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous;"&gt;&lt;br /&gt;&lt;b&gt;Effort&lt;/b&gt;&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Custom record format&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Total time reduced by 1%&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;2 hours of coding.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Adding combiners&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;This, along with &lt;i&gt;Custom record&lt;br /&gt;formal&gt;&lt;/i&gt;, reduced total time by 17%. &lt;b&gt;&lt;i&gt;Diff&lt;/i&gt;&lt;/b&gt; time reduced by 15% and &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt; time reduced by 20%.&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;2 hours of coding.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Update hadoop&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Total time reduced by 30% by similar speed up of all steps&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Had to fix deployment scripts for&lt;br /&gt;EC2, this should be already fixed in codebase.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;GZip&lt;/i&gt;&lt;i&gt; compression of input/output&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;No visible effect&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Two lines in JobDriver&lt;br /&gt;code.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;LZO compression of intermediate data&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Total processing time reduces by 5%&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Two lines of code in JobDriver in Hadoop 0.18.&lt;br /&gt;Significant effort (2-3 days) of adding LZO-like compression to Hadoop 0.20 (until the compression in incorporated in Hadoop distribution)&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Map-reduce task tuning&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Total processing reduced by 30%&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;A week of experiments. Note that this&lt;br /&gt;should be revisited when data size or distribution changes (and we know it&lt;br /&gt;always grows).&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Map side join&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Negative: total processing time increased.&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;A week of coding &amp;amp; experiments.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Put dictionary data in local file system&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;10% saved on &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt;,&lt;br /&gt;total time reduces by 7%&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;Couple of lines in running scripts.&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;&lt;i&gt;Put dictionary data in memory&lt;/i&gt;&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;70% &lt;b&gt;&lt;i&gt;Merge&lt;/i&gt;&lt;/b&gt; speed up, 60%&lt;br /&gt;&lt;b&gt;&lt;i&gt;New&lt;/i&gt;&lt;/b&gt; speed up, total time reduced by 50%.&lt;br /&gt;&lt;/td&gt; &lt;td style="border: 1px solid rgb(0, 0, 0); padding: 5px; vertical-align: top;"&gt;&lt;br /&gt;2 days of coding for simple in-memory hash-table. In case when dictionary data does not fit in memory, reconsideration is&lt;br /&gt;required. Custom in-memory DHT may take a bliss of time, commercial promises&lt;br /&gt;to be pricey, open solutions should be investigated..&lt;br /&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-8918104414674159291?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/8918104414674159291/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=8918104414674159291" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8918104414674159291?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/8918104414674159291?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/KmOKNqKTnIk/war-story-optimizing-one-hadoop-job.html" title="War story: optimizing one Hadoop job" /><author><name>kapliars</name><uri>http://www.blogger.com/profile/01715198722262085613</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/_IDeqzt1J338/TDIr013R33I/AAAAAAAACmA/h6zca2CDNNY/S220/redshirt.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_umG7njH7Wmg/TC3fQVNgyeI/AAAAAAAAAZ4/QyigtuqZvh4/s72-c/optimize-hadoop-for-blog.gif" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/07/war-story-optimizing-one-hadoop-job.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08NQn4_fCp7ImA9WxFUGUQ.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-4376520545616867944</id><published>2010-06-30T13:57:00.000-07:00</published><updated>2010-07-01T07:51:33.044-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-01T07:51:33.044-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="coherence" /><category scheme="http://www.blogger.com/atom/ns#" term="~Alexey Ragozin" /><title>Coherence. Read through and operation bundling.</title><content type="html">If you are using &lt;a href="http://wiki.tangosol.com/display/COH35UG/read-write-backing-map-scheme"&gt;read-write-backing-map&lt;/a&gt;, you should know what &lt;a href="http://download.oracle.com/otn_hosted_doc/coherence/350/com/tangosol/net/cache/CacheLoader.html"&gt;CacheLoader&lt;/a&gt; interface has  methods load(...) and loadAll(…) for bulk loading. And if your cache loader is loading data from DB, your implementation of loadAll(…) is probably designed to load all objects via single DB query (cause it is usually order of magnitude more efficient than issue DB query per requested key). Lets assume your &lt;i&gt;read through&lt;/i&gt; cache is working just fine, and at some point you decided to implement cache preloading – a popular pattern. To implement preloading you have found some way to collect keys (e.g. via query to DB) and wanted to use getAll(…) call to load data into cache.  Everything looks ok, unit tests have passed, but on real data it takes forever to preload cache! Let’s investigate this …&lt;br /&gt;
&lt;br /&gt;
Problem quickly reveals itself, Coherence is not calling loadAll(…), and instead it calls load(…) for each key in single thread. Culprit here is partitioned (distributed) cache. Your call to loadAll(…) produces single GetAllRequest (one request per storage member owning part of key set to be precise). While processing this request partitioned service is looping over keys from request at call get(…) for each key from backing map. Partitioned service never calls getAll(…) from backing map and it gives no chance for read-write-backing-map implementation to call loadAll(…). Bummer.&lt;br /&gt;
&lt;br /&gt;
My favorite solution for this issue is to load objects from DB directly and then put them to cache (looks a bit ugly, but as you will see below it is the most clean workaround). Sometimes, it may not be an option. Do we have other alternatives?&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://wiki.tangosol.com/display/COH35UG/cachestore-scheme"&gt;cachestore-scheme&lt;/a&gt; element has a configuration option named &lt;a href="http://wiki.tangosol.com/display/COH35UG/operation-bundling"&gt;operation-bundling&lt;/a&gt;. Let’s try to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://gist.github.com/459212.js?file=1.xml"&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
No effect. What is a problem?&lt;br /&gt;
&lt;br /&gt;
Let me explain how operation bundling works. Operation bundler intercepts method calls ( load(…) for this case) and delay them a little (1ms in config above). After delay it check if there are pending requests in other threads, and if they are, it gathers all requests for all threads and executes them in single loadAll(…), then dispatch results back to callers in other threads (and finally returns its own result of cause). This means max number of request in bundle is limited by number of threads which are accessing read-write-backing-map. By default we have just one thread per partitioned service, that's why nothing interesting happens.&lt;br /&gt;
&lt;br /&gt;
Let’s add thread pool config to distributed scheme.&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://gist.github.com/459212.js?file=2.xml"&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Test it. Nothing has changed. What next?&lt;br /&gt;
&lt;br /&gt;
Yes we have thread pool now, but partitioned service have received just one GetAllRequest and each request is processed by single thread, so we still have one thread that sequentially calls to get(…) method. Blast!&lt;br /&gt;
&lt;br /&gt;
Go back to our getAll(…) call site, create thread pool, separate keys between threads, call multiple getAll(…) in parallel.&lt;br /&gt;
&lt;br /&gt;
&lt;script src="http://gist.github.com/459212.js?file=3.java"&gt;&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
Finally, loadAll(…) is being called now, but number of keys in single call to getAll(…) is still limited to size of partitioned service thread pool, and we also have to have same number of parallel getAll(…) requests.&lt;br /&gt;
&lt;br /&gt;
So, for me this solution is a way more hacky than just load object for DB without Coherence help. I have notified Coherence team on this problem, hope they will fix it in some future release.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-4376520545616867944?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/4376520545616867944/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=4376520545616867944" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/4376520545616867944?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/4376520545616867944?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/k0AJ1M2Zp2s/coherence-read-through-and-operation.html" title="Coherence. Read through and operation bundling." /><author><name>Alexey Ragozin</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="29" height="32" src="http://2.bp.blogspot.com/_CQV12Vs8lZ0/SuV09NgeGmI/AAAAAAAAIpg/SaVy7eLs13I/S220/Alexey.Ragozin.4036.crop.png" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/06/coherence-read-through-and-operation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8ERXY7cSp7ImA9WxFUE00.&quot;"><id>tag:blogger.com,1999:blog-3946011063058389308.post-1267669363329471790</id><published>2010-06-22T10:56:00.000-07:00</published><updated>2010-06-23T07:20:04.809-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-23T07:20:04.809-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="deployment" /><category scheme="http://www.blogger.com/atom/ns#" term="cloud" /><category scheme="http://www.blogger.com/atom/ns#" term="~Dmitry Korotkov" /><category scheme="http://www.blogger.com/atom/ns#" term="Hyper-V" /><title>Deploying to Hyper-V: Windows over Windows</title><content type="html">Recently I was able to spend some time to getting acquainted with Microsoft Powershell and Microsoft Hyper-V. The task was to imitate elastic cloud service on existing hardware running Windows Server 2008 R2 with Hyper-V. Main goal was to learn how to create and shutdown running windows-based virtual machines on-demand.&lt;br /&gt;
&lt;br /&gt;
Hyper-V provides WMI management interface which is available for use in Powershell, thanks to &lt;a href="http://pshyperv.codeplex.com/"&gt;PowerShell Management Library for Hyper-V&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
While solving my task I faced several issues I would like to share&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Backup &amp; Restore&lt;/h2&gt;&lt;br /&gt;
Unfortunatelly, current version of NTFS does not support neither data de-duplication nor copy-on-write. Each of these technologies could dramatically speed-up creation of running instance from snapshot. For now, making a copy of virtual machine snapshot (including disk image snapshot) takes about 95% of instance creation time.&lt;br /&gt;
&lt;br /&gt;
Hence, when you need fast instance creation, it might worth to use some NAS that supports de-duplication.&lt;br /&gt;
&lt;br /&gt;
The other option is to use Hyper-V Differential Disk feature, but it requires to mangle or recreate virtual machine config file to avoid original disk image corruption. The other caveat is that if original image becomes corrupted, all differential disks become corrupted too.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Avoiding duplicate VM names&lt;/h2&gt;&lt;br /&gt;
An obvious way to maintain reusable VM image is to prepare virtual machine with all needed software pre-installed, and then shutdown and 'export' it. When importing VM, Hyper-V uses disk image in-place, and rewrites config files making image unusable. Hence, for getting working copy of VM, we need to make a copy of exported image in some other place and then 'import' it.&lt;br /&gt;
&lt;br /&gt;
But when we restore two such virtual machines, we get two identical instances with the same names. We need to give these instances different names to distinguish them. The easiest way is to generate GUID and use it as a VM name.&lt;br /&gt;
&lt;br /&gt;
The VM name is specified in two places in the exported virtual machine XML configuration file. It would be very easy to use XPath to specify nodes for update, but unfortunately, Hyper-V config file parser is very formatting-sensitive. Hyper-V does not accept MSXML-parsed and saved VM config file, because it is saved slightly re-formatted. Hence, we have to replace original VM name with replacement pattern and consider xml file as plaintext.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;Update:&lt;/i&gt;&lt;/b&gt; It is possible to use XML object OuterXml() method to get config file Hyper-V understands. Hence, config file update script might look like:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
$hostname = [System.Guid]::NewGuid().ToString()&lt;br /&gt;
$cfgfile = Resolve-Path("$VMsPath\$hostname\Virtual Machines\*.exp")&lt;br /&gt;
$xml = [xml](Get-Content $cfgfile)&lt;br /&gt;
$xml.SelectSingleNode('DECLARATIONS/DECLGROUP/VALUE.OBJECT/INSTANCE[@CLASSNAME="Msvm_VirtualSystemGlobalSettingData"]/PROPERTY[@NAME="ElementName"]/VALUE').'#text' = $hostname&lt;br /&gt;
$xml.SelectSingleNode('DECLARATIONS/DECLGROUP/VALUE.OBJECT/INSTANCE[@CLASSNAME="Msvm_VirtualSystemSettingData"]/PROPERTY[@NAME="ElementName"]/VALUE').'#text' = $hostname&lt;br /&gt;
$xml.OuterXml | Set-Content $cfgfile&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Avoiding duplicate hostnames and SIDs&lt;/h2&gt;&lt;br /&gt;
After automatic virtual machine creation was implemented, the next issue was machine names and IP addresses. Obviously, when a complete copy of the VM is created, the copy will have the same hostname as original machine and some IP address obtained via DHCP.&lt;br /&gt;
&lt;br /&gt;
Avoiding machine SID and hostname duplication is pretty simple. Microsoft provides freeware system preparation tool in Windows Resource Kit (sysprep.exe). It has different configuration file formats for different windows versions, but setupctl.exe tool from Windows Resource Kit generates valid config files for any windows version.&lt;br /&gt;
&lt;br /&gt;
Sysprep.exe moves Windows back to sealed state (the state in which pre-installed windows exists on new computers), removes itself from disk and shuts down the Windows.&lt;br /&gt;
&lt;br /&gt;
In sealed state all host-specific information is misssing: hostname, SID, Windows Product Key, activation date and so on. On first boot Windows starts post-install process, queries user for hostname, product key, generates system SID and makes several other steps. Setupctl.exe allows to create unattended post-install file. One of important unattended setup features is optional random hostname generation.&lt;br /&gt;
&lt;br /&gt;
Hence, duplicated SIDs and hostnames can be avoided using sysprep and setupctl at the last step of preparing reusable VM image.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Acquiring IP addresses of the VM&lt;/h2&gt;&lt;br /&gt;
IP address of running virtual machine is available in VM key-value pairs. Hyper-V acquires it through Integration Services. Note, that on some early versions of Hyper-V it is impossible to acquire IP address of the running virtual machine. Hence, if you installed Integration Services on VM, type in powershell:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;Get-VMKVP "vm-name"&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
if you don't see IP address among other values, you should upgrade Hyper-V.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;br /&gt;
Microsoft Hyper-V with some workarounds may be used as local cloud-like infrastructure. Combining such infrastructure with public cloud services like Amazon EC2 and GoGrid may provide almost unlimited infrastructure on demand with reduced cost as a result of local infrastructure usage when demand is moderate.&lt;br /&gt;
&lt;br /&gt;
Have a nice day!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3946011063058389308-1267669363329471790?l=blog.griddynamics.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.griddynamics.com/feeds/1267669363329471790/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3946011063058389308&amp;postID=1267669363329471790" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1267669363329471790?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3946011063058389308/posts/default/1267669363329471790?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/griddynamics/~3/y_5F-YhRHiY/deploying-to-hyper-v-windows-over.html" title="Deploying to Hyper-V: Windows over Windows" /><author><name>Dmitry Korotkov</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_9g8QFmHJL_E/SxpGxHIjfwI/AAAAAAAAAL8/_KcgScF7CAM/S220/userpic.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://blog.griddynamics.com/2010/06/deploying-to-hyper-v-windows-over.html</feedburner:origLink></entry></feed>

