<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1680085285488970412</id><updated>2025-07-10T23:52:39.398-07:00</updated><category term="cache"/><category term="data grid"/><category term="transactions"/><category term="cloud"/><category term="compute grid"/><category term="grid"/><category term=".NET"/><category term="C++"/><category term="SQL"/><category term="distributed services"/><category term="portable objects"/><title type='text'>Distributed Thoughts</title><subtitle type='html'>By Dmitriy Setrakyan</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>147</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-8299874103139888506</id><published>2017-09-13T20:03:00.000-07:00</published><updated>2017-09-14T13:18:35.177-07:00</updated><title type='text'>What is Apache Ignite?</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.apache.org/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;87&quot; data-original-width=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7IjLGToqGPdnhqyfc-tg2UeRtDpRtnI4MlnBkae0MvjrOLREQDona0y9AezsIXxTrQ3KkNq9bAjtStQ8sRD3-vwN-_kXrqNINaLxWjDE0QVwRcEGyZFn20dBIlnEXhCegoQSfSdmBfic/s200/apache_ignite_200x87.png&quot; width=&quot;150&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
If you ever looked at &lt;a href=&quot;https://ignite.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;, you have probably noticed that it is a fairly rich platform with lots of components. However, despite the extensive feature set, Ignite community aims to make the platform easy to use and understand. Here is how the Ignite community defines their project:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;i&gt;Apache Ignite is&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;i&gt;the &lt;b&gt;in-memory&lt;/b&gt; computing platform&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;i&gt;that is &lt;b&gt;durable&lt;/b&gt;, &lt;b&gt;strongly consistent&lt;/b&gt;, and &lt;b&gt;highly available&lt;/b&gt;&lt;br /&gt;with powerful &lt;b&gt;SQL&lt;/b&gt;, &lt;b&gt;key-value&lt;/b&gt; and &lt;b&gt;processing&lt;/b&gt; APIs&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
So, in summary, Ignite looks like a distributed data storage that can work both, in-memory and on-disk, and provides SQL, key-value and processing APIs to the data. Sounds simple enough. However, to get a complete picture, perhaps it is better to define Ignite by answering several &lt;i&gt;&quot;Is Ignite a ...?&quot;&lt;/i&gt; questions:&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Is Ignite a persistent or pure in-memory storage?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Both&lt;/b&gt;. Native persistence in Ignite can be turned on and off. This allows Ignite to store data sets bigger than can fit in the available memory. Essentially, the smaller operational data sets can be stored in-memory only, and larger data sets that do not fit in memory can be stored on disk, using memory as a caching layer for better performance. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite an in-memory database (IMDB)?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Yes&lt;/b&gt;. Even though Ignite durable memory works well in-memory and on-disk, the disk persistence can be disabled and Ignite can act as a pure distributed in-memory database, with support for SQL and distributed joins. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite an in-memory data grid (IMDG)?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Yes&lt;/b&gt;. Ignite is a full-featured data grid, which can be used either in pure in-memory mode or with Ignite native persistence. It can also automatically integrate with any 3rd party databases, including any RDBMS or NoSQL stores. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite a distributed database?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Yes&lt;/b&gt;. Data in Ignite is either partitioned or replicated across a cluster of multiple nodes. This provides scalability and adds resiliency to the system. Ignite automatically controls how data is partitioned, however, users can plugin their own distribution (affinity) functions and collocate various pieces of data together for efficiency. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite an SQL database?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Not fully&lt;/b&gt;. Although Ignite aims to behave like any other relational SQL database, there are differences in how Ignite handles constraints and indexes. Ignite supports primary and secondary indexes, however, the uniqueness can only be enforced for the primary indexes. Ignite also does not support foreign key constraints. &lt;br /&gt;
&lt;br /&gt;
Essentially, Ignite purposely does not support any constraints that would entail a cluster broadcast message for each update and significantly hurt performance and scalability of the system. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite a transactional database?&amp;nbsp;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Not fully&lt;/b&gt;. ACID Transactions are supported, but only at key-value API level. Ignite also supports cross-partition transactions, which means that transactions can span keys residing in different partitions on different servers. At SQL level Ignite supports atomic, but not yet transactional consistency. Ignite community plans to implement SQL transactions in version 2.4. &lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;Is Ignite a key-value store?&lt;/h3&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Yes&lt;/b&gt;. Ignite provides a feature rich key-value API, that is JCache (JSR-107) compliant and supports Java, C++, and .NET. &lt;br /&gt;
&lt;br /&gt;
You can find out more about Ignite by visiting the freshly redesigned &lt;a href=&quot;https://ignite.apache.org/&quot;&gt;Ignite website&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/8299874103139888506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/8299874103139888506' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/8299874103139888506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/8299874103139888506'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2017/09/what-is-apache-ignite.html' title='What is Apache Ignite?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7IjLGToqGPdnhqyfc-tg2UeRtDpRtnI4MlnBkae0MvjrOLREQDona0y9AezsIXxTrQ3KkNq9bAjtStQ8sRD3-vwN-_kXrqNINaLxWjDE0QVwRcEGyZFn20dBIlnEXhCegoQSfSdmBfic/s72-c/apache_ignite_200x87.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-1174694140050930568</id><published>2017-09-07T17:39:00.000-07:00</published><updated>2017-09-07T20:32:57.047-07:00</updated><title type='text'>Apache Ignite - In Memory Performance with Durability of Disk</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;&lt;i&gt;Ignite is the &lt;b&gt;in-memory&lt;/b&gt; computing platform&lt;br /&gt;
that is &lt;b&gt;durable&lt;/b&gt;, strongly &lt;b&gt;consistent&lt;/b&gt;, and highly &lt;b&gt;available&lt;/b&gt;&lt;br /&gt;with powerful &lt;b&gt;SQL&lt;/b&gt;, &lt;b&gt;key-value&lt;/b&gt; and &lt;b&gt;processing&lt;/b&gt; APIs&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;Starting with 2.1 release, &lt;a href=&quot;https://ignite.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt; has become one of a very few in-memory computing systems that provides its own distributed persistence layer. Essentially, users do not have to integrate Ignite with any type of 3&lt;sup&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;rd&lt;/span&gt;&lt;/sup&gt; party databases (although such integration is supported), and start using Ignite as a primary storage of their data on disk and in memory.&lt;/span&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin: 0px 0px 10px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;So, what makes Ignite data storage unique? Let us look at a
few important features provided by Ignite. You will probably notice that some
of these features can also be seen in other data storage systems. However, it
is the combination of these features in one cohesive platform that makes Ignite
stand out among others.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;margin: 0px 0px 10.66px; text-align: left;&quot;&gt;
1. Durable Memory&lt;/h3&gt;
&lt;div style=&quot;margin: 0px 0px 10.66px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;Ignite durable memory component treats RAM not just as a
caching layer, but as a complete fully-functional storage layer. This means
that users can turn the persistence on and off as needed. If the persistence is
off, then Ignite, just like always, can act as a distributed In-Memory Database
or as an In-Memory Data Grid, depending whether you prefer to use SQL or
key-value APIs. If the persistence is turned on, then Ignite becomes a
distributed, horizontally scalable database that guarantees full data
consistency and is resilient to full cluster failures. On top of that, the data is stored in&lt;b&gt; off-heap memory&lt;/b&gt; so there are no GC pauses even on large data sets.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;b&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0tjNsovGwycu-7ibXkxgXYW1poSjZinSl-1gFWToYvhlHIMBSKes-KAGYtOzopFPHoB5GguIRri6ghSeyZb0o7J4t9eNftHDJh_JwMHXPYWWsr3nKKcwSOISJE2vO0PqBAD83OZKC-Yg/s1600/durable-memory.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;505&quot; data-original-width=&quot;1600&quot; height=&quot;202&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0tjNsovGwycu-7ibXkxgXYW1poSjZinSl-1gFWToYvhlHIMBSKes-KAGYtOzopFPHoB5GguIRri6ghSeyZb0o7J4t9eNftHDJh_JwMHXPYWWsr3nKKcwSOISJE2vO0PqBAD83OZKC-Yg/s640/durable-memory.png&quot; style=&quot;border: none;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;margin: 0px 0px 10.66px; text-align: left;&quot;&gt;
2. Complete SQL support&lt;/h3&gt;
&lt;div style=&quot;margin: 0px 0px 10.66px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;With the latest release, in addition to SQL querying, Ignite
added support for DDL and DML, allowing users to interact with Ignite using
pure SQL without writing any code. This means that users can create tables and
indexes, insert, update, and query data using only SQL. Having such complete
SQL support makes Ignite a one-of-a-kind &lt;b&gt;distributed SQL database&lt;/b&gt;.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;margin: 0px 0px 10.66px; text-align: left;&quot;&gt;
3. ACID compliance&lt;/h3&gt;
&lt;div style=&quot;margin: 0px 0px 10.66px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;Data stored in Ignite is ACID-compliant both in memory and
on disk, making Ignite a strongly consistent system. Ignite transactions work
across the network and can span multiple servers. This makes Ignite stand out
from the eventually consistent NoSQL systems that hardly support any type of
transactions.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3 style=&quot;margin: 0px 0px 10.66px; text-align: left;&quot;&gt;
4. Collocated Processing&lt;/h3&gt;
&lt;div style=&quot;margin: 0px 0px 10.66px;&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;Most traditional SQL and NoSQL databases work in a
client-server fashion, meaning that data must be brought to the client side for
processing. This approach requires lots of data movement from servers to
clients and generally does not scale.&lt;span style=&quot;margin: 0px;&quot;&gt;&amp;nbsp;
&lt;/span&gt;Ignite, on the other hand, allows for sending computations to the
data, moving only the light weight compute functions across the network. As a result, Ignite scales better and minimizes data movement. When
&lt;b&gt;collocated&lt;/b&gt;, all the data processing happens locally on the node that stores the
data, and only the result is brought back to the user.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8T6y8uz9ElT-xNBOPEGPwWEBVOyQ9W5C3GfuXteAliQ3TgpR6k6Z-NWvNkc0jY1sjWbzOI7bpfdGEdlttCzxxfqIE48zF_4suVFoX4W33-zmw1Ecb-3Mji8uHpxwZD3HO1UtpEr5985E/s1600/collocated-processing.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;758&quot; data-original-width=&quot;1600&quot; height=&quot;302&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8T6y8uz9ElT-xNBOPEGPwWEBVOyQ9W5C3GfuXteAliQ3TgpR6k6Z-NWvNkc0jY1sjWbzOI7bpfdGEdlttCzxxfqIE48zF_4suVFoX4W33-zmw1Ecb-3Mji8uHpxwZD3HO1UtpEr5985E/s640/collocated-processing.png&quot; style=&quot;border: none;&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3 style=&quot;margin: 0px 0px 10.66px; text-align: left;&quot;&gt;
5. Scalability and Durability&lt;/h3&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11pt; line-height: 107%; margin: 0px;&quot;&gt;Ignite is an elastic, horizontally scalable distributed system that supports adding and removing cluster nodes on demand. Ignite also allows for
storing multiple copies of the data, making it resilient to partial cluster
failures. If the persistence is enabled, then data stored in Ignite will also survive full cluster failures. Cluster restarts in Ignite can be very
fast, as the data becomes operational instantaneously directly from disk. As a result the data does not need to be preloaded in memory to begin processing, and Ignite caches will lazily warm up resuming the in memory performance.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/1174694140050930568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/1174694140050930568' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1174694140050930568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1174694140050930568'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2017/09/apache-ignite-in-memory-performance.html' title='Apache Ignite - In Memory Performance with Durability of Disk'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0tjNsovGwycu-7ibXkxgXYW1poSjZinSl-1gFWToYvhlHIMBSKes-KAGYtOzopFPHoB5GguIRri6ghSeyZb0o7J4t9eNftHDJh_JwMHXPYWWsr3nKKcwSOISJE2vO0PqBAD83OZKC-Yg/s72-c/durable-memory.png" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-1379001179423386133</id><published>2016-02-11T02:39:00.001-08:00</published><updated>2016-02-13T13:53:30.802-08:00</updated><title type='text'>GridGain In-Memory Data Fabric 7.5 is Released</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.gridgain.com/&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;50&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWaMFl4eOEy22Ioii9wjztfgFQlkmPTAd4nIGgbjURuhC0pBagV1mL072OQLk-4kWjkcO6ZCVWFrAOg-EOo436HTgmR5HlQH1RmX6ZVZ7dATtrgO7n-T2fHMD8Gqzo7PpPHxWx1WEcUFQ/s200/gridgain-logo.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Today the GridGain team has&amp;nbsp;announced the release of enterprise-grade &lt;a href=&quot;http://www.gridgain.com/download/&quot;&gt;GridGain In-Memory Data Fabric v. 7.5&lt;/a&gt;, based on &lt;a href=&quot;https://ignite.apache.org/&quot;&gt;Apache Ignite&lt;sup&gt;tm&lt;/sup&gt; v. 1.5&lt;/a&gt;. For those not familiar with GridGain or Apache Ignite, it provides the ability to distribute, cache, and compute on data in memory, including such features as in-memory data grid, compute grid, ANSI-99 in-memory SQL, real-time streaming, in-memory file system, and many more.&lt;br /&gt;
&lt;br /&gt;
Some of the most important features of this release, among others, include deadlock-free in-memory transactions, significant improvements to the zero-deployment model, and major performance improvements. All these features have been available in Apache Ignite 1.5 for a while, but now, after many rounds of load testing and bug fixes, have finally received GridGain&#39;s &lt;i&gt;ready-for-production&lt;/i&gt; stamp of approval.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Deadlock-Free Transactions&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj82w5NGygMxKqrYmEii-i7y_9qM9qEMkSZk4eUXQ9nl0U22dVsVcNNGLe6WkPxiHDTlZOS0Mx5lRj2GUl6HCpYZW5ja5aQ6gcpz9mFpNZEfvrKKs-V6KKoGKKlFtV-aVWTAAf5xNRrZlg/s1600/deadlock.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj82w5NGygMxKqrYmEii-i7y_9qM9qEMkSZk4eUXQ9nl0U22dVsVcNNGLe6WkPxiHDTlZOS0Mx5lRj2GUl6HCpYZW5ja5aQ6gcpz9mFpNZEfvrKKs-V6KKoGKKlFtV-aVWTAAf5xNRrZlg/s400/deadlock.png&quot; width=&quot;228&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Deadlocks usually happen when the same objects are concurrently updated in a different order by different transactions. Transactions begin to indefinitely wait on each other to complete, causing deadlock scenarios. Such problems are very difficult to spot and are even harder to debug. In production, they would require a full cluster restart, leading to costly system down times.&lt;br /&gt;
&lt;br /&gt;
The traditional solution to the deadlock problem is to ensure that applications acquire locks in the same order. However, this is easier said than done, especially in large distributed teams. Just imagine how many objects may be updated by a simple &lt;i&gt;&quot;transfer(...)&quot;&lt;/i&gt; method on some bank&#39;s API. &amp;nbsp;Grouping such calls in a common transaction is almost certain to generate a deadlock.&lt;br /&gt;
&lt;br /&gt;
A much better solution is to drop the locks altogether, which is what Apache Ignite community did. Essentially, all the transactions are given a chance to succeed until it is impossible to logically order some transaction. When this happens, the transaction optimistically fails with an exception and is allowed to be retried. Turns out that this &lt;i&gt;optimistic-serializable &lt;/i&gt;consistency model is about 50% faster than its &lt;i&gt;pessimistic&lt;/i&gt;&amp;nbsp;counterpart. However, the biggest benefit is that the deadlocks are now impossible.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Zero-Deployment (revisited)&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
With this release user objects are always kept in the binary form and are never deserialized on the server side. This makes GridGain servers agnostic to user domain models, allowing users to dynamically add or remove fields to their data types, or create and deploy new data types on the fly. When it comes to executing computations, Ignite provides a distributed class-loader which will automatically undeploy the old computation logic and deploy the new one.&lt;br /&gt;
&lt;br /&gt;
Such combination of the binary protocol together with the distributed class-loader creates a deployment-free cluster environment, where both data model and computation logic can be dynamically updated without any explicit deployment steps or down times.&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Pushing Performance Boundaries&lt;/b&gt;&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFvBsZiK6QWmKsonrhOUL1ktvQjj-FAizYs9BHjIOh11QnP9pg1D4auLNx5MrXxgdD4op7fT6lW8xEGa9EBEwA7a4IP1yYEXsDQbvz1pN6bKn9gg6BAxqkHduIcQ4lS0a-woWocBfi1i4/s1600/cheetah.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFvBsZiK6QWmKsonrhOUL1ktvQjj-FAizYs9BHjIOh11QnP9pg1D4auLNx5MrXxgdD4op7fT6lW8xEGa9EBEwA7a4IP1yYEXsDQbvz1pN6bKn9gg6BAxqkHduIcQ4lS0a-woWocBfi1i4/s1600/cheetah.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
With the introduction of the revised compact binary protocol, GridGain and Ignite became a lot faster, beating its nearest data grid competitor, Hazelcast, by over 100% in throughput and latencies. The performance benchmarks are public and can be viewed and downloaded on the &lt;a href=&quot;https://ignite.apache.org/benchmarks/ignite-vs-hazelcast.html&quot;&gt;Ignite website&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Other features of 7.5 release include OSGI compliance as well as new data streamers, including support for Twitter, MQTT, and Flume real time streams.&lt;br /&gt;
&lt;br /&gt;
The latest release can be downloaded &lt;a href=&quot;http://www.gridgain.com/download/&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/1379001179423386133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/1379001179423386133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1379001179423386133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1379001179423386133'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2016/02/gridgain-75-released.html' title='GridGain In-Memory Data Fabric 7.5 is Released'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWaMFl4eOEy22Ioii9wjztfgFQlkmPTAd4nIGgbjURuhC0pBagV1mL072OQLk-4kWjkcO6ZCVWFrAOg-EOo436HTgmR5HlQH1RmX6ZVZ7dATtrgO7n-T2fHMD8Gqzo7PpPHxWx1WEcUFQ/s72-c/gridgain-logo.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-5579726240162330220</id><published>2015-05-19T14:56:00.001-07:00</published><updated>2015-05-20T00:07:47.016-07:00</updated><title type='text'>Benchmarking Data Grids: Apache Ignite vs Hazelcast, Part II</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;86&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXkvl0kwuAFM6YplQKAZmkaQ7IfO5L4iqtZ9TJcsSh5dzOfTShGxovM8Q7yVIVdKJC_9mTiAgDmtx4Vp7KkY0y36b-JfJ-ghsGCIAOhZRkd7V1FxUkvARzzPPTk1a4d0Unki8UoNi8Zk/s1600/apache_ignite_200x87.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://hazelcast.org/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;38&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisz-ACh8Dh8cI8i06lN1viQajmzupWAvHFhPj8FCFvgG7plFsdQyxJZ2PO0KgYWiRq0tqAGpG9EZjHOcUZhfNtjVauqRGfDgZqtJMI1XgldGdwUf39ed4xidloPuWessrR_x-Quw5Xtvk/s1600/HazelcastLogo-Blue_Dark_600w.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
In my &lt;a href=&quot;http://gridgain.blogspot.com/2015/04/benchmarking-data-grids-apache-ignite.html&quot;&gt;previous post&lt;/a&gt; I have demonstrated benchmarks for &lt;i&gt;atomic&lt;/i&gt; JCache (JSR 107) operations and &lt;i&gt;optimistic transactions&lt;/i&gt; between&amp;nbsp;&lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;&lt;sup&gt;tm&lt;/sup&gt;&amp;nbsp;data grid and&amp;nbsp;&lt;a href=&quot;http://hazelcast.org/&quot;&gt;Hazelcast&lt;/a&gt;. In this blog I will focus on benchmarking the &lt;b&gt;&lt;i&gt;pessimistic&amp;nbsp;transactions&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
The difference between &lt;i&gt;optimistic&lt;/i&gt; and &lt;i&gt;pessimistic&lt;/i&gt;&amp;nbsp;modes is in the lock acquisition. In &lt;i&gt;pessimistic&lt;/i&gt; mode locks are acquired on first access, while in &lt;i&gt;optimistic&lt;/i&gt; mode locking happens during the commit phase. Pessimistic transactions provide a more consistent view on the data, given that, since locks are acquired early, you are guaranteed that no changes will happen to the data between transaction start and commit steps.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Yardstick Framework&lt;/h3&gt;
&lt;div&gt;
Just like before, I will be using &lt;a href=&quot;https://github.com/gridgain/yardstick&quot;&gt;Yardstick Framework&lt;/a&gt; for the benchmarks, specifically &lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-docker&quot;&gt;Yardstick-Docker&lt;/a&gt; extension.&amp;nbsp;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Transparency&lt;/h3&gt;
&lt;div&gt;
One of the most important characteristics of any benchmark is full transparency. The code for both, Apache Ignite and Hazelcast benchmarks is provided in the corresponding GIT repos:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-ignite&quot;&gt;https://github.com/yardstick-benchmarks/yardstick-ignite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-hazelcast/&quot;&gt;https://github.com/yardstick-benchmarks/yardstick-hazelcast/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Both, Apache Ignite and Hazelcast teams were given the opportunity to review the configuration and provide feedback.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Hardware&lt;/h3&gt;
&lt;div&gt;
Both benchmarks were executed on 4 AWS&amp;nbsp;c4.2xlarge instances used as servers and 1 AWS&amp;nbsp;c4.2xlarge instance used as the client and the driver for the benchmark.&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Benchmarks&lt;/h3&gt;
&lt;div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;&lt;b&gt;In this benchmark we attempt to compare pessimistic cache transactions only. Both, Ignite and Hazelcast have many other features that you can learn more about on their respective websites.&lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
The benchmarks were run in 2 modes, synchronous backups and asynchronous backups. In case of synchronous backups, the client waited until both, primary and backup copies were updated. In case of asynchronous backups, the client waited&amp;nbsp;only&amp;nbsp;for the primary copies to be updated and the backups were updated asynchronously. This was controlled with configuration properties of both products.&lt;br /&gt;
&lt;br /&gt;
Also, in both benchmarks clients were allowed to read data from backups whenever necessary.&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;/ol&gt;
&lt;div&gt;
The code used for the benchmark execution is very simple and can be found on GitHub:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;Apache Ignite&lt;/span&gt;: &lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-ignite/blob/master/src/main/java/org/apache/ignite/yardstick/cache/IgnitePutGetTxBenchmark.java&quot;&gt;IgnitePutGetTxBenchmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Hazelcast&lt;/span&gt;:&amp;nbsp;&lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-hazelcast/blob/master/src/main/java/org/yardstickframework/hazelcast/HazelcastPutGetTxPessimisticBenchmark.java&quot;&gt;HazelcastPutGetTxPessimisticBenchmark&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Apache Ignite:&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;brush:java;&quot;&gt;try (Transaction tx = ignite().transactions().txStart()) {
    Object val = cache.get(key);

    if (val != null)
        key = nextRandom(args.range() / 2, args.range());

    cache.put(key, new SampleValue(key));

    tx.commit();
}&lt;/pre&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Hazelcast:&lt;/b&gt;&lt;/h4&gt;
&lt;pre class=&quot;brush:java;&quot;&gt;TransactionContext tCtx = hazelcast().newTransactionContext(txOpts);

tCtx.beginTransaction();

TransactionalMap&amp;lt;Object, Object&amp;gt; txMap = tCtx.getMap(&quot;map&quot;);

Object val = txMap.getForUpdate(key);

if (val != null)
    key = nextRandom(args.range() / 2, args.range());

txMap.put(key, new SampleValue(key));

tCtx.commitTransaction();&lt;/pre&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;b&gt;Result:&lt;/b&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Just like with &lt;a href=&quot;http://gridgain.blogspot.com/2015/04/benchmarking-data-grids-apache-ignite.html&quot;&gt;optimistic&amp;nbsp;transactions&lt;/a&gt;, we found that in &lt;i&gt;pessimistic mode&lt;/i&gt;, Apache Ignite data grid is about &lt;b&gt;44% faster&lt;/b&gt; than Hazelcast. Apache Ignite averaged approximately &lt;b&gt;16,500&lt;/b&gt; transactions per second, while Hazelcast came in at about &lt;b&gt;11,000&lt;/b&gt; transactions per second.&lt;br /&gt;
&lt;br /&gt;
Here is a sample graph produced by Yardstick:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_XchEd9He4F25An7W0MOSeQyeRtQVUY8HBjbSk2aS6O_mEGeeLvUwOB4k4CdVptQ_IjDJ9P1FgZVHP2h5kfQhKAe8c9rnu5rh3_DrcGG0PtJhTJ-GF8S4QtBEo_xRyOLF5DMyY_V_BRk/s1600/Screen+Shot+2015-05-19+at+12.53.06+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;353&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_XchEd9He4F25An7W0MOSeQyeRtQVUY8HBjbSk2aS6O_mEGeeLvUwOB4k4CdVptQ_IjDJ9P1FgZVHP2h5kfQhKAe8c9rnu5rh3_DrcGG0PtJhTJ-GF8S4QtBEo_xRyOLF5DMyY_V_BRk/s640/Screen+Shot+2015-05-19+at+12.53.06+PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
Also, when running Hazelcast benchmarks, the following exception kept popping up in the logs, which keeps me wondering about the consistency of the data cached in Hazelcast overall:&lt;br /&gt;
&lt;pre class=&quot;brush:text; gutter:false;&quot;&gt;SEVERE: [172.30.1.95]:57500 [dev] [3.4.2] Lock is not owned by the transaction! Caller: fa705359-7154-4346-a5f2-292e1a2a75a5, Owner: Owner: fa705359-7154-4346-a5f2-292e1a2a75a5, thread-id: 105
com.hazelcast.transaction.TransactionException: Lock is not owned by the transaction! Caller: fa705359-7154-4346-a5f2-292e1a2a75a5, Owner: Owner: fa705359-7154-4346-a5f2-292e1a2a75a5, thread-id: 105
        at com.hazelcast.map.impl.tx.TxnPrepareBackupOperation.run(TxnPrepareBackupOperation.java:48)
        at com.hazelcast.spi.impl.Backup.run(Backup.java:92)
        at com.hazelcast.spi.impl.BasicOperationService$OperationHandler.handle(BasicOperationService.java:749)
        at com.hazelcast.spi.impl.BasicOperationService$OperationHandler.access$500(BasicOperationService.java:725)
        at com.hazelcast.spi.impl.BasicOperationService$OperationPacketHandler.handle(BasicOperationService.java:699)
        at com.hazelcast.spi.impl.BasicOperationService$OperationPacketHandler.handle(BasicOperationService.java:643)
        at com.hazelcast.spi.impl.BasicOperationService$OperationPacketHandler.access$1500(BasicOperationService.java:630)
        at com.hazelcast.spi.impl.BasicOperationService$BasicDispatcherImpl.dispatch(BasicOperationService.java:582)
        at com.hazelcast.spi.impl.BasicOperationScheduler$OperationThread.process(BasicOperationScheduler.java:466)
        at com.hazelcast.spi.impl.BasicOperationScheduler$OperationThread.doRun(BasicOperationScheduler.java:458)
        at com.hazelcast.spi.impl.BasicOperationScheduler$OperationThread.run(BasicOperationScheduler.java:432)
&lt;/pre&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/5579726240162330220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/5579726240162330220' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5579726240162330220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5579726240162330220'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/05/benchmarking-data-grids-apache-ignite.html' title='Benchmarking Data Grids: Apache Ignite vs Hazelcast, Part II'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXkvl0kwuAFM6YplQKAZmkaQ7IfO5L4iqtZ9TJcsSh5dzOfTShGxovM8Q7yVIVdKJC_9mTiAgDmtx4Vp7KkY0y36b-JfJ-ghsGCIAOhZRkd7V1FxUkvARzzPPTk1a4d0Unki8UoNi8Zk/s72-c/apache_ignite_200x87.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-5034075157612499437</id><published>2015-04-14T05:09:00.000-07:00</published><updated>2015-06-02T19:34:50.593-07:00</updated><title type='text'>Benchmarking Data Grids: Apache Ignite vs Hazelcast, Part I</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;86&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXkvl0kwuAFM6YplQKAZmkaQ7IfO5L4iqtZ9TJcsSh5dzOfTShGxovM8Q7yVIVdKJC_9mTiAgDmtx4Vp7KkY0y36b-JfJ-ghsGCIAOhZRkd7V1FxUkvARzzPPTk1a4d0Unki8UoNi8Zk/s1600/apache_ignite_200x87.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;http://hazelcast.org/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;38&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisz-ACh8Dh8cI8i06lN1viQajmzupWAvHFhPj8FCFvgG7plFsdQyxJZ2PO0KgYWiRq0tqAGpG9EZjHOcUZhfNtjVauqRGfDgZqtJMI1XgldGdwUf39ed4xidloPuWessrR_x-Quw5Xtvk/s1600/HazelcastLogo-Blue_Dark_600w.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Recently I have been doing many benchmarks comparing the incubating&amp;nbsp;&lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;&lt;sup&gt;tm&lt;/sup&gt;&amp;nbsp;project to other products. In this blog I will describe my experience in comparing &lt;a href=&quot;https://ignite.incubator.apache.org/features.html&quot;&gt;Apache Ignite Data Grid&lt;/a&gt; vs &lt;a href=&quot;http://hazelcast.org/&quot;&gt;Hazelcast Data Grid&lt;/a&gt;.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Yardstick Framework&lt;/h3&gt;
&lt;div&gt;
I will be using &lt;a href=&quot;https://github.com/gridgain/yardstick&quot;&gt;Yardstick Framework&lt;/a&gt; for the benchmarks, specifically &lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-docker&quot;&gt;Yardstick-Docker&lt;/a&gt; extension. Yardstick is an open source framework for performing distributed benchmarks. One of the best things about Yardstick is that it generates graphs at the end, so we can observe how the benchmark behaved throughout the whole execution.&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Transparency&lt;/h3&gt;
&lt;div&gt;
One of the most important characteristics of any benchmark is full transparency. The code for both, Apache Ignite and Hazelcast benchmarks is provided in the corresponding GIT repos:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-ignite&quot;&gt;https://github.com/yardstick-benchmarks/yardstick-ignite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/yardstick-benchmarks/yardstick-hazelcast/&quot;&gt;https://github.com/yardstick-benchmarks/yardstick-hazelcast/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
On startup, Yardstick simply accepts the URL of a GIT repo as a parameter and executes all the benchmarks provided in that repository. This approach makes it really easy to change existing benchmarks or add new ones.&lt;br /&gt;
&lt;br /&gt;
In the interest of full disclosure, I should also mention that I am one of the committers for Apache Ignite project. However, to the best of my ability, I try to stay away from any opinions and simply state the discovered facts here.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Hardware&lt;/h3&gt;
&lt;div&gt;
Both benchmarks were executed on 4 AWS&amp;nbsp;c4.2xlarge instances used as servers and 1 AWS&amp;nbsp;c4.2xlarge instance used as the client and the driver for the benchmark.&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Benchmarks&lt;/h3&gt;
&lt;div&gt;
Yardstick S3 functionality automatically adds benchmark results to the specified S3 bucket on Amazon S3 store. Moreover, if you run multiple sets of benchmarks, e.g. Apache Ignite and Hazelcast benchmarks, then Yardstick will automatically generate comparison graphs and store them in S3 bucket as well.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;&lt;b&gt;In this benchmark we attempt to compare Data Grid basic cache operations and transactions only. Both, Ignite and Hazelcast have many other features that you can find out on their respective websites.&lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
After some tweaking and tuning, here is what I found about Ignite and Hazelcast:&lt;/div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Both, Apache Ignite and Hazelcast, support distributed data grids (i.e. distributed partitioned caches). In short, they can be viewed as distributed partitioned key-value in-memory stores.&lt;/li&gt;
&lt;li&gt;Both, Apache Ignite and Hazelcast, implement JCache (JSR 107) specification&lt;/li&gt;
&lt;li&gt;Both are fairly easy to configure and introduce minimal dependencies into the project.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Both have redundancy and failover. In the benchmarks, we configure both products with 1 primary and 1 backup copies for each key stored in cache.&lt;/li&gt;
&lt;li&gt;Apache Ignite and Hazelcast have different configuration properties, but it is possible to configure them in the same way for the benchmark.&lt;/li&gt;
&lt;li&gt;Both have support for ACID transactions. Ignite allows to set OPTIMISTIC or PESSIMISTIC mode for transactions. Hazelcast also can be coded to work in OPTIMISTIC and PESSIMISTIC modes, even though they don&#39;t call it that way explicitly.&lt;/li&gt;
&lt;li&gt;The querying capabilities of both products are very different. I will be benchmarking them in the nearest future and will describe them in my next blog.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Basic Atomic Operations&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
We compared basic puts and puts-and-gets into the cache.&lt;br /&gt;
&lt;br /&gt;
The code used for the benchmark execution can be found on GitHub:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;Apache Ignite&lt;/span&gt;: &lt;a href=&quot;https://github.com/apacheignite/yardstick-ignite/blob/master/src/main/java/org/apache/ignite/yardstick/cache/IgnitePutBenchmark.java&quot;&gt;IgnitePutBenchmark&lt;/a&gt; and &lt;a href=&quot;https://github.com/apacheignite/yardstick-ignite/blob/master/src/main/java/org/apache/ignite/yardstick/cache/IgnitePutGetBenchmark.java&quot;&gt;IgnitePutGetBenchmark&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Hazelcast&lt;/span&gt;: &lt;a href=&quot;https://github.com/gridgain/yardstick-hazelcast/blob/master/src/main/java/org/yardstickframework/hazelcast/HazelcastPutBenchmark.java&quot;&gt;HazelcastPutBenchmark&lt;/a&gt; and &lt;a href=&quot;https://github.com/gridgain/yardstick-hazelcast/blob/master/src/main/java/org/yardstickframework/hazelcast/HazelcastPutGetBenchmark.java&quot;&gt;HazelcastPutGetBenchmark&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Result:&lt;/b&gt;&lt;br /&gt;
We found that both Ignite and Hazelcast exhibit about the same performance with Ignite being about 4% to 7% faster on most of the runs.&lt;br /&gt;
&lt;br /&gt;
Here are the graphs produced by Yardstick:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW2Mm-i4HnowppunQIdLTJaZvSAd0r53Hag7A9SxhFfHfM9dyxB3XF01BY7tvNRKoFf37lshJaJMyMt13G6_gCCqvdBBjTZDmw-PJ9Xu9cwOqhk3SvC56GW2kXg0rZzQAJmsc_RqkH3Y4/s1600/Screen+Shot+2015-04-13+at+12.30.27+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;326&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW2Mm-i4HnowppunQIdLTJaZvSAd0r53Hag7A9SxhFfHfM9dyxB3XF01BY7tvNRKoFf37lshJaJMyMt13G6_gCCqvdBBjTZDmw-PJ9Xu9cwOqhk3SvC56GW2kXg0rZzQAJmsc_RqkH3Y4/s1600/Screen+Shot+2015-04-13+at+12.30.27+PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpnSvgXwa7WQXFCNkWHro17gueh_LCI8XjIo_h6ky8ikEBI1NzhiTz6QSaxngko32vC7gB3dOJjKceYDB_bKdzxa3n2KyDT5MyYAx9GxKIwwWrpJgfxPCt29yVWJ7eekf5nbPMXcyOWFQ/s1600/Screen+Shot+2015-04-13+at+12.37.02+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpnSvgXwa7WQXFCNkWHro17gueh_LCI8XjIo_h6ky8ikEBI1NzhiTz6QSaxngko32vC7gB3dOJjKceYDB_bKdzxa3n2KyDT5MyYAx9GxKIwwWrpJgfxPCt29yVWJ7eekf5nbPMXcyOWFQ/s1600/Screen+Shot+2015-04-13+at+12.37.02+PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h4 style=&quot;clear: both; text-align: left;&quot;&gt;
Basic Transaction Operations&lt;/h4&gt;
We compared basic transactional puts and puts-and-gets into the cache in OPTIMISTIC mode.&lt;br /&gt;
&lt;br /&gt;
The code used for the benchmark execution can be found on GitHub:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;Apache Ignite&lt;/span&gt;:&amp;nbsp;&lt;a href=&quot;https://github.com/apacheignite/yardstick-ignite/blob/master/src/main/java/org/apache/ignite/yardstick/cache/IgnitePutTxBenchmark.java&quot;&gt;IgnitePutTxBenchmark&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://github.com/apacheignite/yardstick-ignite/blob/master/src/main/java/org/apache/ignite/yardstick/cache/IgnitePutGetTxBenchmark.java&quot;&gt;IgnitePutGetTxBenchmark&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Hazelcast&lt;/span&gt;:&amp;nbsp;&lt;a href=&quot;https://github.com/gridgain/yardstick-hazelcast/blob/master/src/main/java/org/yardstickframework/hazelcast/HazelcastPutTxBenchmark.java&quot;&gt;HazelcastPutTxBenchmark&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://github.com/gridgain/yardstick-hazelcast/blob/master/src/main/java/org/yardstickframework/hazelcast/HazelcastPutGetTxBenchmark.java&quot;&gt;HazelcastPutGetTxBenchmark&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Result:&lt;/b&gt;&lt;br /&gt;
The performance difference for OPTIMISTIC transactions was much bigger, with Ignite transactions outperforming Hazelcast transactions by about 35% to 45%.&lt;br /&gt;
&lt;br /&gt;
Here are the graphs produced by Yardstick:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGkJ8FElFNbjYOM3JONzwFLB4-asEDeQBVSrfLyswOc0wW44i9soVc9ZfsWNiW5NvLSceHLvWJgrGBnk8Dq16Bg-CRqbnXG2idE2t03WatAt3cHWLFe3Ydp3gBp1l9-CTYWyk2Gi09udA/s1600/Screen+Shot+2015-04-13+at+12.49.43+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;326&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGkJ8FElFNbjYOM3JONzwFLB4-asEDeQBVSrfLyswOc0wW44i9soVc9ZfsWNiW5NvLSceHLvWJgrGBnk8Dq16Bg-CRqbnXG2idE2t03WatAt3cHWLFe3Ydp3gBp1l9-CTYWyk2Gi09udA/s1600/Screen+Shot+2015-04-13+at+12.49.43+PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdwCMNPMK8YVWV4QnbFaE331mQ5nhkAMwEwZATOIcO6eCepUVmo3v7Is4S1XeMlwvRynHBDQUetMfOlj7oTMVEa8A8pUTML9wWzW0bWX2FeJgBEIbBxa2rat1ZXA9QKcjroQhcUTYgkYQ/s1600/Screen+Shot+2015-04-13+at+12.51.23+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdwCMNPMK8YVWV4QnbFaE331mQ5nhkAMwEwZATOIcO6eCepUVmo3v7Is4S1XeMlwvRynHBDQUetMfOlj7oTMVEa8A8pUTML9wWzW0bWX2FeJgBEIbBxa2rat1ZXA9QKcjroQhcUTYgkYQ/s1600/Screen+Shot+2015-04-13+at+12.51.23+PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In my following blogs I will compare the query performance of both products as well and will post my findings.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/5034075157612499437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/5034075157612499437' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5034075157612499437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5034075157612499437'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/04/benchmarking-data-grids-apache-ignite.html' title='Benchmarking Data Grids: Apache Ignite vs Hazelcast, Part I'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtXkvl0kwuAFM6YplQKAZmkaQ7IfO5L4iqtZ9TJcsSh5dzOfTShGxovM8Q7yVIVdKJC_9mTiAgDmtx4Vp7KkY0y36b-JfJ-ghsGCIAOhZRkd7V1FxUkvARzzPPTk1a4d0Unki8UoNi8Zk/s72-c/apache_ignite_200x87.png" height="72" width="72"/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-1389430236149808397</id><published>2015-04-08T08:53:00.001-07:00</published><updated>2015-04-08T08:58:56.994-07:00</updated><title type='text'>Streaming and Transforming Data with Apache Ignite</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjztICqoO4JwUYnuvwr3vXYUP1A8YOwIy2NWYoLCT7nJI52Sv4Lfi6LMpoLf4cGj8LrnDKm4QuvMSVo9EWFaDyR-GfQx_Jv3cAQP0pB4PJwsiR4aX0oLxCpMlW553zSuF3CFZwsXKi9q3A/s1600/logo_ignite_128x128.png&quot; width=&quot;100&quot;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
In its 1.0 release &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;&lt;sup&gt;tm&lt;/sup&gt; added much better streaming support with ability to perform various data transformations, as well as query the streamed data using standard SQL queries. Streaming in Ignite is generally used to ingest continuous large volumes of data into Ignite distributed caches (possibly configured with &lt;a href=&quot;http://apacheignite.readme.io/v1.0/docs/sliding-windows&quot;&gt;sliding windows&lt;/a&gt;). Streamers can also be used to simply preload large amounts of data into caches on startup.&lt;br /&gt;
&lt;br /&gt;
Here is an example of processing a stream of random numbers.&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The stream gets partitioned to multiple cluster nodes in such a way that same numbers will always be processed on the same node.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Upon receiving a number, our StreamTransformer will get the current count for that number and increment it by 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;try (IgniteDataStreamer&amp;lt;Integer, Long&amp;gt; stmr = ignite.dataStreamer(&quot;numbers&quot;)) {
    // Allow data updates.
    stmr.allowOverwrite(true);

    // Configure data transformation to count random numbers 
    // added to the stream.
    stmr.receiver(StreamTransformer.from((e, arg) -&amp;gt; {
        // Get current count.
        Long val = e.getValue();

        // Increment count by 1.
        e.setValue(val == null ? 1L : val + 1);

        return null;
    }));

    // Stream 10 million of random numbers in the range of 0 to 1000.
    for (int i = 1; i &amp;lt;= 10_000_000; i++) {
        stmr.addData(RAND.nextInt(1000), 1L);

        if (i % 500_000 == 0)
            System.out.println(&quot;Number of tuples streamed into Ignite: &quot; + i);
    }
}
&lt;/pre&gt;
As we are streaming the data into the system, we can also query it using standard SQL. In this case, the data type name (in the example below it is &quot;Long&quot;) is treated as a table name.
&lt;br /&gt;
&lt;br /&gt;
In the query below, we select 10 most popular numbers out of the stream.&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;// Query top 10 most popular numbers every.
SqlFieldsQuery top10Qry = new SqlFieldsQuery(
    &quot;select _key, _val from Long order by _val desc limit 10&quot;);

// Execute query and get the whole result set.
List&amp;lt;List&amp;lt;?&amp;gt;&amp;gt; top10 = stmCache.query(top10Qry).getAll();
&lt;/pre&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/1389430236149808397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/1389430236149808397' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1389430236149808397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1389430236149808397'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/04/streaming-and-transforming-data-with.html' title='Streaming and Transforming Data with Apache Ignite'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjztICqoO4JwUYnuvwr3vXYUP1A8YOwIy2NWYoLCT7nJI52Sv4Lfi6LMpoLf4cGj8LrnDKm4QuvMSVo9EWFaDyR-GfQx_Jv3cAQP0pB4PJwsiR4aX0oLxCpMlW553zSuF3CFZwsXKi9q3A/s72-c/logo_ignite_128x128.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-4034199603398796716</id><published>2015-04-05T23:05:00.001-07:00</published><updated>2015-04-27T08:36:03.318-07:00</updated><title type='text'>Apache Ignite Word Count Streaming Example</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.booksandsuch.com/wp-content/uploads/2014/02/Word-count.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.booksandsuch.com/wp-content/uploads/2014/02/Word-count.png&quot; height=&quot;150&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
In this example we will stream text into &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt; and count each individual word. We will also issue periodic SQL queries into the stream to query top 10 most popular words.&lt;br /&gt;
&lt;br /&gt;
The example will work as follows:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;We will setup up a cache to hold the words as they come from a stream.&lt;/li&gt;
&lt;li&gt;We will setup a 1 second sliding window to keep the words only for the last 1 second.&lt;/li&gt;
&lt;li&gt;StreamWords program will stream text data into Ignite.&lt;/li&gt;
&lt;li&gt;QueryWords program will query top 10 words out of the stream.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Cache Configuration&lt;/h2&gt;
We define a CacheConfig class which will provide configuration to be used from both programs, StreamWords and QueryWords. The cache will be a partitioned cache which will store words as values. To guarantee that identical words are cached on the same data node, we use &lt;a href=&quot;https://github.com/apache/incubator-ignite/blob/ignite-1.0.2/modules/core/src/main/java/org/apache/ignite/cache/affinity/AffinityUuid.java&quot;&gt;AffinityUuid&lt;/a&gt; type for unique cache keys.&lt;br /&gt;
&lt;br /&gt;
Note that in this example we use a sliding window of 1 second for our cache. This means that words will disappear from cache after 1 second since they were first entered into cache.&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public class CacheConfig {
  public static CacheConfiguration&amp;lt;String, Long&amp;gt; wordCache() {
    CacheConfiguration&amp;lt;String, Long&amp;gt; cfg = new CacheConfiguration&amp;lt;&amp;gt;(&quot;words&quot;);

    // Index individual words.
    cfg.setIndexedTypes(AffinityUuid.class, /*word type*/String.class);

    // Sliding window of 1 seconds.
    cfg.setExpiryPolicyFactory(FactoryBuilder.factoryOf(
      new CreatedExpiryPolicy(new Duration(SECONDS, 1))));

    return cfg;
  }
}
&lt;/pre&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Stream Words&lt;/h2&gt;
We define a StreamWords class which will be responsible to continuously read words form a local text file (&quot;alice-in-wonderland.txt&quot; in our case) and stream them into Ignite &lt;i&gt;&quot;words&quot;&lt;/i&gt; cache.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Example&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public class StreamWords {
  public static void main(String[] args) throws Exception {
    // Mark this cluster member as client.
    Ignition.setClientMode(true);

    try (Ignite ignite = Ignition.start(&quot;examples/config/example-ignite.xml&quot;)) {
      // The cache is configured with sliding window holding 1 second of the streaming data.
      IgniteCache&amp;lt;AffinityUuid, String&amp;gt; stmCache = ignite.getOrCreateCache(CacheConfig.wordCache());

      try (IgniteDataStreamer&amp;lt;AffinityUuid, String&amp;gt; stmr = ignite.dataStreamer(stmCache.getName())) {
        // Stream words from &quot;alice-in-wonderland&quot; book.
        while (true) {
          InputStream in = StreamWords.class.getResourceAsStream(&quot;alice-in-wonderland.txt&quot;);

          try (LineNumberReader rdr = new LineNumberReader(new InputStreamReader(in))) {
            for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
              for (String word : line.split(&quot; &quot;))
                if (!word.isEmpty())
                  // Stream words into Ignite.
                  // By using AffinityUuid as a key, we ensure that identical
                  // words are processed on the same cluster node.
                  stmr.addData(new AffinityUuid(word), word);
            }
          }
        }
      }
    }
  }
}
&lt;/pre&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Query Words&lt;/h2&gt;
We define a QueryWords class which will periodically query word counts form the cache.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;SQL Query&lt;/b&gt;&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;We use standard SQL to query popular words.&lt;/li&gt;
&lt;li&gt;Ignite SQL treats Java classes as SQL tables. Since our words are stored as simple String type, the SQL query below queries String table.&lt;/li&gt;
&lt;li&gt;Ignite always stores cache keys and values as &quot;_key&quot; and &quot;_val&quot; fields. In our case, &quot;_val&quot; is the word, so we use this syntax in our SQL query.&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;Example&lt;/b&gt;&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public class QueryWords {
  public static void main(String[] args) throws Exception {
    // Mark this cluster member as client.
    Ignition.setClientMode(true);

    try (Ignite ignite = Ignition.start()) {
      IgniteCache&amp;lt;String, Long&amp;gt; stmCache = ignite.getOrCreateCache(CacheConfig.wordCache());

      // Select top 10 words.
      SqlFieldsQuery top10Qry = new SqlFieldsQuery(
          &quot;select _val, count(_val) as cnt from String &quot; + 
            &quot;group by _val &quot; + 
            &quot;order by cnt desc &quot; + 
            &quot;limit 10&quot;,
          true /*collocated*/
      );

      // Query top 10 popular numbers every 5 seconds.
      while (true) {
        // Execute queries.
        List&amp;lt;List&amp;lt;?&amp;gt;&amp;gt; top10 = stmCache.query(top10Qry).getAll();

        // Print top 10 words.
        ExamplesUtils.printQueryResults(top10);

        Thread.sleep(5000);
      }
    }
  }
}
&lt;/pre&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Starting Server Nodes&lt;/h2&gt;
In order to run the example, you need to start data nodes. In Ignite, data nodes are called server nodes. You can start as many server nodes as you like, but you should have at least 1 in order to run the example.&lt;br /&gt;
&lt;br /&gt;
Server nodes can be started from command line as follows:&lt;br /&gt;
&lt;pre class=&quot;brush:bash&quot;&gt;bin/ignite.sh
&lt;/pre&gt;
You can also start server nodes programmatically, like so:&lt;br /&gt;
&lt;pre class=&quot;brush:java&quot;&gt;public class ExampleNodeStartup {
    public static void main(String[] args) throws IgniteException {
        Ignition.start();
    }
}
&lt;/pre&gt;
Here is how the output of the &lt;i&gt;QueryWords&lt;/i&gt; program looks like on my MacBook Pro laptop (I have started 2 server nodes and one &lt;i&gt;StreamWords&lt;/i&gt; program as well)
&lt;br /&gt;
&lt;pre class=&quot;brush:bash&quot;&gt;...
Query results:
(the,2890)
(and,1355)
(to,1298)
(a,1139)
(of,1029)
(said,1002)
(in,912)
(she,820)
(was,766)
(you,711)
Query results:
(the,1679)
(to,830)
(and,810)
(a,680)
(of,629)
(she,491)
(it,357)
(in,330)
(said,315)
(was,274)
...
&lt;/pre&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/4034199603398796716/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/4034199603398796716' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4034199603398796716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4034199603398796716'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/04/apache-ignite-word-count-streaming.html' title='Apache Ignite Word Count Streaming Example'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-4680784750362756232</id><published>2015-03-04T01:14:00.002-08:00</published><updated>2015-03-09T14:22:34.176-07:00</updated><title type='text'>Asynchronous APIs Done Right</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBQujlymomW3nC4_jDfIujChRAycxclr14atJkVAkIUimk4MFdt2Ka5FCrAohGF4__K9-hXVNCqwbPPTGRvgt_9zP6iuChwmNKjLqfKxZ8ZWS9gjiD-EZtii9nk78JpJGLyHhmmIP5WkA/s1600/time-for-async.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBQujlymomW3nC4_jDfIujChRAycxclr14atJkVAkIUimk4MFdt2Ka5FCrAohGF4__K9-hXVNCqwbPPTGRvgt_9zP6iuChwmNKjLqfKxZ8ZWS9gjiD-EZtii9nk78JpJGLyHhmmIP5WkA/s1600/time-for-async.jpg&quot; width=&quot;250&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Ever seen a product which has duplicated mirrored APIs for synchronous and asynchronous processing? I never liked such APIs as they introduce extra noise to what otherwise could be considered a clean design. There is really no point to have &lt;i&gt;myMethod()&lt;/i&gt; and &lt;i&gt;myMethodAsync()&lt;/i&gt; methods while all you are trying to do is to change the mode of method execution from synchronous to asynchronous.&lt;br /&gt;
&lt;br /&gt;
So how do we approach this problem? How do we make the same API operate synchronously or asynchronously by simply flipping a switch? I believe that &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;&amp;nbsp;project came up with a very neat and elegant solution to this problem.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Enhance the Java Futures&lt;/h3&gt;
First of all, we need to enhance standard Java futures. Standard &lt;i&gt;java.util.concurrent.Future&lt;/i&gt; allows you to cancel a task and wait for its completion synchronously, but it misses the whole point of asynchronous execution, which is to be notified about the completion of the operation asynchronously. Java 8 actually addresses this problem with &lt;i&gt;CompletableFuture&lt;/i&gt; abstraction, however, it does a lot more than that and may be an overkill for most of the programming tasks.&lt;br /&gt;
&lt;br /&gt;
Apache Ignite has an API called &lt;a href=&quot;https://ignite.incubator.apache.org/releases/1.0.0/javadoc/org/apache/ignite/lang/IgniteFuture.html&quot;&gt;IgniteFuture&lt;/a&gt; which extends standard &lt;i&gt;java.util.concurrent.Future&lt;/i&gt;&amp;nbsp;and adds ability to register asynchronous callbacks and chain callbacks one after another:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;public interface IgniteFuture&amp;lt;V&amp;gt; extends Future&amp;lt;V&amp;gt; {
    ...

    /**
     * Registers listener closure to be asynchronously notified whenever future completes.
     *
     * @param lsnr Listener closure to register. If not provided - this method is no-op.
     */
    public void listen(IgniteInClosure&amp;lt;? super IgniteFuture&amp;lt;V&amp;gt;&amp;gt; lsnr);

    /**
     * Make a chained future to convert result of this future (when complete) into a new format.
     * It is guaranteed that done callback will be called only ONCE.
     *
     * @param doneCb Done callback that is applied to this future when it finishes to produce chained future result.
     * @return Chained future that finishes after this future completes and done callback is called.
     */
    public &amp;lt;T&amp;gt; IgniteFuture&amp;lt;T&amp;gt; chain(IgniteClosure&amp;lt;? super IgniteFuture&amp;lt;V&amp;gt;, T&amp;gt; doneCb);
    
    ...
}
&lt;/pre&gt;
Now that we have the truly asynchronous futures, let&#39;s see how we can avoid duplicity of synchronous and asynchronous APIs.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
IgniteAsyncSupport&lt;/h3&gt;
By default, all API invocations in Apache Ignite are synchronous. From usability standpoint this makes sense, as most of the time we all utilize synchronous APIs and resort to asynchronous ones only when we really have to.&lt;br /&gt;
&lt;br /&gt;
For whenever we need asynchronous behavior, Apache Ignite has &lt;a href=&quot;http://apacheignite.readme.io/v1.0/docs/async-support&quot;&gt;IgniteAsyncSupport&lt;/a&gt;&amp;nbsp;interface which is a parent to all the APIs that require both, synchronous and asynchronous mode of operation. In Ignite, such APIs usually have to do with distributed operations and may take longer to comlete, like storing data in distributed caches, or executing a distributed computation.&lt;br /&gt;
&lt;br /&gt;
The main method here is&amp;nbsp;&lt;i&gt;&lt;b&gt;IgniteAsyncSupport.withAsync()&lt;/b&gt;&lt;/i&gt;&amp;nbsp;which switches any API into asynchronous mode of operation. Whenever asynchronous mode is enabled, the APIs will always store a future for every previous call on per-thread basis. This way, after having invoked an API in asynchronous mode, you can always get the&amp;nbsp;&lt;i&gt;IgniteFuture&lt;/i&gt;&amp;nbsp;for that call and listen for the result asynchronously.&lt;br /&gt;
&lt;br /&gt;
Here is an example of synchronous and asynchronous computations on the cluster.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Synchronous Compute:&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;// IgniteCompute has synchronous and asynchronous modes.
IgniteCompute compute = ignite.compute();

// Execute a job synchronously and wait for the result.
String res = compute.call(() -&amp;gt; &quot;Hello world&quot;);
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;Asynchronous Compute:&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;// Enable asynchronous mode (note that the same IgniteCompute API is used).
IgniteCompute asyncCompute = ignite.compute().withAsync();

// Asynchronously execute a job.
asyncCompute.call(() -&amp;gt; &quot;Hello world&quot;);

// Get the future for the above invocation.
IgniteFuture&amp;lt;String&amp;gt; fut = asyncCompute.future();

// Asynchronously listen for completion and print out the result.
fut.listen(f -&amp;gt; System.out.println(&quot;Job result: &quot; + f.get()));&lt;/pre&gt;
&lt;br /&gt;
Here is an example of a how asynchronous mode is enabled for distributed caches.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Synchronous Cache:&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;IgniteCache&amp;lt;String, Integer&amp;gt; cache = ignite.jcache(&quot;mycache&quot;);

// Synchronously store value in cache and get previous value.
Integer val = cache.getAndPut(&quot;1&quot;, 1);
&lt;/pre&gt;
&lt;b&gt;Asynchronous Cache:&lt;/b&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;// Enable asynchronous mode (note that the same IgniteCache API is used).
IgniteCache&amp;lt;String, Integer&amp;gt; asyncCache = ignite.jcache(&quot;mycache&quot;).withAsync();

// Asynchronously store value in cache.
asyncCache.getAndPut(&quot;1&quot;, 1);

// Get future for the above invocation.
IgniteFuture&amp;lt;Integer&amp;gt; fut = asyncCache.future();

// Asynchronously listen for the operation to complete.
fut.listenAsync(f -&amp;gt; System.out.println(&quot;Previous cache value: &quot; + f.get()));
&lt;/pre&gt;
&lt;br /&gt;
See Ignite documentation for more information about &lt;a href=&quot;http://apacheignite.readme.io/v1.0/docs/async-support&quot;&gt;Ignite Asynchronous Mode&lt;/a&gt;.&lt;br /&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6d7gKF1UGIxF-iUxldlVNvNdAOB4qHB_5WfjnfGZwXyDCvPUPjAeA20woW4jPhhvliS8CqOYzv7mxZL5Azy19ZJTwy9f8eIql03evYBZ4eo3zF5VdBzBDn7-huzD9mZ3hyphenhyphenZqDXi_LE7E/s1600/apache-ignite.png&quot; height=&quot;120&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;&amp;nbsp;is a distributed In-Memory Data Fabric which allows to distribute and cache data in memory, perform distributed computations, streaming, etc... Since most of the supported functionality in Ignite is distributed, having properly implemented asynchronous mode of operation becomes very critical.&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/4680784750362756232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/4680784750362756232' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4680784750362756232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4680784750362756232'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/03/asynchronous-apis-done-right.html' title='Asynchronous APIs Done Right'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBQujlymomW3nC4_jDfIujChRAycxclr14atJkVAkIUimk4MFdt2Ka5FCrAohGF4__K9-hXVNCqwbPPTGRvgt_9zP6iuChwmNKjLqfKxZ8ZWS9gjiD-EZtii9nk78JpJGLyHhmmIP5WkA/s72-c/time-for-async.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-4403462010764010197</id><published>2015-03-01T12:55:00.000-08:00</published><updated>2015-03-02T09:43:59.430-08:00</updated><title type='text'>Virtual Cluster Groups with Apache Ignite</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_pTEZ_P_RrgfapHUpDQ23TolLyhDPqqf50oErKbwo-TMW_s36AC5BPjJtUsgQRDP1fgYjye5qVDbT1tNf_GQUSH5VzGhRYq6rIcodsC5W01w1qDPHfOcskrS4tHHh8mVA6ouhenAdrFw/s1600/aws-cloud.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_pTEZ_P_RrgfapHUpDQ23TolLyhDPqqf50oErKbwo-TMW_s36AC5BPjJtUsgQRDP1fgYjye5qVDbT1tNf_GQUSH5VzGhRYq6rIcodsC5W01w1qDPHfOcskrS4tHHh8mVA6ouhenAdrFw/s200/aws-cloud.png&quot; height=&quot;120&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;br /&gt;
An easy-to-manage network cluster is a cluster in which all nodes are equal and can be brought up with identical configuration. However, even though all nodes are equal, it often still makes sense to assign application-specific roles to them, like &quot;workers&#39;, &quot;clients&quot;, or &quot;data-nodes&quot;. In &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt;, this concept is called &lt;b&gt;cluster groups&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt; is an In-Memory Data Fabric composed of multiple distributed components with Clustering APIs serving as the main backbone for the rest of the components, including Data Grid, Compute Grid, and Service Grid. I am one of the committers to this project and generally blog quite a bit about it.&lt;br /&gt;
&lt;br /&gt;
You can create virtual &lt;b&gt;cluster groups&lt;/b&gt; in Ignite based on any application-specific custom filter. However, to make things easier, Ignite comes with some predefined filters.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Select Remote Nodes&lt;/h3&gt;
&lt;div&gt;
Here is how you can execute a simple closure on all remote nodes. Remote nodes include all cluster members, except for the member who is starting the execution.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;final Ignite ignite = Ignition.ignite();

IgniteCluster cluster = ignite.cluster();

// Get compute instance which will only execute
// over remote nodes, i.e. not this node.
IgniteCompute compute = ignite.compute(cluster.forRemotes());

// Broadcast to all remote nodes and print the ID of the node 
// on which this closure is executing.
compute.broadcast(() -&amp;gt; System.out.println(&quot;Hello Node: &quot; + cluster.localNode().id());
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;
&lt;/h3&gt;
&lt;h3&gt;
&lt;br /&gt;&lt;/h3&gt;
&lt;h3&gt;
Select Worker Nodes&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
You can assign application specific roles to cluster members, like &quot;masters&quot; and &quot;workers&quot;, for example. This can be done via user attributes specified on node startup. For example, here is how you can bring up a cluster node with &quot;ROLE&quot; attribute set to &quot;worker&quot;:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;IgniteConfiguration cfg = new IgniteConfiguration();

Map&amp;lt;String,String&amp;gt; attrs = Collections.singletonMap(&quot;ROLE&quot;, &quot;worker&quot;);

cfg.setUserAttributes(attrs);

// Start Ignite node.
Ignite ignite = Ignition.start(cfg);
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Then here is how you would execute a closure only over nodes with role &quot;worker&quot;:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;IgniteCluster cluster = ignite.cluster();

// Get compute instance which will only execute over &quot;worker&quot; nodes.
IgniteCompute compute = ignite.compute(cluster.forAttribute(&quot;ROLE&quot;, &quot;worker&quot;));

// Broadcast to all &quot;worker&quot; nodes and print the ID of the node 
// on which this closure is executing.
compute.broadcast(() -&amp;gt; System.out.println(&quot;Hello Node: &quot; + cluster.localNode().id());
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Custom Cluster Groups&lt;/h3&gt;
And finally, you can create custom cluster groups based on any user-defined predicates. Such cluster groups will always only include the nodes that pass the predicate. For example, here is how we would create a group of cluster nodes that have CPU utilization less than 50%:
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot; style=&quot;text-align: left;&quot;&gt;// Nodes with less than 50% CPU load.
ClusterGroup readyNodes = cluster.forPredicate((node) -&amp;gt; node.metrics().getCurrentCpuLoad() &amp;lt; 0.5);

// Broadcast to all nodes with CPU load less than 50% and
// print the ID of the node on which this closure is executing.
compute.broadcast(() -&amp;gt; System.out.println(&quot;Hello Node: &quot; + cluster.localNode().id());
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
For more on cluster groups, visit &lt;a href=&quot;http://apacheignite.readme.io/v1.0/docs/cluster-groups&quot;&gt;Ignite Cluster Groups&lt;/a&gt; documentation.
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/4403462010764010197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/4403462010764010197' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4403462010764010197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4403462010764010197'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/03/virtual-cluster-groups-with-apache.html' title='Virtual Cluster Groups with Apache Ignite'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_pTEZ_P_RrgfapHUpDQ23TolLyhDPqqf50oErKbwo-TMW_s36AC5BPjJtUsgQRDP1fgYjye5qVDbT1tNf_GQUSH5VzGhRYq6rIcodsC5W01w1qDPHfOcskrS4tHHh8mVA6ouhenAdrFw/s72-c/aws-cloud.png" height="72" width="72"/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-3057545387579304579</id><published>2015-02-26T00:00:00.000-08:00</published><updated>2015-02-26T05:22:30.384-08:00</updated><title type='text'>Emergence of the In-Memory Data Fabric</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;!--[if gte mso 9]&gt;&lt;xml&gt;
 &lt;o:DocumentProperties&gt;
  &lt;o:Revision&gt;0&lt;/o:Revision&gt;
  &lt;o:TotalTime&gt;0&lt;/o:TotalTime&gt;
  &lt;o:Pages&gt;1&lt;/o:Pages&gt;
  &lt;o:Words&gt;544&lt;/o:Words&gt;
  &lt;o:Characters&gt;3106&lt;/o:Characters&gt;
  &lt;o:Company&gt;GridGain Systems&lt;/o:Company&gt;
  &lt;o:Lines&gt;25&lt;/o:Lines&gt;
  &lt;o:Paragraphs&gt;7&lt;/o:Paragraphs&gt;
  &lt;o:CharactersWithSpaces&gt;3643&lt;/o:CharactersWithSpaces&gt;
  &lt;o:Version&gt;14.0&lt;/o:Version&gt;
 &lt;/o:DocumentProperties&gt;
 &lt;o:OfficeDocumentSettings&gt;
  &lt;o:AllowPNG/&gt;
 &lt;/o:OfficeDocumentSettings&gt;
&lt;/xml&gt;&lt;![endif]--&gt;

&lt;!--[if gte mso 9]&gt;&lt;xml&gt;
 &lt;w:WordDocument&gt;
  &lt;w:View&gt;Normal&lt;/w:View&gt;
  &lt;w:Zoom&gt;0&lt;/w:Zoom&gt;
  &lt;w:TrackMoves/&gt;
  &lt;w:TrackFormatting/&gt;
  &lt;w:PunctuationKerning/&gt;
  &lt;w:ValidateAgainstSchemas/&gt;
  &lt;w:SaveIfXMLInvalid&gt;false&lt;/w:SaveIfXMLInvalid&gt;
  &lt;w:IgnoreMixedContent&gt;false&lt;/w:IgnoreMixedContent&gt;
  &lt;w:AlwaysShowPlaceholderText&gt;false&lt;/w:AlwaysShowPlaceholderText&gt;
  &lt;w:DoNotPromoteQF/&gt;
  &lt;w:LidThemeOther&gt;EN-US&lt;/w:LidThemeOther&gt;
  &lt;w:LidThemeAsian&gt;JA&lt;/w:LidThemeAsian&gt;
  &lt;w:LidThemeComplexScript&gt;X-NONE&lt;/w:LidThemeComplexScript&gt;
  &lt;w:Compatibility&gt;
   &lt;w:BreakWrappedTables/&gt;
   &lt;w:SnapToGridInCell/&gt;
   &lt;w:WrapTextWithPunct/&gt;
   &lt;w:UseAsianBreakRules/&gt;
   &lt;w:DontGrowAutofit/&gt;
   &lt;w:SplitPgBreakAndParaMark/&gt;
   &lt;w:EnableOpenTypeKerning/&gt;
   &lt;w:DontFlipMirrorIndents/&gt;
   &lt;w:OverrideTableStyleHps/&gt;
   &lt;w:UseFELayout/&gt;
  &lt;/w:Compatibility&gt;
  &lt;m:mathPr&gt;
   &lt;m:mathFont m:val=&quot;Cambria Math&quot;/&gt;
   &lt;m:brkBin m:val=&quot;before&quot;/&gt;
   &lt;m:brkBinSub m:val=&quot;&amp;#45;-&quot;/&gt;
   &lt;m:smallFrac m:val=&quot;off&quot;/&gt;
   &lt;m:dispDef/&gt;
   &lt;m:lMargin m:val=&quot;0&quot;/&gt;
   &lt;m:rMargin m:val=&quot;0&quot;/&gt;
   &lt;m:defJc m:val=&quot;centerGroup&quot;/&gt;
   &lt;m:wrapIndent m:val=&quot;1440&quot;/&gt;
   &lt;m:intLim m:val=&quot;subSup&quot;/&gt;
   &lt;m:naryLim m:val=&quot;undOvr&quot;/&gt;
  &lt;/m:mathPr&gt;&lt;/w:WordDocument&gt;
&lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;
 &lt;w:LatentStyles DefLockedState=&quot;false&quot; DefUnhideWhenUsed=&quot;true&quot;
  DefSemiHidden=&quot;true&quot; DefQFormat=&quot;false&quot; DefPriority=&quot;99&quot;
  LatentStyleCount=&quot;276&quot;&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;0&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Normal&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;heading 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 7&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 8&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 9&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 7&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 8&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 9&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;35&quot; QFormat=&quot;true&quot; Name=&quot;caption&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;10&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Title&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;1&quot; Name=&quot;Default Paragraph Font&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;11&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtitle&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;22&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Strong&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;20&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Emphasis&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;59&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Table Grid&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; UnhideWhenUsed=&quot;false&quot; Name=&quot;Placeholder Text&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;1&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;No Spacing&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; UnhideWhenUsed=&quot;false&quot; Name=&quot;Revision&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;34&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;List Paragraph&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;29&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Quote&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;30&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Quote&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 1&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 2&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 3&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 4&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 5&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 6&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;19&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtle Emphasis&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;21&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Emphasis&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;31&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtle Reference&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;32&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Reference&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;33&quot; SemiHidden=&quot;false&quot;
   UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Book Title&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;37&quot; Name=&quot;Bibliography&quot;/&gt;
  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; QFormat=&quot;true&quot; Name=&quot;TOC Heading&quot;/&gt;
 &lt;/w:LatentStyles&gt;
&lt;/xml&gt;&lt;![endif]--&gt;

&lt;!--[if gte mso 10]&gt;
&lt;style&gt;
 /* Style Definitions */
table.MsoNormalTable
 {mso-style-name:&quot;Table Normal&quot;;
 mso-tstyle-rowband-size:0;
 mso-tstyle-colband-size:0;
 mso-style-noshow:yes;
 mso-style-priority:99;
 mso-style-parent:&quot;&quot;;
 mso-padding-alt:0in 5.4pt 0in 5.4pt;
 mso-para-margin:0in;
 mso-para-margin-bottom:.0001pt;
 mso-pagination:widow-orphan;
 font-size:12.0pt;
 font-family:Cambria;
 mso-ascii-font-family:Cambria;
 mso-ascii-theme-font:minor-latin;
 mso-hansi-font-family:Cambria;
 mso-hansi-theme-font:minor-latin;}
&lt;/style&gt;
&lt;![endif]--&gt;



&lt;!--StartFragment--&gt;

&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
Some of us may have already heard the terms&lt;b&gt; Data Grid &lt;/b&gt;and
&lt;b&gt;Data Fabric&lt;/b&gt;, however, neither of these terms has been well defined in the
industry. In this blog, I will try to add some clarity to both terms by
outlining some main features for data grids and data fabrics.&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
What is a Data Grid&lt;/h2&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/images/in_memory_data.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;216&quot; src=&quot;https://ignite.incubator.apache.org/images/in_memory_data.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;
Often when doing meetup presentations about Apache Ignite, I
ask the crowd if anyone has ever heard of what a Data Grid is. I usually get
only a few hands. However, when I flip the question and ask what Distributed
Caching is, everyone in the room immediately raises their hands and nods in
understanding. The reality is that a Data Grid can be viewed as a Distributed
Cache with extra features, so if you do know what a Distributed Cache is, you
probably already know a lot about Data Grids as well.&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
Generally, the term &lt;i&gt;distributed
cache&lt;/i&gt; means ability to replicate data in memory, so it is accessible from
anywhere in the cluster. Data Grids usually accomplish this by partitioning
data in memory, where each cluster member is responsible only for its own
subset of the data. You can also think of it as a distributed Hash Table. This
way, the more servers are available in your cluster, the more data you can
cache. &lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
Data grids are generally known for having a fairly rich
feature set on top of in-memory caches. The 3 main features that are absolutely
mandatory for any data grid solution are:&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;/div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;distributed transactions&lt;/li&gt;
&lt;li&gt;distributed queries&lt;/li&gt;
&lt;li&gt;collocation of compute and data&lt;/li&gt;
&lt;/ul&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;Without the above 3 features, you cannot really call a
product a data grid. Many vendors also differentiate between each other by
adding other popular features, including:&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;/div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;SQL support&lt;/li&gt;
&lt;li&gt;Off-Heap Memory (to avoid lengthy GC pauses)&lt;/li&gt;
&lt;li&gt;WebSession Caching&lt;/li&gt;
&lt;li&gt;Hibernate Integration&lt;/li&gt;
&lt;li&gt;Database Integration&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
Some of the popular Data Grid providers include &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite&lt;/a&gt; (incubating), &lt;a href=&quot;http://hazelcast.org/&quot;&gt;Hazelcast&lt;/a&gt; and &lt;a href=&quot;http://infinispan.org/&quot;&gt;Infinispan&lt;/a&gt; in the open source space, and
&lt;a href=&quot;http://www.oracle.com/technetwork/middleware/coherence/overview/index.html&quot;&gt;Oracle Coherence&lt;/a&gt; and &lt;a href=&quot;http://www.gridgain.com/&quot;&gt;GridGain&lt;/a&gt; commercial offerings. GridGain is a commercial
offering of&amp;nbsp; the Apache Ignite.&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
What is an In-Memory Data Fabric&lt;/h2&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/index.html&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;96&quot; src=&quot;https://ignite.incubator.apache.org/images/apache-ignite.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;
In Memory Data Fabrics represent the natural evolution of in-memory
computing. Data Fabrics generally take a broader approach to in memory
computing, grouping the whole set of in memory computing use cases into a
collection of well-defined independent components. Usually a Data Grid is just
one of the components provided by a Data Fabric.&amp;nbsp; Additionally to the data grid functionality, an
In-Memory Data Fabric typically also includes a Compute Grid, CEP Streaming, an
In-Memory File System, and more.&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
The main advantage of an In-Memory Data Fabric is that all of
the provided in-memory computing components can be used independently, while
being well integrated with each other. For example, in Apache Ignite a Compute Grid knows how to
load-balance and schedule computations within a cluster, but when used together
with a Data Grid, the Compute Grid will also route all the computations that
process data to the cluster members responsible for caching that data. The same
goes for Streaming and CEP - when working with streamed data, all the
processing happens on the cluster members responsible for caching that data as
well.&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
Commonly seen features of In-Memory Data Fabrics include:&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;/div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Data Grid (must have for any Data Fabric)&lt;/li&gt;
&lt;li&gt;Compute Grid&lt;/li&gt;
&lt;li&gt;Service Grid&lt;/li&gt;
&lt;li&gt;Streaming &amp;amp; CEP&lt;/li&gt;
&lt;li&gt;Distributed File System&lt;/li&gt;
&lt;li&gt;In-Memory Database&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;MsoNormal&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/index.html&quot;&gt;Apache Ignite&lt;/a&gt;, an Apache Incubator project, is the only
In-Memory Data Fabric available in the Open Source space. GridGain provides a
commercial, enterprise edition of Apache Ignite that is targeted toward
production, business critical use cases.&lt;o:p&gt;&lt;/o:p&gt;&lt;/div&gt;
&lt;!--EndFragment--&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/3057545387579304579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/3057545387579304579' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/3057545387579304579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/3057545387579304579'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/02/emergence-of-in-memory-data-fabric.html' title='Emergence of the In-Memory Data Fabric'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-4620304563932079388</id><published>2015-02-17T15:49:00.002-08:00</published><updated>2015-02-20T01:24:52.208-08:00</updated><title type='text'>Apache Ignite In-Memory Data Fabric v1.0 is Born</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAnvDkf3KwhsRL7oKyNCmPE19aXDyS3jXw96U9JWJBMJ5Axg1R4bD5gPqGOtCK80oWeLgaJrMiiqjSJ-xPhZ4cia6gw6Z1BtNvYKQQYS1C8k5SLnSIS5vcbzFJHW7pTR9h6cPq8nIQEqA/s1600/apache-ignite_300x125.png&quot; height=&quot;82&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Today, as part of the community of Apache Ignite (incubating), I am proud to announce that we have made the first code drop of the &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite In-Memory Data Fabric&lt;/a&gt; – Apache Ignite v1.0 Release Candidate - &lt;a href=&quot;https://ignite.incubator.apache.org/#download&quot;&gt;available&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The Apache Ignite project started in September 2014, when the Open Source edition of the &lt;a href=&quot;http://www.gridgain.com/&quot;&gt;GridGain In-Memory Data Fabric&lt;/a&gt; was donated to the Apache Software Foundation and branded as Apache Ignite. Now, after 5 months of many &lt;a href=&quot;mailto:dev-subscribe@ignite.incubator.apache.org&quot;&gt;dev-list&lt;/a&gt; discussions and late nights, we finally have released a stable, well-tested release candidate of Apache Ignite 1.0.&lt;br /&gt;
&lt;br /&gt;
Going forward, the role of GridGain engineers will be to continue to actively contribute to the Ignite code base, but also to provide a hardened, enterprise-grade feature set on top of Apache Ignite. GridGain support will be available for both Apache Ignite and the GridGain In-Memory Data Fabric Enterprise Edition.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
What is an In-Memory Data Fabric&lt;/h2&gt;
So why should you care about Apache Ignite? First and foremost, Ignite is lightning fast and has virtually unlimited scale. Ignite is based on the former GridGain In-Memory Data Fabric Open Source edition, the leading open source in-memory data fabric, which has several known 1000+ node deployments.&lt;br /&gt;
&lt;br /&gt;
Apache Ignite has a very rich feature set. From the get-go, our main goal was to make Apache Ignite an all-in-one stop for everything you need for in-memory computing.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://ignite.incubator.apache.org/images/apache-ignite.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;201&quot; src=&quot;https://ignite.incubator.apache.org/images/apache-ignite.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Some of the &lt;a href=&quot;https://ignite.incubator.apache.org/features.html&quot;&gt;main features&lt;/a&gt; of the project include:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Advanced Clustering&lt;/li&gt;
&lt;li&gt;Distributed Caching (JCache)&lt;/li&gt;
&lt;li&gt;Data Grid&lt;/li&gt;
&lt;li&gt;Compute Grid&lt;/li&gt;
&lt;li&gt;Service Grid&lt;/li&gt;
&lt;li&gt;Streaming &amp;amp; CEP&lt;/li&gt;
&lt;li&gt;Distributed File System - IgniteFS&lt;/li&gt;
&lt;li&gt;Hadoop Accelerator&lt;/li&gt;
&lt;li&gt;Distributed Data Structures&lt;/li&gt;
&lt;li&gt;Distributed Messaging&lt;/li&gt;
&lt;li&gt;Distributed Events&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
But one of the coolest, new features in Ignite is its ability to automatically integrate with different RDBMS systems, such as Oracle, MySql, Postgres, DB2, Microsoft SQL, etc. This feature automatically generates the application domain model based on the schema definition of the underlying database, and then loads the data in memory.&lt;br /&gt;
&lt;br /&gt;
While you may be able to get some subset of the above functionality from other individual point solutions, the main benefit you get from the Apache Ignite In-Memory Data Fabric is the integration of all these components. For example, Ignite will automatically route your computations that need to process data to the cluster nodes responsible for caching this data. The same goes for the processing of streaming data as well. This approach is called &quot;collocation of compute and data&quot; and when applied, significantly reduces network traffic and increases scalability and performance.&lt;br /&gt;
&lt;br /&gt;
Here is an example of how you would broadcast a computation in Ignite:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;compute.broadcast(() -&amp;gt; System.out.println(&quot;Hello World&quot;);
&lt;/pre&gt;
&lt;br /&gt;
Here is cache example of how to perform an in-memory distributed transaction in Ignite:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;try (Transaction tx = ignite.transactions().txStart()) {
    Integer hello = cache.get(&quot;Hello&quot;);
  
    if (hello == 1)
        cache.put(&quot;Hello&quot;, 11);
  
    cache.put(&quot;World&quot;, 22);
  
    tx.commit();
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Ease Of Use&lt;/h2&gt;
Despite the breadth of its feature set, Apache Ignite is easy to deploy and use.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Installation&lt;/h4&gt;
The product does not have any custom installers. It comes as one ZIP file, which is ready to go once you unzip it. To startup multiple cluster nodes, simply execute &quot;bin/ignite.sh&quot; script multiple times.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Dependencies&lt;/h4&gt;
The project has 1 main dependency - &lt;b&gt;&lt;i&gt;ignite-core.jar&lt;/i&gt;&lt;/b&gt;. All other dependencies, like integration with Spring for configuration, or with H2 database for SQL, etc. can be added to the process a la carte by dragging corresponding folders form &quot;&lt;i&gt;libs/optional&lt;/i&gt;&quot; folder into &quot;&lt;i&gt;libs/&lt;/i&gt;&quot; folder.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Maven&lt;/h4&gt;
The project is fully mavenized, and is composed of over a dozen of maven artifacts that can be imported and used in any combination.&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
Standard APIs&lt;/h4&gt;
Ignite is based on standard Java APIs. For distributed caches and data grids, Ignite in its final 1.0 release will implement the &lt;b&gt;JCache (JSR107)&lt;/b&gt; standard. For distributed computations, you can utilize standard &lt;i&gt;ExecutorService&lt;/i&gt; API. There are also distributed &lt;i&gt;Queues&lt;/i&gt; and &lt;i&gt;Sets&lt;/i&gt;. Ignite also has implemented most of the data structures from the &lt;i&gt;java.util.concurrent&lt;/i&gt; package by distributing them in memory. &lt;i&gt;IgniteFS&lt;/i&gt; – the distributed file system provided by Ignite implements the standard Hadoop&lt;i&gt; FileSystem&lt;/i&gt; API and can be automatically plugged into any Hadoop installation.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Code Quality&lt;/h2&gt;
Apache Ignite is very stable and well tested. The development process is structured in such a way that before any merge to the main branch happens, over 10,000 tests are executed on top of JetBrains Team City, and all need to pass.&lt;br /&gt;
&lt;br /&gt;
Moreover, Ignite has its own QA team. All the main functionality undergoes scrupulous testing for every release. Also, every release is benchmarked against a previous release to ensure that it is at least as fast (or faster) and as stable as the previous release.&lt;br /&gt;
&lt;br /&gt;
Also, the project inherited several years of thorough testing and stability-tuning from the GridGain In-Memory Data Fabric Open Source edition, which boasts over a thousand production installations.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Community&lt;/h2&gt;
Even though the project has been in Apache for less than 4 months, it already has a vibrant and growing community. The project currently has 11 committers and about as many contributors, all of whom are very active. Some have joined the project just recently, but have already been actively contributing.&lt;br /&gt;
&lt;br /&gt;
We always welcome community contributions. If you would like to contribute, send an email to the Ignite dev list and we will get you started. And even if you are not ready to contribute immediately, I would like to invite everyone to join our dev list. Most of the discussions happen there, and you can find out a lot about where the project is going and also provide your own ideas.&lt;br /&gt;
&lt;br /&gt;
Another way, of course, to familiarize yourself with Apache Ignite, is to &lt;a href=&quot;https://git-wip-us.apache.org/repos/asf?p=incubator-ignite.git;a=tree&quot;&gt;take a look at the code&lt;/a&gt; and see what it can do for your project.&lt;br /&gt;
&lt;br /&gt;
You can download the Ignite bits on the &lt;a href=&quot;https://ignite.incubator.apache.org/&quot;&gt;Apache Ignite homepage&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: xx-small;&quot;&gt;Apache®, Apache Ignite, Ignite®, and the Apache Ignite logo are either registered trademarks or trademarks of the Apache Software Foundation in the United States and/or other countries.&lt;/span&gt;&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/4620304563932079388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/4620304563932079388' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4620304563932079388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4620304563932079388'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2015/02/apache-ignite-v10-is-born.html' title='Apache Ignite In-Memory Data Fabric v1.0 is Born'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAnvDkf3KwhsRL7oKyNCmPE19aXDyS3jXw96U9JWJBMJ5Axg1R4bD5gPqGOtCK80oWeLgaJrMiiqjSJ-xPhZ4cia6gw6Z1BtNvYKQQYS1C8k5SLnSIS5vcbzFJHW7pTR9h6cPq8nIQEqA/s72-c/apache-ignite_300x125.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-2296293871445812612</id><published>2014-10-31T12:39:00.000-07:00</published><updated>2014-10-31T12:46:18.462-07:00</updated><title type='text'>Chrontrack Technology, Powered by GridGain, Tracks NYC Marathon Runners</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;-webkit-font-smoothing: antialiased !important; background-color: white; margin-bottom: 25px !important; text-rendering: optimizelegibility; visibility: visible;&quot;&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 26px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;-webkit-font-smoothing: antialiased !important; background-color: white; margin-bottom: 25px !important; text-rendering: optimizelegibility; visibility: visible;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.runningnews.com.br/wp-content/uploads/2013/05/NovaYork.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.runningnews.com.br/wp-content/uploads/2013/05/NovaYork.jpg&quot; height=&quot;265&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a href=&quot;https://www.chronotrack.com/&quot; style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;ChronoTrack&lt;/a&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt; is an industry trusted provider of race solutions for race organizers and timing partners. Its hardware and software solutions paired with certified network of partners provide the most comprehensive set of timing, race management and live race services available.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;This weekend Chronotrack technology will be used to track NYC marathon runners. Essentially, every runner gets a chip embedded into a tag, and when they pass through the censors installed along the marathon track, their timings and other data are immediately sent back to the servers in real time.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;So why is this interesting? It turns out that when it comes to real-time race analytics to track hundreds of thousands of runners across the globe, standard disk-based processing simply does not scale. In order to achieve real-time performance, Chronotrack had to move to &lt;b&gt;in-memory processing&lt;/b&gt;, and now uses &lt;/span&gt;&lt;a href=&quot;http://www.gridgain.com/&quot; style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;GridGain In-Memory Data Fabric&lt;/a&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt; to provide marathon data in real time, being able to serve all sorts of race analytics in a matter of a few milliseconds.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;background-color: white; font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;Bloomberg TV&lt;/span&gt;&lt;/h2&gt;
&lt;span style=&quot;background-color: white; font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;Watch GridGain CEO, Abe Kleinfeld, talk about Chronotrack technology, powered by GridGain, on &lt;b&gt;&lt;i&gt;Bloomberg TV&lt;/i&gt;&lt;/b&gt;:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;-webkit-font-smoothing: antialiased !important; background-color: white; margin-bottom: 25px !important; text-rendering: optimizelegibility; visibility: visible;&quot;&gt;
&lt;br /&gt;
&lt;object data=&quot;http://www.bloomberg.com/video/embed/lpdAk0h4S2WjM94onxk~uw?height=395&amp;amp;width=640&quot; height=&quot;430&quot; style=&quot;overflow: hidden;&quot; width=&quot;640&quot;&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif; line-height: 26px;&quot;&gt;&lt;a href=&quot;http://www.bloomberg.com/video/nyc-marathon-and-the-tech-used-to-track-the-runners-lpdAk0h4S2WjM94onxk~uw.html&quot;&gt;http://www.bloomberg.com/video/nyc-marathon-and-the-tech-used-to-track-the-runners-lpdAk0h4S2WjM94onxk~uw.html&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/2296293871445812612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/2296293871445812612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/2296293871445812612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/2296293871445812612'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/10/chrontrack-technology-powered-by.html' title='Chrontrack Technology, Powered by GridGain, Tracks NYC Marathon Runners'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-6372630121693323478</id><published>2014-09-16T16:47:00.001-07:00</published><updated>2014-09-17T21:36:47.652-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cache"/><category scheme="http://www.blogger.com/atom/ns#" term="data grid"/><category scheme="http://www.blogger.com/atom/ns#" term="transactions"/><title type='text'>One-Phase-Commit - Fast Transactions For In-Memory Caches</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid06TOs63pZBzYWy6U7YuodsS_TgbxmQzDo1MbO5FE95CKl7qIk6NJPIWrtN1upb49WofvWACNKzw4FSwGbTN8Z1nJl1D0CVHcyBvynsexZRZEmX0G7gfTkyMDdQulw2sHjL-gzBCdPP8/s1600/icon-verify.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid06TOs63pZBzYWy6U7YuodsS_TgbxmQzDo1MbO5FE95CKl7qIk6NJPIWrtN1upb49WofvWACNKzw4FSwGbTN8Z1nJl1D0CVHcyBvynsexZRZEmX0G7gfTkyMDdQulw2sHjL-gzBCdPP8/s1600/icon-verify.png&quot; width=&quot;100&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
In my &lt;a href=&quot;http://gridgain.blogspot.com/2014/09/two-phase-commit-for-in-memory-caches.html&quot;&gt;previous blogs&lt;/a&gt; I have talked at length about &lt;i&gt;2-Phase-Commit&lt;/i&gt; transaction protocol for in memory caches, and how in-memory caches can handle failures a lot more efficiently than disk-based databases. In this blog I want to cover yet another very important optimization that can be utilized for in-memory caches, specifically for cases where data is partitioned across the network.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In-memory caches, and specifically in-memory data grids, such as &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt; or &lt;a href=&quot;http://www.oracle.com/technetwork/middleware/coherence/overview/index.html&quot;&gt;Oracle Coherence&lt;/a&gt;, often employ a technique called data partitioning, where every key in the key set is assigned to a partition, and every partition is assigned to a specific cluster member. Assigning keys to a partition is usually easy and is done similarly to how hash maps work:&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;b&gt;&lt;i&gt;key.hashCode() % N&lt;/i&gt;&lt;/b&gt;, where N is a total number of partitions.&lt;/blockquote&gt;
&lt;/div&gt;
Assigning a partition to a cluster node is a little trickier, as in case of failures or cluster topology changes, the amount of repartitioning has to be minimal. There are various algorithms that can be employed here, such as &lt;a href=&quot;http://en.wikipedia.org/wiki/Rendezvous_hashing&quot;&gt;Rendezvous Hashing&lt;/a&gt;, or &lt;a href=&quot;http://en.wikipedia.org/wiki/Consistent_hashing&quot;&gt;Consistent Hashing&lt;/a&gt;, which we will not be discussing here. Let&#39;s assume that after applying some of the partition strategy algorithms, your in-memory cache evenly distributed data among cluster nodes:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgepyowlLm6JcxRc4LR-1IUF4LIvAO3fxl8uIEMM2OmVxzp0F0wJ0GljePDdMmDFaw33NviLA-iziTUwffwdQ6nvxc289Je-nIaW_S2OdGuTiGWZnFynnzEq1n-J_fmKkSkXfsnZ5sybb8/s1600/data-paritioning.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgepyowlLm6JcxRc4LR-1IUF4LIvAO3fxl8uIEMM2OmVxzp0F0wJ0GljePDdMmDFaw33NviLA-iziTUwffwdQ6nvxc289Je-nIaW_S2OdGuTiGWZnFynnzEq1n-J_fmKkSkXfsnZ5sybb8/s1600/data-paritioning.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;i&gt;&lt;b&gt;&lt;span style=&quot;color: #999999;&quot;&gt;Figure 1: Cache Partition Distribution&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
Usually to achieve best performance we need to minimize the number of cluster nodes participating in a transaction. This can be done by ensuring that all the entries in the transaction belong to the same partition, which consecutively ensures that they all belong to the same node. It will also ensure that the backup copies for these entries will be grouped together on some other node as well (and secondary backups will be grouped together as well, and so on). Such custom key mapping is called &lt;i style=&quot;font-weight: bold;&quot;&gt;custom affinity mapping&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
For example, if we have &lt;i&gt;Employee&lt;/i&gt; objects and &lt;i&gt;Company&lt;/i&gt; objects, then we can ensure that all employees working for the same company will be mapped to the same partition by providing a custom &lt;i&gt;affinity-key&lt;/i&gt; for &lt;i&gt;Employees&lt;/i&gt;, which in this case will be the &lt;i&gt;&quot;companyId&quot;&lt;/i&gt;.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;&lt;b&gt;Custom affinity mapping&amp;nbsp;helps us ensure that all objects within a single transaction are mapped to the same cluster node, thus collocating the whole transaction logic on that node and minimizing the number of nodes involved in a transaction.&lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
The &lt;i&gt;1-Phase-Commit&lt;/i&gt;&amp;nbsp;optimization is possible only when we have 1 primary and 1 backup copy. Such deployments are most common for distributed caches. If we add 2 backup copies, then we have to resort to&amp;nbsp;&lt;i&gt;2-Phase-Commit&lt;/i&gt;, however, adding a 2nd backup copy is generally considered wasteful from memory standpoint and is rarely done. Diagram below illustrates the &lt;i&gt;1-Phase&lt;/i&gt; optimization:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTys3bTvMJUJ5Yz7Z-C-XIUU8O9PjyatVs4r6AvIAxBnfGuAn9_2hm1FgzoNKVkCTMxtimzF-Q0l-HARTs42qwSZlJC3BEEQRjTgpgogP4YL6G-UGnQIjKzzVQeTOXWiOtbailKGRmq_Y/s1600/1-phase-commit.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTys3bTvMJUJ5Yz7Z-C-XIUU8O9PjyatVs4r6AvIAxBnfGuAn9_2hm1FgzoNKVkCTMxtimzF-Q0l-HARTs42qwSZlJC3BEEQRjTgpgogP4YL6G-UGnQIjKzzVQeTOXWiOtbailKGRmq_Y/s1600/1-phase-commit.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: #999999;&quot;&gt;Figure 2: 1-Phase-Commit for Collocated Partition Transaction&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
The first deviation from standard transactions is that now the client node sends the whole transaction logic to the primary node. This is possible because we ensure in advance that all the keys we are transacting on are mapped to the same partition on that node. Once the primary node receives the transaction logic, it will acquire all the locks locally, and will send only one &lt;i&gt;commit&lt;/i&gt; message (without the &lt;i&gt;prepare&lt;/i&gt; message) to the backup node.&lt;br /&gt;
&lt;br /&gt;
Now let&#39;s analyze failure scenarios. In this case, failures of client nodes or backup nodes are not very interesting, as they do not affect the primary copies. Failures of primary nodes are a bit trickier, however they are still safe. If the primary node crashes before it sends the commit message, then the backup transaction never starts, so there are no side effects. If the primary node fails after or during the&lt;i&gt;&amp;nbsp;commit acknowledgement&lt;/i&gt;&amp;nbsp;is received from the backup node, then the backup transaction is committed, and data consistency is again not violated.&lt;br /&gt;
&lt;br /&gt;
The hardest part is that even though the data remains consistent in case of any cluster failures, how does the client node know whether the transaction was committed or not if it failed to get the final &lt;i&gt;acknowledgement&lt;/i&gt;, i.e. if the primary node failed before it was able to send the acknowledgement to the client? In this case the &lt;i&gt;&quot;recovery protocol&quot;&lt;/i&gt;&amp;nbsp;is initiated, which was described in detail in my &lt;a href=&quot;http://gridgain.blogspot.com/2014/09/two-phase-commit-for-distributed-in.html&quot;&gt;previous blog&lt;/a&gt;. Essentially, a message is sent to the backup node asking whether the transaction was committed or not. Since the backup node keeps a backlog of completed transaction IDs in memory, it can always check the backlog. If the backlog does not have the given transaction ID, the backup node will add it in the&amp;nbsp;&lt;i&gt;&quot;rolled back&quot;&lt;/i&gt; state and will reply to the client with &lt;i&gt;rollback&lt;/i&gt; acknowledgement. If afterwards the backup node actually does receive the commit request for the same transaction ID from the now failed primary node, it can verify in the backlog that it was rolled back and safely ignore it.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Conclusion&amp;nbsp;&lt;/h3&gt;
&lt;div&gt;
By ensuring that all objects participating in a transaction are mapped to the same logical partition, we can remove the whole &lt;i&gt;&quot;prepare&quot;&lt;/i&gt; phase from the distributed commit protocol, thus converting the standard &lt;i&gt;2-Phase-Commit&lt;/i&gt; into very light weight &lt;i&gt;1-Phase-Commit &lt;/i&gt;transactions.&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/6372630121693323478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/6372630121693323478' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/6372630121693323478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/6372630121693323478'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/09/one-phase-commit-fast-transactions-for.html' title='One-Phase-Commit - Fast Transactions For In-Memory Caches'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid06TOs63pZBzYWy6U7YuodsS_TgbxmQzDo1MbO5FE95CKl7qIk6NJPIWrtN1upb49WofvWACNKzw4FSwGbTN8Z1nJl1D0CVHcyBvynsexZRZEmX0G7gfTkyMDdQulw2sHjL-gzBCdPP8/s72-c/icon-verify.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-228755968443449606</id><published>2014-09-09T00:51:00.002-07:00</published><updated>2014-09-17T21:37:00.680-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cache"/><category scheme="http://www.blogger.com/atom/ns#" term="data grid"/><category scheme="http://www.blogger.com/atom/ns#" term="transactions"/><title type='text'>Two-Phase-Commit for In-Memory Caches - Part II</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Generally, persistent disk-oriented systems will require the additional &lt;i&gt;3rd phase&lt;/i&gt; in commit protocol in order to ensure data consistency in case of failures.&amp;nbsp;&lt;a href=&quot;http://gridgain.blogspot.com/2014/09/two-phase-commit-for-distributed-in.html&quot;&gt;In my previous blog&lt;/a&gt; I covered why the&amp;nbsp;&lt;i&gt;2-Phase-Commit&lt;/i&gt; protocol (without 3rd phase) is sufficient to handle failures for distributed in-memory caches. The explanation was based on the open source&amp;nbsp;&lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt;&amp;nbsp;architecture, however it can be applied to any in-memory distributed system.&lt;br /&gt;
&lt;br /&gt;
In this blog we will cover a case when an in-memory cache serves as a layer on top of a persistent database. In this case the database serves as a primary system of records, and distributed in-memory cache is added for performance and scalability reasons to accelerate reads and (sometimes) writes to the data. Cache must be kept consistent with database which means that a cache transaction must merge with the database transaction.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;&lt;b&gt;When we add a persistent store to an in-memory cache, our primary goal is to make sure that the cache will remain consistent with on-disk database at all times.&amp;nbsp;&lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
In order to keep the data consistent between memory and database, data is automatically loaded on demand whenever a read happens and the data cannot be found in cache. This behavior is called &lt;i&gt;read-through&lt;/i&gt;. Alternatively, whenever a write operation happens, data is stored in cache and is automatically persisted to the database. &amp;nbsp;This behavior is called &lt;i&gt;write-through&lt;/i&gt;. Additionally, there is also a mode called &lt;i&gt;write-behind&lt;/i&gt;&amp;nbsp;which batches up the writes in memory and flushes them to the database in one bulk operation (we will not be covering this mode here).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWPNkjttTfD9-9YBN50x_uyuHC61h1K1cqKbKh4zzTPFxPTnwRqh9-AbpOl3a_We52c3egYR7xUEG0gJXRBwpL_j4pYDs9PreBas2_V-BJoWukQC-qp2pK-mAELDEKFOkdjfe7N1xd4wM/s1600/read-write-through.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWPNkjttTfD9-9YBN50x_uyuHC61h1K1cqKbKh4zzTPFxPTnwRqh9-AbpOl3a_We52c3egYR7xUEG0gJXRBwpL_j4pYDs9PreBas2_V-BJoWukQC-qp2pK-mAELDEKFOkdjfe7N1xd4wM/s1600/read-write-through.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;Figure 1: Read-through operation for K2 &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; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
When we add a persistent store to the &lt;i&gt;2-Phase-Commit&lt;/i&gt; protocol, in order to merge cache and database transactions into one, the &lt;i&gt;coordinator&lt;/i&gt; will have to write the transactional changes to the database before it sends the &lt;i&gt;Commit&lt;/i&gt; message to the other participants. This way, if database transaction fails, the coordinator can still send the &lt;i&gt;Rollback&lt;/i&gt; message to everyone involved, so that the cached data will remain consistent with database. Figure below illustrates this behavior.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZkhtNYLrxO5ph9Znwfi1sLoedTpPsi5xF95jVR0BWC5_k6a6p6gB5mL86zCp7tP5b3b6XbMfB4gi0U-HKKx21rV4gb6UN3RAOy-b62pitzWhTdu1uJR5KKFM4Jeu60OsY45Cwa27SFc/s1600/2pc-store-ok.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihZkhtNYLrxO5ph9Znwfi1sLoedTpPsi5xF95jVR0BWC5_k6a6p6gB5mL86zCp7tP5b3b6XbMfB4gi0U-HKKx21rV4gb6UN3RAOy-b62pitzWhTdu1uJR5KKFM4Jeu60OsY45Cwa27SFc/s1600/2pc-store-ok.png&quot; height=&quot;367&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;i&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Figure 2: Two-Phase-Commit with In-Memory-Cache and Database&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Handling failures is actually more straight forward whenever a database is present rather than when it is not. We always assume that the database must have the utmost up-to-date copy, and it is acceptable to reload data from the database into cache whenever in doubt (see&amp;nbsp;&lt;i&gt;Figure 1&lt;/i&gt;). Just like in &lt;a href=&quot;http://gridgain.blogspot.com/2014/09/two-phase-commit-for-distributed-in.html&quot;&gt;my previous blog&lt;/a&gt;, the most challenging scenario here is when the &lt;i&gt;coordinator&lt;/i&gt;&amp;nbsp;node crashes (potentially together with other nodes), because in this case we cannot tell whether it crashed before it was able to commit to the database or not. Other failure scenarios are handled the same way with database present as without.&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Whenever we cannot tell whether the database commit had happened or not, we can simply &lt;b&gt;reload&lt;/b&gt; the relevant data from database into cache upon committing the transaction. This effectively ensures that database and cache always remain in consistent state.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnn1mXW9cJXxJnmA-xfEN6GAwpkU1nXkGL-wd5glEAsTMacaMCy9a2yerludA92vQHaInerj7oKDYJcHwvU5YJwmBcvd-T0eZkONj5UVI3WsHewJXpLb-A-3HRfyHk43PVSY_OL_iA26Q/s1600/2pc-store-failure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnn1mXW9cJXxJnmA-xfEN6GAwpkU1nXkGL-wd5glEAsTMacaMCy9a2yerludA92vQHaInerj7oKDYJcHwvU5YJwmBcvd-T0eZkONj5UVI3WsHewJXpLb-A-3HRfyHk43PVSY_OL_iA26Q/s1600/2pc-store-failure.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Conclusion&lt;/h3&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
When working with in-memory caches, we can always manage to keep the data within transactions consistent by slightly enhancing the standard &lt;i&gt;2-Phase-Commit&lt;/i&gt; protocol. The main advantage of in-memory vs. disk is that failure handling does not introduce any additional overhead, and we do not need to add an expensive &lt;i&gt;3rd phase&lt;/i&gt; to the &lt;i&gt;2-Phase-Commit&lt;/i&gt; protocol in order to keep caches consistent with databases in case of failures.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/228755968443449606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/228755968443449606' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/228755968443449606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/228755968443449606'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/09/two-phase-commit-for-in-memory-caches.html' title='Two-Phase-Commit for In-Memory Caches - Part II'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWPNkjttTfD9-9YBN50x_uyuHC61h1K1cqKbKh4zzTPFxPTnwRqh9-AbpOl3a_We52c3egYR7xUEG0gJXRBwpL_j4pYDs9PreBas2_V-BJoWukQC-qp2pK-mAELDEKFOkdjfe7N1xd4wM/s72-c/read-write-through.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-8223933307660501574</id><published>2014-09-02T16:07:00.001-07:00</published><updated>2014-09-17T21:31:17.649-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cache"/><category scheme="http://www.blogger.com/atom/ns#" term="data grid"/><category scheme="http://www.blogger.com/atom/ns#" term="transactions"/><title type='text'>Two-Phase-Commit for Distributed In-Memory Caches</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;i&gt;2-Phase-Commit&lt;/i&gt; is probably one of the oldest consensus protocols and is known for its deficiencies when it comes to handling failures, as it may indefinitely block the servers waiting in &lt;i&gt;prepare&lt;/i&gt;&amp;nbsp;state. To mitigate this, a &lt;i&gt;3-Phase-Commit&lt;/i&gt;&amp;nbsp;protocol was introduced which adds better fault tolerance at the expense of extra network round-trip message and higher latencies.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;I would like to extend these traditional quorum concepts into distributed in-memory caching, as it is particularly relevant to what we do at &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt;. GridGain too has&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;2-phase-commit&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; transactions, but unlike disk-based persistent systems, &lt;i&gt;&lt;b&gt;GridGain does not need to add a 3rd phase to the commit protocol in order to preserve data consistency during failures&lt;/b&gt;.&lt;/i&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;i&gt;We want to avoid the 3-Phase-Commit protocol because it adds an additional network round-trip and has a negative impact on latencies and performance.&lt;/i&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;In GridGain, the data is &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;partitioned&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; in memory, which in the purest form means that every key-value pair is assigned to a specific node within the cluster. If for example, we have 100 keys and 4 nodes, then every node will cache &lt;i&gt;100 / 4 = 25&lt;/i&gt; keys. This way the more nodes we have, the more data we can cache. Of course, in real life scenarios, we also have to worry about failures and redundancy, so for every key-value pair we will have 1 primary copy, and 1 or more backup copies.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Let us now look at the 2-Phase-Commit protocol in more detail to see why we can avoid the 3rd commit phase in GridGain.&lt;/span&gt;&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Two-Phase-Commit Protocol&lt;/span&gt;&lt;/h3&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Generally the &lt;i&gt;2-Phase-Commit&lt;/i&gt; protocol is initiated whenever an application has already made a decision to commit the transaction. The &lt;i&gt;Coordinator&lt;/i&gt; node sends a &lt;/span&gt;&lt;b style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;i&gt;Prepare&lt;/i&gt;&lt;/b&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; message to all the participating nodes holding primary copies (&lt;/span&gt;&lt;b style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;i&gt;primary nodes&lt;/i&gt;&lt;/b&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;), and the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;primary nodes&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;, after acquiring the necessary locks,&lt;/span&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;synchronously send the &lt;i&gt;&quot;Prepare&quot;&lt;/i&gt; message to the nodes holding backup copies (&lt;/span&gt;&lt;b style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&lt;i&gt;backup nodes&lt;/i&gt;&lt;/b&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;). Once every node votes &lt;i&gt;&quot;Yes&quot;&lt;/i&gt;, then the &lt;i&gt;&quot;Commit&quot;&lt;/i&gt;&amp;nbsp;message is sent and the transaction gets committed.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdrY6lVpbaF-ojY6cuAngoK3GI7a4xbY67Y0yxQlIAM2eRyhLhrQqV6IkMX2MQILvAWRIXXKzIbkRkdhlcjV-HLmTQAeu3Zd2GtbHZDk-FQ5-SypwU25lzPM79n-cdzSYemETiJN-ghN8/s1600/two-phase-commit.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdrY6lVpbaF-ojY6cuAngoK3GI7a4xbY67Y0yxQlIAM2eRyhLhrQqV6IkMX2MQILvAWRIXXKzIbkRkdhlcjV-HLmTQAeu3Zd2GtbHZDk-FQ5-SypwU25lzPM79n-cdzSYemETiJN-ghN8/s1600/two-phase-commit.png&quot; height=&quot;334&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;span style=&quot;color: #666666; font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;i&gt;Figure 1: 2-Phase-Commit Protocol For Distributed In-Memory Cache&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Advantages of In-Memory&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;So, why does in-memory-only processing allow us to avoid the 3rd phase as opposed to persistent disk-based transactions? The main reason is that the in-memory cache is purely volatile and does not need to worry about leaving any state behind in case of a crash. Contrast that to the persistent architectures, where we need to worry whether the state on disk was committed or not after a failure had occurred.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Another advantage of in-memory-only distributed cache is that&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;the only valid vote for the&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Prepare&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;message is&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Yes&quot;. T&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;here is really no valid reason for any cluster member to vote&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;No&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;This essentially means that the only reason a rollback should happen is if the&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Coordinator&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;node crashed before it was able to send the&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Prepare&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;message to all the participating nodes.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;span id=&quot;goog_1742555331&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_1742555332&quot;&gt;&lt;/span&gt;Now, that we have the ground rules settled, let&#39;s analyze what happens in case of failures:&lt;/span&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Backup Node Failures&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;If a backup node fails during either &lt;i&gt;&quot;Prepare&quot;&lt;/i&gt; phase or &lt;i&gt;&quot;Commit&quot;&amp;nbsp;&lt;/i&gt;phase, then no special handling is needed. The data will still be committed on the nodes that are alive. GridGain will then, in the background, designate a new backup node and the data will be copied there outside of the transaction scope.&lt;/span&gt;


&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Primary Node Failures&lt;/span&gt;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;If a primary node fails before or during the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Prepare&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; phase, then the coordinator will designate one of the backup nodes to become primary and retry the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Prepare&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; phase. If the failure happens before or during the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Commit&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; phase, then the backup nodes will detect the crash and send a message to the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Coordinator&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;node&amp;nbsp;to find out whether to commit or rollback. The transaction still completes and the data within distributed cache remains consistent.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Coordinator Node Failures&lt;/span&gt;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt;Failure of the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt;Coordinator&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt; node becomes a little tricky. Without the &lt;i&gt;Coordinator&lt;/i&gt; node, neither primary nodes, nor backup nodes know whether to commit the transaction or to rollback. In this case the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&quot;Recovery Protocol&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt; initiates, and all the nodes participating in the transaction send a message to every other&amp;nbsp;participating&amp;nbsp;node asking whether the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt;&quot;Prepare&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt; message was received. If at least one of the nodes replied&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt;&quot;No&quot;&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif; font-weight: normal;&quot;&gt;, then the transaction will be rolled back, otherwise the transaction will be committed.&lt;/span&gt;&lt;/h4&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Note that after all the nodes received the &lt;i&gt;&quot;Prepare&quot;&lt;/i&gt; message, we can safely commit, since voting&amp;nbsp;&lt;i&gt;&quot;No&quot;&lt;/i&gt; is impossible during the&amp;nbsp;&lt;i&gt;&quot;Prepare&quot;&lt;/i&gt; phase as stated above.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;It is possible that some nodes will have already committed the transaction by the time they have received the &lt;i&gt;Recovery Protocol&lt;/i&gt;&amp;nbsp;message from other nodes. For such cases, every node keeps a backlog of completed transaction IDs for a certain period of time. If there is no ongoing transaction with given ID found, then the backlog is checked. If the transaction was not found in the backlog, then it was never started, which means that the failure had occurred before the&amp;nbsp;&lt;i&gt;Prepare&lt;/i&gt; phase was completed and it is safe to rollback.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Since the data is volatile, and does not leave any state after the crash, it does not really matter if any of the primary or backup nodes also crashed together with the coordinator node. The&amp;nbsp;&lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;Recovery Protocol&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;&amp;nbsp;still works the same.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfrOIMIayQC3AA4YfteajASaKehSlTLry0B46lat95ycqxBTNrixmfNChC6IosYySjBk6htfXZAy4GKyZnhVXa5teP09Be8lB4hPU5rQHQcNsbSgxxalXExQOyfaqeWGccexnjIpUv1aA/s1600/two-phase-commit-failure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfrOIMIayQC3AA4YfteajASaKehSlTLry0B46lat95ycqxBTNrixmfNChC6IosYySjBk6htfXZAy4GKyZnhVXa5teP09Be8lB4hPU5rQHQcNsbSgxxalXExQOyfaqeWGccexnjIpUv1aA/s1600/two-phase-commit-failure.png&quot; height=&quot;194&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;color: #666666; font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;i&gt;Figure 2: Recovery Protocol&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Conclusion&lt;/span&gt;&lt;/h4&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;Note that we are able to fully recover the transaction without introducing the 3rd commit phase mainly because the data in distributed in-memory caches is volatile and node crashes do not leave any state behind.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;The important advantage of the &lt;i&gt;2-Phase-Commit Recovery Protocol &lt;/i&gt;in GridGain&lt;i&gt;&amp;nbsp;&lt;/i&gt;over the&amp;nbsp;&lt;i&gt;3-Phase-Commit&lt;/i&gt;&amp;nbsp;is that, in the absence of failures, the recovery protocol does not introduce any additional overhead, while the &lt;i&gt;3-phase-commit&lt;/i&gt; adds an additional synchronous network roundtrip to the transaction and, therefore, has negative impact on performance and latencies.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Georgia, Times New Roman, serif;&quot;&gt;GridGain also supports modes where it works with various persistent stores including transactional databases.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;In my next blog, I will cover the scenario where a cache sits on top of a transactional persistent store, and how the &lt;/span&gt;&lt;i style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt;2-Phase-Commit&lt;/i&gt;&lt;span style=&quot;font-family: Georgia, &#39;Times New Roman&#39;, serif;&quot;&gt; protocol works in that case.&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/8223933307660501574/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/8223933307660501574' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/8223933307660501574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/8223933307660501574'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/09/two-phase-commit-for-distributed-in.html' title='Two-Phase-Commit for Distributed In-Memory Caches'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdrY6lVpbaF-ojY6cuAngoK3GI7a4xbY67Y0yxQlIAM2eRyhLhrQqV6IkMX2MQILvAWRIXXKzIbkRkdhlcjV-HLmTQAeu3Zd2GtbHZDk-FQ5-SypwU25lzPM79n-cdzSYemETiJN-ghN8/s72-c/two-phase-commit.png" height="72" width="72"/><thr:total>4</thr:total><georss:featurename>Foster City, CA, USA</georss:featurename><georss:point>37.5585465 -122.2710788</georss:point><georss:box>37.508193999999996 -122.3517598 37.608899 -122.1903978</georss:box></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-4895915156398901773</id><published>2014-08-27T15:54:00.001-07:00</published><updated>2015-01-19T11:51:54.849-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="distributed services"/><category scheme="http://www.blogger.com/atom/ns#" term="portable objects"/><title type='text'>GridGain 6.2.0 Released with Portable Objects and Distributed Services</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; height=&quot;45&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I am pleased to announce the release of &lt;b&gt;&lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain Open Source In-Memory Computing Platform 6.2.0&lt;/a&gt;&lt;/b&gt;. The main components of the platform are: &lt;i&gt;compute grid&lt;/i&gt;, &lt;i&gt;data grid (or in-memory distributed cache)&lt;/i&gt;, and &lt;i&gt;CEP&amp;nbsp;streaming&lt;/i&gt;.&amp;nbsp;This release revolves primarily around Portable Object functionality as well as Distributed (or Guaranteed) Services.&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Portable Objects&lt;/h2&gt;
One of the main benefits of &lt;i&gt;&lt;a href=&quot;http://entdoc.gridgain.org/latest/Portable+Cross+Platform+Objects&quot;&gt;Portable Objects&lt;/a&gt;&lt;/i&gt;, which was not available in our prior release, is the ability to access any data or field without having to deserialize the entire object. This brings significant performance improvements to the server-side processing of in-memory cached data, as filtering remote caches and executing SQL or predicate-based queries becomes very inexpensive and fast. As a matter of fact, you don’t even need to have class definitions on the server side, which essentially allows for dynamic structural changes of cached data without the need to restart the cluster.&lt;br /&gt;
&lt;br /&gt;
Here is an example of how a single field can be accessed from a portable object without having to deserialize it into a concrete class representation:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;GridCacheProjection&amp;lt;Integer, GridPortableObject&amp;gt; prj = cache.keepPortable();

int myKey = 123;

GridPortableObject val = prj.get(myKey);

String field = val.field(&quot;myFieldName&quot;);
&lt;/pre&gt;
In addition, portable objects also include the ability to perform the following:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Make any object portable with zero code change to your existing code.&lt;/li&gt;
&lt;li&gt;Nest portable objects within each other.&lt;/li&gt;
&lt;li&gt;Automatically handle circular or null references.&lt;/li&gt;
&lt;li&gt;Optionally avoid deserialization of objects on the server side (objects are stored in GridPortableObject format).&lt;/li&gt;
&lt;li&gt;Avoid the need to have concrete class definitions on the server side.&lt;/li&gt;
&lt;li&gt;Dynamically change the structure of the classes without having to restart the cluster.&lt;/li&gt;
&lt;li&gt;Index into portable objects for querying purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Distributed Services&lt;/h2&gt;
&lt;i&gt;&lt;a href=&quot;http://doc.gridgain.org/latest/Distributed+Services&quot;&gt;Distributed Services&lt;/a&gt;&lt;/i&gt; allow for controlled deployment of any service on the grid. You can think of a distributed service as a fault-tolerant thread pool, for which you can configure how many threads are allowed to be deployed on each grid node.&lt;br /&gt;
&lt;br /&gt;
For example, what if you need to deploy a web server within your cluster, but you are only allowed to have one instance of it deployed? If the node on which your web server is deployed fails, then you want it to automatically start up on another server. Distributed Services allow you to have such functionality, in this case by deploying a cluster-wide singleton service which will start your web server.&lt;br /&gt;
&lt;br /&gt;
With distributed services you can do the following:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Automatically deploy any number of service instances in the grid.&lt;/li&gt;
&lt;li&gt;Automatically deploy singletons, including cluster-singleton, node-singleton, or key-affinity-singleton.&lt;/li&gt;
&lt;li&gt;Automatically deploy services on node start-up by specifying them in grid configuration.&lt;/li&gt;
&lt;li&gt;Undeploy any of the deployed services.&lt;/li&gt;
&lt;li&gt;Get information about service deployment topology within the grid.&lt;/li&gt;
&lt;/ul&gt;
Here is an example of how a simple cluster singleton service can be deployed:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;// Simple service implementation.
public class MyGridService implements GridService {
    @Override public void cancel(GridServiceContext ctx) {
        // No-op.
    }

    @Override public void execute(GridServiceContext ctx) {
        // Loop until service is cancelled.
        while (!ctx.isCancelled()) {
            // Do something.
            ...
        }
    }
}
...
GridServices svcs = grid.services();

GridFuture&amp;lt;?&amp;gt; fut = svcs.deployClusterSingleton(&quot;mySingleton&quot;, new MyGridService());

// Wait for deployment to complete.
fut.get();
&lt;/pre&gt;
Click here to &lt;a href=&quot;http://www.gridgain.org/download&quot;&gt;download GridGain 6.2.0&lt;/a&gt;.
&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/4895915156398901773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/4895915156398901773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4895915156398901773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/4895915156398901773'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/08/gridgain-620-released-with-portable.html' title='GridGain 6.2.0 Released with Portable Objects and Distributed Services'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-9007752594404382177</id><published>2014-07-03T19:24:00.000-07:00</published><updated>2014-07-03T19:40:28.108-07:00</updated><title type='text'>GridGain 6.1.9 - One Click Installation - One Jar Dependency</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; height=&quot;45&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
For those who are not familiar with &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt;, it is an open source distributed data grid product mainly focusing on distributed in-memory caching, &amp;nbsp;distributed computations, and streaming. It generally addresses all sorts of performance and scalability challenges for business applications by bringing and caching data in memory and allowing to compute on it.&lt;br /&gt;
&lt;br /&gt;
With release 6.1.9, GridGain significantly simplified its installation and deployment. GridGain now allows for:&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;&lt;b&gt;One Click Installation:&lt;/b&gt;&lt;br /&gt;The product simply has to be downloaded and unzipped. After that it is ready to be used.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;One Jar Dependency:&lt;/b&gt;&lt;br /&gt;GridGain now has only one mandatory dependency - gridgain-6.1.9.jar. All other jars are optional.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Essentially, you still have support for the same set of features, like Spring configuration, or Hibernate L2 cache, but you don&#39;t have to have dependency on Spring or Hibernate, or anything else, unless you start using it. To add a dependency to GridGain, simply drag and drop a corresponding folder from &lt;i&gt;&quot;libs/optional&quot;&lt;/i&gt; to &lt;i&gt;&quot;libs/&quot;&lt;/i&gt; folder. For example, to add log4j dependency, drag &lt;i&gt;&quot;libs/optional/gridgain-log4j&quot;&lt;/i&gt; folder into &lt;i&gt;&quot;libs&quot;&lt;/i&gt; folder.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here is how GridGain 6.1.9 structure looks with only one mandatory &lt;i&gt;gridgain-6.1.9.jar&lt;/i&gt; file. Note that in the example below, &lt;i&gt;gridgain-indexing&lt;/i&gt; and &lt;i&gt;gridgain-spring&lt;/i&gt; modules are located in the &lt;i&gt;&quot;libs/&quot;&lt;/i&gt; folder, and therefore are enabled.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiHefq_t14zArci3PuY-fCzywWmuz93D-JUoLuqJv5lvIzTN_XH3gC44jiW-Mk_rIjFbnRnnTuV9Mnh_KdWnFBlT9EPkOmLo63uMvz4bz0yxZMu1E0TVoDn1SPAI33swFj5ytvaNZ-3_4/s1600/gridgain-6.1.9-structure.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiHefq_t14zArci3PuY-fCzywWmuz93D-JUoLuqJv5lvIzTN_XH3gC44jiW-Mk_rIjFbnRnnTuV9Mnh_KdWnFBlT9EPkOmLo63uMvz4bz0yxZMu1E0TVoDn1SPAI33swFj5ytvaNZ-3_4/s1600/gridgain-6.1.9-structure.png&quot; height=&quot;233&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
You can download GridGain 6.1.9 Open Source edition here: &lt;a href=&quot;http://www.gridgain.org/download/&quot;&gt;www.gridgain.org/download/&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/9007752594404382177/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/9007752594404382177' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/9007752594404382177'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/9007752594404382177'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/07/gridgain-619-one-click-installation-one.html' title='GridGain 6.1.9 - One Click Installation - One Jar Dependency'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiHefq_t14zArci3PuY-fCzywWmuz93D-JUoLuqJv5lvIzTN_XH3gC44jiW-Mk_rIjFbnRnnTuV9Mnh_KdWnFBlT9EPkOmLo63uMvz4bz0yxZMu1E0TVoDn1SPAI33swFj5ytvaNZ-3_4/s72-c/gridgain-6.1.9-structure.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-18246881368024816</id><published>2014-06-16T18:12:00.000-07:00</published><updated>2014-09-17T21:33:20.289-07:00</updated><title type='text'>G1 Garbage Collector Thrashes On Larger Heaps</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Since the&amp;nbsp;&lt;a href=&quot;http://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html&quot;&gt;G1 (garbage-first) garbage collector&lt;/a&gt; has been released, there were expectations that it would finally perform better for larger heap sizes (&amp;gt;16GB). Unfortunately those expectations were not met. While G1 garbage collector is meant to remove larger GC pauses, the sporadic and unpredictable behavior of G1 collector on larger heaps renders it generally unusable for any system sensitive to performance SLAs.&lt;br /&gt;
&lt;br /&gt;
At &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt;, having worked on a distributed caching (data grid) product for many years, we constantly benchmark with various Garbage Collectors to find the optimal configuration for larger heap sizes. From conducting numerous tests, we have concluded that unless you are utilizing some&amp;nbsp;&lt;b&gt;off-heap technology&lt;/b&gt;&amp;nbsp;(e.g. &lt;a href=&quot;http://doc.gridgain.org/latest/Off-Heap+Memory&quot;&gt;GridGain OffHeap&lt;/a&gt;), no Garbage Collector provided with JDK will render any kind of stable GC performance with heap sizes larger that 16GB. For example, on 50GB heaps we can often encounter up to 5 minute GC pauses, with average pauses of 2 to 4 seconds.&lt;br /&gt;
&lt;br /&gt;
Here is a good comparison of a simple test for a cache &#39;put&#39; benchmark on 50GB of memory. The &lt;span style=&quot;color: blue;&quot;&gt;&lt;b&gt;blue&lt;/b&gt;&lt;/span&gt; graph was run with &lt;span style=&quot;color: blue;&quot;&gt;&lt;b&gt;G1 garbage collector&lt;/b&gt;&lt;/span&gt; set to 200ms average GC pauses, and the &lt;b&gt;&lt;span style=&quot;color: #6aa84f;&quot;&gt;green&lt;/span&gt;&lt;/b&gt; one was run with &lt;span style=&quot;color: #6aa84f;&quot;&gt;&lt;b&gt;GridGain OffHeap Memory&lt;/b&gt;&lt;/span&gt; technology. In each test we are storing over 120,000,000 objects in cache from multiple threads under load on a cluster of 2 servers:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv3brMS44ncPgB-0-Xihfr42D_Y8UHZFQMdfNiRD9zTH9QsqDzVWmEh3c2g4zDPAYZ0OGE3Trd8fCBlAy_v38VjWa9RlFMv4HeZV2pk0wtgJT0r3fou2c8YSIEc8F5X6koAqUo6bxeBck/s1600/Screen+Shot+2014-06-16+at+4.41.12+PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv3brMS44ncPgB-0-Xihfr42D_Y8UHZFQMdfNiRD9zTH9QsqDzVWmEh3c2g4zDPAYZ0OGE3Trd8fCBlAy_v38VjWa9RlFMv4HeZV2pk0wtgJT0r3fou2c8YSIEc8F5X6koAqUo6bxeBck/s1600/Screen+Shot+2014-06-16+at+4.41.12+PM.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
As you see, using&amp;nbsp;&lt;a href=&quot;http://doc.gridgain.org/latest/Off-Heap+Memory&quot;&gt;&lt;b&gt;GridGain OffHeap&lt;/b&gt;&lt;/a&gt;&amp;nbsp;memory renders a fairly smooth and predictable &lt;span style=&quot;color: #6aa84f;&quot;&gt;&lt;b&gt;green&lt;/b&gt;&lt;/span&gt; graph.&lt;br /&gt;
&lt;br /&gt;
Here are some of the GC printouts we received from G1 garbage collector:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;474.404: [GC pause (young) 13278M-&amp;gt;9596M(20480M), 0.7638660 secs]&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;481.850: [GC pause (young) (initial-mark) 13356M-&amp;gt;9674M(20480M), 0.7320680 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;482.583: [GC concurrent-root-region-scan-start]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;482.784: [GC concurrent-root-region-scan-end, 0.2017740]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;482.784: [GC concurrent-mark-start]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;489.055: [GC pause (young) 13442M-&amp;gt;9752M(20480M), 0.7715580 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;495.648: [GC concurrent-mark-end, 12.8631950 sec]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;495.675: [GC remark, 0.0303560 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;495.715: [GC cleanup 13232M-&amp;gt;13232M(20480M), 0.2076440 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;496.305: [GC pause (young) 13520M-&amp;gt;9830M(20480M), 0.7453250 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;505.025: [GC pause (mixed) 13598M-&amp;gt;9363M(20480M), 2.7538670 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;516.698: [GC pause (mixed) 13131M-&amp;gt;9241M(26624M), 2.9020230 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white;&quot;&gt;...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1160.396: [GC pause (young) 24923M-&amp;gt;15508M(51200M), 3.2503740 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1177.879: [GC pause (young) 25052M-&amp;gt;15637M(51200M), 3.4448020 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1202.492: [GC pause (young) 25189M-&amp;gt;15765M(51200M), 3.1212860 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1220.057: [GC pause (young) 25325M-&amp;gt;15891M(51200M), 4.0836240 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1245.212: [GC pause (young) 25459M-&amp;gt;16016M(51200M), 3.6344050 secs]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: #fce5cd;&quot;&gt;1262.500: [GC pause (young) 25584M-&amp;gt;16141M(51200M), 4.0109490 secs]
&lt;/span&gt;&lt;/blockquote&gt;
The JVM Parameters we ran G1 garbage collector with were:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;b&gt;&lt;i&gt;-Xms50g -Xmx50g -XX:+UseG1GC -XX:MaxGCPauseMillis=200&lt;/i&gt;&lt;/b&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;b&gt;G1 garbage collector&amp;nbsp;&lt;/b&gt;had average GC pauses between 2 and 4 seconds, with major mixed or concurrent sweeps happening for 6 to 12 seconds in the middle. From the graphs you can easily see that latencies and throughput (operations / second) for G1 garbage collector are all over the place, and often drop to the bottom, rendering the system completely unresponsive multiple times during the 20 minute test run.&lt;br /&gt;
&lt;br /&gt;
The benchmark was run on 2 Dell R610 blades, with 8 cores, and 96GB of RAM each. The benchmarking framework used, which helped with generation of pretty graphs, was the open source &lt;a href=&quot;https://github.com/gridgain/yardstick&quot;&gt;Yardstick framework&lt;/a&gt;,&amp;nbsp;available on GitHub.&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/18246881368024816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/18246881368024816' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/18246881368024816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/18246881368024816'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/06/jdk-g1-garbage-collector-pauses-for.html' title='G1 Garbage Collector Thrashes On Larger Heaps'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv3brMS44ncPgB-0-Xihfr42D_Y8UHZFQMdfNiRD9zTH9QsqDzVWmEh3c2g4zDPAYZ0OGE3Trd8fCBlAy_v38VjWa9RlFMv4HeZV2pk0wtgJT0r3fou2c8YSIEc8F5X6koAqUo6bxeBck/s72-c/Screen+Shot+2014-06-16+at+4.41.12+PM.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-5655999325833341204</id><published>2014-06-08T13:23:00.001-07:00</published><updated>2014-09-17T21:36:20.791-07:00</updated><title type='text'>Distributed Caching In 5 Minutes</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil6T1PAM4GvbQj4YMj_ytaid65r_fyw26c4Qnxl5Xagj5BEROr62tGJrxzfj8nSvJnVJ2wnNrzhp4D_T5gt1YIow-CHVN0tbzfjc9Td-FQOg6_wTsnqEXxXZJsk6dsfzShxue0CUuIzAI/s1600/datagrid.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil6T1PAM4GvbQj4YMj_ytaid65r_fyw26c4Qnxl5Xagj5BEROr62tGJrxzfj8nSvJnVJ2wnNrzhp4D_T5gt1YIow-CHVN0tbzfjc9Td-FQOg6_wTsnqEXxXZJsk6dsfzShxue0CUuIzAI/s1600/datagrid.png&quot; height=&quot;160&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;i&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/i&gt;
&lt;i&gt;&lt;b&gt;If you prefer a video demo with coding examples, skip to the screencast at the bottom of this blog.&lt;/b&gt;&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
Distributed In-Memory Caching generally allows you to replicate or partition your data in memory across your cluster. Memory provides a much faster access to the data, and by utilizing multiple cluster nodes the performance and scalability of the application increases significantly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Majority of the products that do distributed caching call themselves &lt;b&gt;In-Memory Data Grids&lt;/b&gt;. On top of simply providing hash-table-like access to your data, a data grid product should provide some combination of the following features:&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Clustering&lt;/li&gt;
&lt;li&gt;Distributed Messaging&lt;/li&gt;
&lt;li&gt;Distributed Event Notifications&lt;/li&gt;
&lt;li&gt;Distributed ACID Transactions&lt;/li&gt;
&lt;li&gt;Distributed Locks&lt;/li&gt;
&lt;li&gt;Distributed Data Queries, possibly using SQL&lt;/li&gt;
&lt;li&gt;Distributed Data Structures, like Maps, Queues, Sets, etc.&lt;/li&gt;
&lt;li&gt;Clustered Web Sessions&lt;/li&gt;
&lt;li&gt;OR-Mapping Integration, including Hibernate&lt;/li&gt;
&lt;li&gt;Persistent Database Support, like Oracle, MySQL, etc.&lt;/li&gt;
&lt;/ul&gt;
Of course the devil is in the details. For example, given the distributed nature of the cluster anything can fail at any point. So a good question to ask is how the failures are handled, especially what if the failures happen during commit. If during commit a cluster can be left in semi-committed state due to failures, it is definitely a problem.
&lt;br /&gt;
&lt;br /&gt;
Another example would be queries. Are the predicate queries being supported? Can you do SQL queries, particularly can the SQL Joins be handled? How are the aggregate functions handled, etc.
&lt;br /&gt;
&lt;br /&gt;
Simplicity of APIs is very important as well. &lt;i&gt;ConcurrentMap&lt;/i&gt; API has become a de facto standard of accessing data stored in distributed caches, but not all the products support it. Also, a good thing to check would be whether other standard data structures are supported. For example, &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt; supports Map, Set, BlockingQueue, AtomicLong, AtomicSequence, CountDownLatch, all in distributed fashion.
&lt;br /&gt;
&lt;br /&gt;
And the last, but not least, always check for performance. Load up the cluster and see what the throughput and latencies are, what is the network load on each server, etc. A good benchmarking tool for testing distributed systems is open source &lt;a href=&quot;https://github.com/gridgain/yardstick&quot;&gt;Yardstick Framework&lt;/a&gt;, available on GitHub.
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Coding Example&lt;/h2&gt;
Here is a &lt;a href=&quot;http://www.gridgain.org/platform/data-grid/&quot;&gt;GridGain Data Grid&lt;/a&gt; coding example of some basic operations on distributed caches:
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;private static void atomicMapOperations() throws GridException {
    GridCache&amp;lt;Integer, String&amp;gt; cache = GridGain.grid().cache(CACHE_NAME);

    // Put and return previous value.
    String v = cache.put(1, &quot;1&quot;);
    assert v == null;

    // Put and do not return previous value 
    // (all methods ending with &#39;x&#39; return boolean).
    // Performs better when previous value is not needed.
    cache.putx(2, &quot;2&quot;);

    // Put asynchronously (every cache operation has async counterpart).
    GridFuture&amp;lt;String&amp;gt; fut = cache.putAsync(3, &quot;3&quot;);

    // Put-if-absent.
    boolean b1 = cache.putxIfAbsent(4, &quot;4&quot;);
    boolean b2 = cache.putxIfAbsent(4, &quot;44&quot;);


    // Put-with-predicate, will succeed if predicate evaluates to true.
    cache.putx(5, &quot;5&quot;);
    cache.putx(5, &quot;55&quot;, new GridPredicate&amp;lt;GridCacheEntry&amp;lt;Integer, String&amp;gt;&amp;gt;() {
        @Override public boolean apply(GridCacheEntry&amp;lt;Integer, String&amp;gt; e) {
            return &quot;5&quot;.equals(e.peek()); // Update only if previous value is &quot;5&quot;.
        }
    });

    // Transform - assign new value based on previous value.
    cache.putx(6, &quot;6&quot;);
    cache.transform(6, new GridClosure&amp;lt;String, String&amp;gt;() {
        @Override public String apply(String v) {
            return v + &quot;6&quot;; // Set new value based on previous value.
        }
    });

    // Replace.
    cache.putx(7, &quot;7&quot;);
    b1 = cache.replace(7, &quot;7&quot;, &quot;77&quot;);
    b2 = cache.replace(7, &quot;7&quot;, &quot;777&quot;);
}
&lt;/pre&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Screencast&lt;/h2&gt;
Here is a brief screencast showing how to get started with basic operations on your cache in under 5 minutes:&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;421&quot; mozallowfullscreen=&quot;&quot; src=&quot;//player.vimeo.com/video/92571537&quot; webkitallowfullscreen=&quot;&quot; width=&quot;750&quot;&gt;&lt;/iframe&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/5655999325833341204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/5655999325833341204' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5655999325833341204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5655999325833341204'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/06/distributed-caching-in-5-minutes.html' title='Distributed Caching In 5 Minutes'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEil6T1PAM4GvbQj4YMj_ytaid65r_fyw26c4Qnxl5Xagj5BEROr62tGJrxzfj8nSvJnVJ2wnNrzhp4D_T5gt1YIow-CHVN0tbzfjc9Td-FQOg6_wTsnqEXxXZJsk6dsfzShxue0CUuIzAI/s72-c/datagrid.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-1635655671959151322</id><published>2014-05-14T12:08:00.000-07:00</published><updated>2014-05-20T13:46:07.433-07:00</updated><title type='text'>Getting Started With Clustering</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVsBgd82uNVsnk_xT-aa-AK7M7AAQp3pgw48SHsa82sY0gumh_1kvV6yf1aaU-W74gbL8N_pogAj_N47YzS2ythvCY0CRAagJAbjlxkIroegLRo41rvU2hG6dxPy5qviPf_odwfsWIGLg/s1600/network-workgroup.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVsBgd82uNVsnk_xT-aa-AK7M7AAQp3pgw48SHsa82sY0gumh_1kvV6yf1aaU-W74gbL8N_pogAj_N47YzS2ythvCY0CRAagJAbjlxkIroegLRo41rvU2hG6dxPy5qviPf_odwfsWIGLg/s320/network-workgroup.png&quot; height=&quot;120&quot; width=&quot;120&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;
&lt;i&gt;If you don&#39;t like to read and prefer video demos, you can skip directly to the &lt;b&gt;Screencast&lt;/b&gt; at the bottom of this post.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
What do Clustering frameworks really do? More often than not clustering frameworks will provide capability to auto-discover servers on the network, share resources, and schedule tasks. Some will also add distributed messaging and distributed event notification capabilities.&lt;br /&gt;
&lt;br /&gt;
While there are some well known clustering frameworks, like Zookeeper or Mesos, they usually provide very rudimentary clustering capabilities. However, often on top of basic clustering, you also need to perform MapReduce computations, distribute closures, or distribute data. For cases like these, Compute Grids (a.k.a. High Performance Computing Grids) or Data Grids become very useful.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;For those not familiar with term &quot;Data Grid&quot;, it is simply a Distributed Cache with more advanced features, like distributed data querying, transactions, etc...&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;
Compute Grids or Data Grids often provide very advanced clustering APIs which are very simple to use. Here I will show some basic examples on top of &lt;a href=&quot;http://www.gridgain.org/platform/data-grid/&quot;&gt;GridGain In-Memory Data Grid&lt;/a&gt;, which is Open Source and licensed under Apache license.&lt;br /&gt;
&lt;br /&gt;
GridGain clustering supports auto-node discovery, but at the same time adds capabilities to create any virtual sub-groups of grid nodes within cluster and exchange messages between them or get remote event notifications. While &lt;a href=&quot;http://gridgain.blogspot.com/2014/03/5-easy-clustering-tips-with-gridgain.html&quot;&gt;I have blogged about it&lt;/a&gt; in more detail before, here is a pretty simple example which demonstrates auto-discovery and distributed computations on the cluster:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;try (Grid grid = GridGain.start()) {
   // Create sample runnable.
   Runnable r = new GridRunnable() {
      @Override public void run() {
         System.out.println(&quot;Hello World&quot;);
      }
   }
 
   // Broadcast to all grid nodes.
   grid.compute().broadcast(r).get();
 
   // Broadcast to remote nodes only.
   grid.forRemotes().compute().broadcast(r).get();
 
   // Unicast to some remote node picked by load balancer.
   grid.forRemotes().compute().run(r).get();
 
   // Unicast to some node with CPU load less than 50%.
   grid.forPredicate(new GridPredicate&amp;lt;GridNode&amp;gt;() {
      @Override public boolean apply(GridNode node) {
         return node.metrics().getCurrentCpuLoad() &amp;lt; 0.5;
      }
   }).compute().run(r).get();
}
&lt;/pre&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
Screencast&lt;/h2&gt;
Here is a brief screencast showing how to get started with running computations on your cluster in under 5 minutes:&lt;br /&gt;
&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;421&quot; mozallowfullscreen=&quot;&quot; src=&quot;//player.vimeo.com/video/92571432&quot; webkitallowfullscreen=&quot;&quot; width=&quot;750&quot;&gt;&lt;/iframe&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/1635655671959151322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/1635655671959151322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1635655671959151322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1635655671959151322'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/05/getting-started-with-clustering.html' title='Getting Started With Clustering'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVsBgd82uNVsnk_xT-aa-AK7M7AAQp3pgw48SHsa82sY0gumh_1kvV6yf1aaU-W74gbL8N_pogAj_N47YzS2ythvCY0CRAagJAbjlxkIroegLRo41rvU2hG6dxPy5qviPf_odwfsWIGLg/s72-c/network-workgroup.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-5276819809324876032</id><published>2014-05-01T12:48:00.003-07:00</published><updated>2014-05-14T12:23:21.034-07:00</updated><title type='text'>GridGain 6.1.0 Is Released with Support for JDK8 and Geospatial Indexes</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; height=&quot;46&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I am pleased to announce that &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain 6.1.0&lt;/a&gt; has been released today. This is the first main upgrade since GridGain 6.0.0 was released in February and contains some cool new functionality and performance improvements:&lt;br /&gt;
&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Support for JDK8&lt;/h3&gt;
With GridGain 6.1.0 you can execute JDK8 closures and functions in distributed fashion on the grid:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;try (Grid grid = GridGain.start()) {
  grid.compute().broadcast((GridRunnable)() -&amp;gt; 
      System.out.println(&quot;Hello World&quot;)).get();
}
&lt;/pre&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Geospatial Indexes&lt;/h3&gt;
GridGain allows to easily query in-memory data in SQL using in-memory indexes. Now you can extend SQL to geospatial queries. For example, query below will find all points on the map within a certain square region:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;Polygon square = factory.createPolygon(new Coordinate[] {
   new Coordinate(0, 0),
   new Coordinate(0, 100),
   new Coordinate(100, 100),
   new Coordinate(100, 0),
   new Coordinate(0, 0)
});

cache.queries().
    createSqlQuery(MapPoint.class, &quot;select * from MapPoint where location &amp;amp;&amp;amp; ?&quot;).
         queryArguments(square).
             execute().get();
&lt;/pre&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Near Cache in Atomic Mode&lt;/h3&gt;
Prior to 6.1.0 GridGain supported near cache only in transactional mode. Starting with 6.1.0 near cache support was added to atomic mode as well.&lt;br /&gt;
&lt;br /&gt;
Near cache allows for client-side caching (vs traditional server side caching) and renders significant performance improvements in some cases.&lt;br /&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Fair Affinity Functions&lt;/h3&gt;
&lt;div&gt;
Many know that Consistent Hashing provides a consistent distribution of data within a cluster that is resilient to server failures, but not many know that consistent hashing is not very fair. The discrepancies in distribution can be up to 20% which means that some servers will end up with 20% more data than others. This may create uneven load distribution when running cluster-enabled computations or queries.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
GridGain 6.1 added two more affinity functions in addition to consistent hashing: &lt;b&gt;Rendezvous&lt;/b&gt; and &lt;b&gt;Fair&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://www.gridgain.org/api/javadoc/org/gridgain/grid/cache/affinity/rendezvous/GridCacheRendezvousAffinityFunction.html&quot;&gt;Rendezvous affinity function&lt;/a&gt; works faster than consistent hashing and for smaller topologies (under 10 servers) provides a pretty fair distribution. One of the nice features here is that cache key affinity survives full cluster restarts. This means that you can back up data to disk and then reload it on restart knowing that all keys are still mapped to the same node.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://www.gridgain.org/api/javadoc/org/gridgain/grid/cache/affinity/fair/GridCachePartitionFairAffinity.html&quot;&gt;Fair affinity function&lt;/a&gt; provides absolutely fair cache key distribution with all grid nodes holding absolutely equal amount of keys at all times. However, fair affinity function may change key-to-node assignment upon full cluster restarts.&lt;/div&gt;
&lt;h3 style=&quot;text-align: left;&quot;&gt;
Other Enhancements&lt;/h3&gt;
&lt;div&gt;
Other fixes and enhancements involve improvements to &lt;i&gt;multicast protocol for discovery&lt;/i&gt; and significant performance improvements for &lt;i&gt;distributed cache queues&lt;/i&gt;.&lt;/div&gt;
&lt;br /&gt;
You can download &lt;a href=&quot;http://www.gridgain.org/download/&quot;&gt;GridGain 6.1 here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/5276819809324876032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/5276819809324876032' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5276819809324876032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5276819809324876032'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/05/gridgain-610-is-released-with-support.html' title='GridGain 6.1.0 Is Released with Support for JDK8 and Geospatial Indexes'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-2897625552444625434</id><published>2014-04-16T20:07:00.001-07:00</published><updated>2014-04-17T15:07:37.680-07:00</updated><title type='text'>Five Easy Tips for Benchmarking In-Memory Data Grids</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm_drJb1DWsJbImfMFHJcTaXpgrTwQR3OeF4hdOT41Kyvl50bQoQdoGblAtoHdgddCowEiABdHlg7YOWp9UjJHNlOrVSXUGIyu_QzI6ypa9CEb6S0lHO9Qaxrh3kztTEypVJNBNcZiEhw/s1600/benchmarking-weight.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm_drJb1DWsJbImfMFHJcTaXpgrTwQR3OeF4hdOT41Kyvl50bQoQdoGblAtoHdgddCowEiABdHlg7YOWp9UjJHNlOrVSXUGIyu_QzI6ypa9CEb6S0lHO9Qaxrh3kztTEypVJNBNcZiEhw/s1600/benchmarking-weight.png&quot; height=&quot;170&quot; width=&quot;170&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Having spoken with many customers evaluating &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;our product&lt;/a&gt; I am noticing that a majority of folks evaluating in-memory computing, whether it be data grid, map reduce, or streaming, do not know how to appropriately perform benchmarking. The right approach to distributed in-memory benchmarking is very different than benchmarking disk-based products, like databases, and generally requires experience and understanding of the delicate details of how network and garbage collections behave under load. With that in mind, &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt; will soon be releasing a benchmarking framework to help easily overcome all these challenges, but until then here is a list of things to watch out for.&lt;br /&gt;
&lt;br /&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
1. Did you allocate enough memory?&lt;/h2&gt;
&lt;div&gt;
If you have not allocated enough memory, the performance of your application may significantly degrade. From a user&#39;s stand point it may not really be noticeable until your application gradually becomes slower and slower, which is the first sign that you may be running out of memory.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Also keep in mind that if you allocate more than 10GB of memory per JVM, your application may start suffering from prolonged garbage collections. To mitigate that, check if the product you are evaluating has support for &lt;a href=&quot;http://atlassian.gridgain.com/wiki/display/GG60/Performance+Tuning#PerformanceTuning-TuneOff-HeapMemory&quot;&gt;off-heap memory&lt;/a&gt; which cheats Java garbage collection by utilizing off-heap memory space.&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;b&gt;&lt;i&gt;When running benchmarks, you should constantly monitor memory consumption. You can do it with any light weight profiler, like &lt;a href=&quot;http://visualvm.java.net/&quot;&gt;VisualVm&lt;/a&gt; which is shipped by default with JDK.&lt;/i&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
2. Are your tests multi-threaded?&lt;/h2&gt;
&lt;div&gt;
Benchmarking should not be performed from a single thread or a small number of threads, as generally such tests will not load the system. This is especially true for synchronous API calls, as the next API call has to wait for the previous one to complete. It is generally a good practice to run benchmarks from about 60 to 100 threads (on boxes with more than 16 cores, the number of threads can be higher).&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;background-color: #fcfcfc; color: #333333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px;&quot;&gt;&lt;b&gt;&lt;i&gt;When running benchmarks, you should monitor the CPU load on your system and add more threads if system is below 90% load.&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
3. Do you perform initial &lt;i&gt;warm-up&lt;/i&gt;?&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
JVM HotSpot compiler will usually inline and precompile portions of the code that get executed the most. However, usually in load tests, this warm-up process takes about 20 or 30 seconds. It is generally a good practice to allow benchmarks to warm up for about 30 seconds before you start measuring performance.&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;b&gt;&lt;i&gt;When running benchmarks, you should do periodic print outs of your throughput (number of operations per second). The warm-up is usually finished when the throughput numbers stabilize.&lt;/i&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
4. Did you tune your garbage collection?&lt;/h2&gt;
&lt;div&gt;
If you are seeing spikes in your throughput, it may be due to JVM Garbage Collection (GC). In this case it is best to use concurrent sweep GC which has proven to provide fairly smooth throughput without any large spikes or long pauses.&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;b&gt;&lt;i&gt;Here is a good link, which describes several GC tuning parameters: &lt;a href=&quot;http://atlassian.gridgain.com/wiki/display/GG60/Performance+Tuning#PerformanceTuning-TuneGarbageCollection&quot;&gt;Tune Garbage Collection&lt;/a&gt;.&lt;/i&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 style=&quot;text-align: left;&quot;&gt;
5. Do you use bulk operations?&lt;/h2&gt;
&lt;div&gt;
Often many developers will sequentially execute multiple single cache &lt;i style=&quot;font-weight: bold;&quot;&gt;&#39;put(key, value)&#39;&lt;/i&gt;&amp;nbsp;operations and then notice that performance is not ideal. The main reason is that whenever network I/O is involved, you should always strive to send as few messages as possible. To achieve this, a majority of data grid or caching products provide support for bulk operations, such as&amp;nbsp;&lt;i style=&quot;font-weight: bold;&quot;&gt;&#39;putAll(...)&#39;&lt;/i&gt;. Bulk updates can often improve performance by 100x magnitude.&amp;nbsp;&lt;/div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;&lt;b&gt;When using bulk updates, make sure to experiment with batch sizes - making them too big or too small can hurt performance. Also see if the product you are evaluating has already &lt;a href=&quot;http://atlassian.gridgain.com/wiki/display/GG60/Performance+Tuning#PerformanceTuning-UseDataLoader&quot;&gt;automated bulk-updates for you&lt;/a&gt;.&lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/2897625552444625434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/2897625552444625434' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/2897625552444625434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/2897625552444625434'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/04/five-easy-tips-for-benchmarking-in.html' title='Five Easy Tips for Benchmarking In-Memory Data Grids'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm_drJb1DWsJbImfMFHJcTaXpgrTwQR3OeF4hdOT41Kyvl50bQoQdoGblAtoHdgddCowEiABdHlg7YOWp9UjJHNlOrVSXUGIyu_QzI6ypa9CEb6S0lHO9Qaxrh3kztTEypVJNBNcZiEhw/s72-c/benchmarking-weight.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-6284004149628011618</id><published>2014-03-25T12:47:00.001-07:00</published><updated>2014-03-26T10:09:16.363-07:00</updated><title type='text'>Five Easy Clustering Tips With GridGain</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxNFULv7MYKch5rRBVKs8vfW_8vrJe8NpAbNZJDKPmwZthAZALXCiCMe8Ef73eGpytqPzy0AhzeC9eGlr0p2bNSq6h4GI3yLGC0GjYok_FUYnx8_lcIsSns2U1R_Czr_C4aSuiSCBmrF8/s1600/1395796102_cluster.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxNFULv7MYKch5rRBVKs8vfW_8vrJe8NpAbNZJDKPmwZthAZALXCiCMe8Ef73eGpytqPzy0AhzeC9eGlr0p2bNSq6h4GI3yLGC0GjYok_FUYnx8_lcIsSns2U1R_Czr_C4aSuiSCBmrF8/s1600/1395796102_cluster.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Before diving deeper into what it means to easily cluster an application, let&#39;s start from defining what &amp;nbsp;a cluster really is. Wikipedia has a pretty good explanation of clustering &lt;a href=&quot;http://en.wikipedia.org/wiki/Computer_cluster&quot;&gt;here&lt;/a&gt;, which is a high level definition that covers fault tolerance, load balancing, scheduling, etc. However, the real magic behind clustering is in making these complex distributed operations seem easy.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From development standpoint ability to cluster an application in most cases can be reduced to being able to easily perform the following functions:&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Get list of all currently alive cluster nodes&lt;/li&gt;
&lt;li&gt;Ability to create sub-groups of nodes within cluster at will&lt;/li&gt;
&lt;li&gt;Exchange messages between any nodes within cluster&lt;/li&gt;
&lt;li&gt;Listen to events from any node within a specified group&lt;/li&gt;
&lt;li&gt;Easily compute and share data on any of the cluster nodes&lt;/li&gt;
&lt;/ol&gt;
Here are the coding examples on how to achieve the above in GridGain. I hope the code is simple enough to understand, but would be interesting to get some feedback on it. Feel free to comment.
&lt;p/&gt;
Let&#39;s start from getting list of all cluster nodes:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;Collection&amp;lt;GridNode&amp;gt; nodes = GridGain.grid().nodes();
&lt;/pre&gt;&lt;br/&gt;
Now, let&#39;s create different sub-groups of nodes within cluster:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;// Remote nodes (all nodes, excluding local)
GridProjection rmtNodes = grid.forRemotes();

// Random remote node.
GridProjection rmtRandomNode = rmtNodes.forRandom();

// Current CPU load of remote random node.
double cpu = rmtRandomNode.node().metrics().getCurrentCpuLoad();

// All nodes on the same physical host as remote random node.
GridProjection hostNodes = grid.forHost(rmtRandomNode.node());

// All nodes marked by user as worker nodes.
GridProjeciton workers = grid.forAttribute(&quot;worker&quot;, &quot;true&quot;);
&lt;/pre&gt;
&lt;br /&gt;
Here is an example of message exchange between cluster nodes in GridGain cluster:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;// User-defined message topics.
private enum TOPIC { MYTOPIC }
 
// Get message instance to provide messaging functionality 
// over a projection of remote nodes.
GridMessaging msg = grid.forRemotes().message();
 
// Register message listeners on all remote grid nodes.
msg.remoteListen(MYTOPIC, new GridBiPredicate&amp;lt;UUID, String&amp;gt;() {
    @Override public boolean apply(UUID sndrNodeId, String msg) {
        System.out.println(&quot;Received message: &quot; + msg&quot;);
         
        return true; // Return true to continue listening.
    }
}).get();
 
msg.send(MYTOPIC, &quot;Hello World&quot;);
&lt;/pre&gt;
&lt;br /&gt;
This example shows how to subscribe an event listener on all grid nodes:
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;// This optional local callback is called for each event notification
// that passed remote predicate listener.
GridBiPredicate&amp;lt;UUID, GridCacheEvent&amp;gt; locLsnr = new GridBiPredicate&amp;lt;UUID, GridCacheEvent&amp;gt;() {
    @Override public boolean apply(UUID uuid, GridCacheEvent evt) {
        System.out.println(&quot;Received event: &quot; + evt.name());

        return true; // Continue listening.
    }
};

// Remote listener which only accepts events for keys that are
// greater or equal than 10 and if event node is primary caching node for this key.
GridPredicate&amp;lt;GridCacheEvent&amp;gt; rmtLsnr = new GridPredicate&amp;lt;GridCacheEvent&amp;gt;() {
    @Override public boolean apply(GridCacheEvent evt) {
        System.out.println(&quot;Cache event: &quot; + evt.name());

        int key = evt.key(); // Cache key.

        return key &amp;gt;= 10 &amp;amp;&amp;amp; cache.affinity().isPrimary(grid.localNode(), key);
    }
};

// Subscribe to specified cache events on all nodes that have &quot;myCache&quot; running.
grid.forCache(&quot;myCache&quot;).events().remoteListen(locLsnr, rmtLsnr, EVT_CACHE_OBJECT_PUT).get();
&lt;/pre&gt;
&lt;br /&gt;
And finally, an example that distributes computations to the nodes where the data is cached:&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;for (int i = 0; i &amp;lt; KEY_CNT; i++) {
    final int key = i;

    // This runnable will execute on the remote node where
    // the data with the given key is cached. 
    GridRunnable run = new GridRunnable() {
        @Override public void run() {
            System.out.println(&quot;Computing [key= &quot; + key + &quot;, value=&quot; + cache.peek(key) + &#39;]&#39;);
        }
    };

    grid.compute().affinityRun(&quot;myCache&quot;, key, run).get();
}
&lt;/pre&gt;
&lt;br /&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/6284004149628011618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/6284004149628011618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/6284004149628011618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/6284004149628011618'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/03/5-easy-clustering-tips-with-gridgain.html' title='Five Easy Clustering Tips With GridGain'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxNFULv7MYKch5rRBVKs8vfW_8vrJe8NpAbNZJDKPmwZthAZALXCiCMe8Ef73eGpytqPzy0AhzeC9eGlr0p2bNSq6h4GI3yLGC0GjYok_FUYnx8_lcIsSns2U1R_Czr_C4aSuiSCBmrF8/s72-c/1395796102_cluster.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-5870990189678131231</id><published>2014-03-11T12:19:00.003-07:00</published><updated>2014-03-11T12:53:33.164-07:00</updated><title type='text'>Grid-Enable Your Local Operations Across Cluster</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAyU8pGYttH0cDwDbxPP5_nS7KFs52EvpzH7SNzEoKBV97PE4aRpb9XB5ky1QpyjxhVKpnvBjGQSCCV6b-eSmS9E0helrMTDya1JzscdzHwlqSlSbVWvG-A-nIzIyJXr7X48MgY54nTac/s1600/1394583539_Network-Recycle.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAyU8pGYttH0cDwDbxPP5_nS7KFs52EvpzH7SNzEoKBV97PE4aRpb9XB5ky1QpyjxhVKpnvBjGQSCCV6b-eSmS9E0helrMTDya1JzscdzHwlqSlSbVWvG-A-nIzIyJXr7X48MgY54nTac/s1600/1394583539_Network-Recycle.png&quot;  width=&quot;125px&quot;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
As you may already know, &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt; went open source last week. Going open source was a lot more involved than simply opening up our code. We put significant amount of thought into simplifying our APIs and making our development process as community friendly as possible.&lt;br /&gt;
&lt;br /&gt;
As an example, take a look at how in GridGain you can take any local operation and distribute it across the cluster. Let&#39;s take&amp;nbsp;&lt;i&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;a href=&quot;http://www.gridgain.org/api/javadoc/org/gridgain/grid/cache/GridCache.html&quot;&gt;GridCache&lt;/a&gt;&lt;/span&gt;&lt;/i&gt;&amp;nbsp;interface. In addition to distributed methods, like &lt;i&gt;get(...)&lt;/i&gt;&amp;nbsp;or &lt;i&gt;put(...), m&lt;/i&gt;any APIs on this interface are local. For example, method &lt;i&gt;size()&lt;/i&gt;&amp;nbsp;will return number of entries locally cached, or method &lt;i&gt;containsValue(...)&lt;/i&gt;&amp;nbsp;will check if value is cached on local node. These APIs are made local on purpose - we anticipated that for certain methods providing local information would be safer and more useful. However, what if you need to see if value is contained across the whole cache, not just local node cache.&lt;br /&gt;
&lt;br /&gt;
In GridGain, to make any operation distributed you need to execute it across multiple nodes using &lt;i&gt;&lt;span style=&quot;font-family: Arial, Helvetica, sans-serif;&quot;&gt;&lt;a href=&quot;http://www.gridgain.org/api/javadoc/org/gridgain/grid/compute/GridCompute.html&quot;&gt;GridCompute&lt;/a&gt;&lt;/span&gt;&amp;nbsp;&lt;/i&gt;functionality. Here is how the global contains method would look like:
&lt;br /&gt;
&lt;pre class=&quot;brush: java&quot;&gt;public boolean contains(final V val) {
    // Not all nodes in the grid may participate in caching data.
    // We want to make sure that we send our computation only to caching nodes.
    GridProjection cacheNodes = GridGain.grid().forCache(&quot;myCache&quot;);

    Collection&amp;lt;Boolean&amp;gt; results = cacheNodes.compute().broadcast(
        new GridCallable&amp;lt;Boolean&amp;gt;() {
            @Override public Boolean call() {
                return GridGain.grid().cache(&quot;myCache&quot;).containsValue(val);
            }
        }
    ).get();
    
    return results.contains(true); 
}
&lt;/pre&gt;
You can do the same for any other operation as well. For example, if you need to find out total cache size across all cache nodes, you would simply broadcast a computation that returned &lt;i&gt;cache.size()&lt;/i&gt; from all nodes, and them add them up to get a total value.
&lt;script type=&quot;text/javascript&quot;&gt;
 SyntaxHighlighter.highlight();
&lt;/script&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/5870990189678131231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/5870990189678131231' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5870990189678131231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/5870990189678131231'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/03/grid-enable-your-local-operations.html' title='Grid-Enable Your Local Operations Across Cluster'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAyU8pGYttH0cDwDbxPP5_nS7KFs52EvpzH7SNzEoKBV97PE4aRpb9XB5ky1QpyjxhVKpnvBjGQSCCV6b-eSmS9E0helrMTDya1JzscdzHwlqSlSbVWvG-A-nIzIyJXr7X48MgY54nTac/s72-c/1394583539_Network-Recycle.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1680085285488970412.post-1660247806516809141</id><published>2014-03-04T09:19:00.000-08:00</published><updated>2014-03-18T10:48:52.632-07:00</updated><title type='text'>GridGain Goes Open Source Under Apache v2.0</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;img border=&quot;0&quot; src=&quot;http://www.gridgain.org/images/logo/logo12.png&quot; height=&quot;46&quot; width=&quot;200&quot; /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvzN3BmgsnmyuhD47q8HRvxyzSvSCnR7iHTi5pCdkJMTQj8MOlYVTe1WY460VGOx6iHtDniKnm2WiZ16ozojIxkIigKIQvw9g07KEqfJOF8PRqETSLbXZ9rnflZ-InbjRWIEdA16gL3-w/s1600/Octocat.png&quot; imageanchor=&quot;1&quot; style=&quot;display: inline !important; margin-left: 1em; margin-right: 1em; text-align: left;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvzN3BmgsnmyuhD47q8HRvxyzSvSCnR7iHTi5pCdkJMTQj8MOlYVTe1WY460VGOx6iHtDniKnm2WiZ16ozojIxkIigKIQvw9g07KEqfJOF8PRqETSLbXZ9rnflZ-InbjRWIEdA16gL3-w/s1600/Octocat.png&quot; width=&quot;120&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Yesterday &lt;a href=&quot;http://www.gridgain.org/&quot;&gt;GridGain&lt;/a&gt; released it&#39;s 6.0 version under the Apache 2.0 open source license. Our CTO, Nikita Ivanov, wrote about the new GridGain features and licensing in &lt;a href=&quot;http://blog.gridgainsystems.com/gridgain-6-0-open-sourced-under-apache-2-0/&quot;&gt;his blog here&lt;/a&gt;, so I will not repeat them. Instead, I will briefly describe our vision behind In-Memory Computing and why we made the move to open source.&lt;br /&gt;
&lt;br /&gt;
Why is In-Memory Computing important? The simple answer is that there is no other way to process today’s enormous data volumes. In order to get answers from 100’s of terabytes of data in milliseconds you absolutely must have an &lt;i&gt;In-Memory&lt;/i&gt; solution in your architecture. This is being validated by not just GridGain. Large vendors, such as&amp;nbsp;Oracle (&lt;a href=&quot;http://www.oracle.com/us/corporate/press/2020717&quot;&gt;in-memory database&lt;/a&gt; and&amp;nbsp;&lt;a href=&quot;http://www.oracle.com/us/corporate/press/1855412&quot;&gt;in-memory Exadata&lt;/a&gt;), IBM (&lt;a href=&quot;http://www-01.ibm.com/software/data/blu/&quot;&gt;BLU analytics&lt;/a&gt;), SAP (&lt;a href=&quot;http://www.saphana.com/&quot;&gt;Hana&lt;/a&gt;), are also moving in the same direction.&lt;br /&gt;
&lt;br /&gt;
So, with all those solutions out there, what makes GridGain different? In a nutshell, we provide a unified In-Memory Computing Platform aimed to solve a wide range of use cases. Our platform is composed of multiple natively integrated products, including &lt;b&gt;High Performance Computing&lt;/b&gt; (HPC), the industry’s fastest &lt;b&gt;In-Memory Data Grid&lt;/b&gt; (IMDG), CEP-based &lt;b&gt;Streaming&lt;/b&gt;, and a plug-and-play &lt;b&gt;Apache Hadoop Accelerator&lt;/b&gt;. With our new open source strategy, all of these products are now freely available for download, either a la carte or together as part of a larger platform edition.&lt;br /&gt;
&lt;br /&gt;
With &lt;a href=&quot;http://www.gridgain.org/features/&quot;&gt;GridGain In-Memory Computing Platform&lt;/a&gt; you can process in parallel 100s of thousands of computational jobs per second, store terabytes of data in memory for fast transactional access and SQL querying, index into never-ending streams of incoming data, or give your Hadoop installations up to 100x boost.&lt;br /&gt;
&lt;br /&gt;
We&#39;ve been around the block as well. The product has been vetted by many customers, including large production deployments exceeding thousands of nodes. Open sourcing our platform just seemed like a natural way to share our technology with community and continue growing as a part of a larger in-memory eco-system. Unlike other commercial open source offerings, we went with a very liberal Apache license and with a feature set more than adequate to give GridGain open source users the ability to deploy in production. The product even includes &lt;b&gt;Management and Monitoring&lt;/b&gt;, which most vendors rarely offer free of change.&lt;br /&gt;
&lt;br /&gt;
In the upcoming days, I will be giving coding examples, demonstrating the ease of use of our APIs, and sharing various use cases. In the mean time, please feel free to&amp;nbsp;&lt;a href=&quot;http://www.gridgain.org/download/&quot;&gt;download&lt;/a&gt; GridGain and give it a try. You can start by taking a look at our &lt;a href=&quot;http://atlassian.gridgain.com/wiki/display/GG60/Getting+Started&quot;&gt;Getting Started&lt;/a&gt; guide and trying a few examples.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;a href=&quot;http://www.gridgain.org&quot;&gt;GridGain - Fastest In-Memory Computing&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gridgain.blogspot.com/feeds/1660247806516809141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1680085285488970412/1660247806516809141' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1660247806516809141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1680085285488970412/posts/default/1660247806516809141'/><link rel='alternate' type='text/html' href='http://gridgain.blogspot.com/2014/03/gridgain-goes-open-source-under-apache.html' title='GridGain Goes Open Source Under Apache v2.0'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/01141522474656442760</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvzN3BmgsnmyuhD47q8HRvxyzSvSCnR7iHTi5pCdkJMTQj8MOlYVTe1WY460VGOx6iHtDniKnm2WiZ16ozojIxkIigKIQvw9g07KEqfJOF8PRqETSLbXZ9rnflZ-InbjRWIEdA16gL3-w/s72-c/Octocat.png" height="72" width="72"/><thr:total>6</thr:total></entry></feed>