Skip to main content

Quick start with In memory Data Grid, Apache Ignite

UP1: For complete quick start guide, see also the sample chapter of the book "High performance in-memory computing with Apache Ignite" here. Even you can find the sample examples from the GitHub repository.

IMDG or In memory data grid is not an in-memory relational database, an NoSQL database or a relational database. It is a different breed of software datastore. The data model is distributed across many servers in a single location or across multiple locations. This distribution is known as a data fabric. This distributed model is known as a ‘shared nothing’ architecture. IMDG has following characteristics:

  1. All servers can be active in each site.
  2. All data is stored in the RAM of the servers.
  3. Servers can be added or removed non-disruptively, to increase the amount of RAM available.
  4. The data model is non-relational and is object-based. 
  5. Distributed applications written on the platform independent language.
  6. The data fabric is resilient, allowing non-disruptive automated detection and recovery of a single server or multiple servers.

Most of all time we use IMDG for web session management of Application server and as a distributed cache or L2 cache. Hazelcast community addition was our all time favourite IMDG tools, but from the last few releases of hazelcast community edition, it's performance not happy us at all. As a quick alternative of HazelCast, we decided to make a try with Apache ignite. This post is dedicated to apache ignite and be used for quick startup guide. For installation I will use 2 virtual machines of Redhat operating system with following configurations:

CPU: 2
RAM: 4
HDD: 25 GB
OS: Redhat Santiago

From a lot of features of Apache ignite6 we will only examines following features:
  1. Prepare operating system
  2. Using Spring for using DataGrid
  3. MyBatis Cache configuration
  4. Spring Caching

Instaling apache ignite:
Pre require-ties:
1) Java 1.7 and above
2) open ports: 47500..47509, 8080 (for Rest interface), 47400, 47100:47101, 48100:48101, 31100:31101

After installing JDK in operating system, we have to open ports that mentioned above. By following commands we can manipulates iptables.
vi /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 47500:47509 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 47400 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 47100 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 47101 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 48100 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 48101 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 31100 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 31101 -j ACCEPT

/etc/init.d/iptables restart
Installation of Apache ignite in few machines:
1) Lets download the ignite 1.5.0final version from the following links.
2) Unzip the archive any where in os such as /opt/apache-ignite
3) Add environmental path IGNITE_HOME to the home directory of the apache ignite.
4) copy the folder $IGNITE_HOME/libs/optional/ignite-rest-http to /home/user/apache-ignite-fabric-1.5.0/libs, it will enable the apache ignite through rest interface.
5) Run the command ignite.sh examples/config/example-cache.xml to start the apache ignite.
If every thing goes fine you should see the following log in your console
[12:32:01] Ignite node started OK (id=ceb614ca)
[12:32:01] Topology snapshot [ver=4, servers=2, clients=0, CPUs=3, heap=2.0GB]
and ignite will also available through http by URL http://host:port/ignite?cmd=version
Using Spring for using DataGrid:
First of all we have to build maven project to write down bunch of code to examine features of apache Ignite.
1) Add the following dependencies to the pom.xml
<dependency>
            <groupId>org.apache.ignite</groupId>
            <artifactId>ignite-core</artifactId>
            <version>${ignite.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ignite</groupId>
            <artifactId>ignite-spring</artifactId>
            <version>${ignite.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ignite</groupId>
            <artifactId>ignite-indexing</artifactId>
            <version>${ignite.version}</version>
        </dependency>
        <!-- myBatis -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ignite</artifactId>
            <version>1.0.0-beta1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.1</version>
        </dependency>
        <!-- Oracle 12-->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>
Please, note that Oracle JDBC client jar should be in local maven repositories. In my case i use Oracle 11.2.02 client.
2) Add spring-context.xml file in resources directory with following contexts
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/cache
        http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd ">
    <!-- Enable annotation-driven caching. -->
    <cache:annotation-driven/>

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- beans -->

    <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="gridName" value="TestGrid"/>
        <!-- Enable client mode. -->
        <property name="clientMode" value="true"/>

        <property name="cacheConfiguration">
            <list>
                <!-- Partitioned cache example configuration (Atomic mode). -->
                <bean class="org.apache.ignite.configuration.CacheConfiguration">
                    <!--<property name="atomicityMode" value="ATOMIC"/>-->
                    <!-- Set cache mode. -->
                    <property name="cacheMode" value="PARTITIONED"/>
                    <property name="backups" value="1"/>
                    <property name="statisticsEnabled" value="true" />
                </bean>
            </list>
        </property>
        <!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
        <property name="discoverySpi">
            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
                <property name="ipFinder">
                    <!-- Uncomment static IP finder to enable static-based discovery of initial nodes. -->
                    <!--<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
                        <property name="addresses">
                            <list>
                                <!-- In distributed environment, replace with actual host IP address. -->
                                <value>Add your node ip address</value>
                                <value>add your node ip address</value>
                            </list>
                        </property>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath*:com/blu/ignite/dao/*Mapper.xml"/>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="URL" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="connectionCachingEnabled" value="true"/>
    </bean>
</beans>
Lets examine a few configuration properties:
property name="clientMode" value="true" - this property will force the current application to run as client.
property name="cacheMode" value="PARTITIONED" - cache mode will be partitioned, cache mode can be replicated also.
property name="backups" value="1" - always there will be one redundant element of cache in another node.
property name="statisticsEnabled" value="true" - this property will activate the cache statistics.

3) now lets write some
public class SpringIgniteRun {
    public static void main(String[] args) throws Exception{
        System.out.println("Run Spring example!!");
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-core.xml");

        IgniteConfiguration igniteConfiguration = (IgniteConfiguration) ctx.getBean("ignite.cfg");
        Ignite ignite = Ignition.start(igniteConfiguration);
        // get or create cache
        IgniteCache cache = ignite.getOrCreateCache("myCacheName");
        for(int i = 1; i < 1000; i++){
            cache.put(i, Integer.toString(i));
        }
        for(int i =1; i<1000;i++){
            System.out.println("Cache get:"+ cache.get(i));
        }
        Thread.sleep(20000); // sleep for 20 seconds
        // statistics
        System.out.println("Cache Hits:"+ cache.metrics(ignite.cluster()).getCacheHits());
        ignite.close();
    }
}
above code is self explained, we just create a cache named "myCacheName" and add 1000 String value of Integer. After inserting the value to cache, we also read the elements from cache and check the statistics. through ignitevisorcmd you can also monitor the data grid, follows you can find screen shot of the statistics of the grid
MyBatis Cache configuration: Now lets add MyBatis ORM l2 cache and examine how it's works.
<bean id="servicesBean" class="com.blu.ignite.WebServices">
        <property name="dao" ref="userServicesBean"/>
    </bean>
    <bean id="userServicesBean" class="com.blu.ignite.dao.UserServices">
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath*:com/blu/ignite/dao/*Mapper.xml"/>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="URL" value="${jdbc.url}" />
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="connectionCachingEnabled" value="true"/>
    </bean>


    <bean id="userMapper" autowire="byName" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.blu.ignite.mapper.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.blu.ignite.mapper" />
    </bean>
We add SQLsessionFactory, MyBatis mapper and Service Bean. Now lets add the *.Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.blu.ignite.mapper.UserMapper">

    <cache type="org.mybatis.caches.ignite.IgniteCacheAdapter" />

    <select id="getUser" parameterType="String" resultType="com.blu.ignite.dto.User" useCache="true">
      SELECT * FROM users WHERE id = #{id}
    </select>

    <select id="getUniqueJob" parameterType="String" resultType="String" useCache="false">
        select unique job from emp order by job desc
    </select>

</mapper>
Full sql (DDL/DML) scripts of emp and dept tables will be find in the directory com/blu/ignite/scripts I have created a simple web service to get the users and the unique jobs for employees. Here is the code for the web service as follows:
@WebService(name = "BusinessRulesServices",
        serviceName="BusinessRulesServices",
        targetNamespace = "http://com.blu.rules/services")
public class WebServices {
    private UserServices userServices;

    @WebMethod(operationName = "getUserName")
    public String getUserName(String userId){
        User user = userServices.getUser(userId);
        return user.getuName();
    }
    @WebMethod(operationName = "getUniqueJobs")
    public List getUniqueJobs(){
        return userServices.getUniqueJobs();
    }
    @WebMethod(exclude = true)
    public void setDao(UserServices userServices){
        this.userServices = userServices;
    }

}
Invoke of the web method getUserName will query the database and cache the query result in Ignite cache. Spring Caching: With spring caching you could achieve caching of the return value of any spring bean method. Apache Ignite will create the cache by the name of the cache which you will provide by the annotation @Cacheable("returnHello") For example, if I have such method as follows:
@Cacheable("returnHello")
    public String sayhello(String str){
        System.out.println("Client says:"+ str);

        return "hello"+str;
    }
The first time when the method will be invoked, a replicated cache with argument name will create in ignite, next time every invocation of the above method will return the value from the cache.
For now it's enough. Soon i will return back with some new features of apache ignite. Full source code of the project will found in the github. If you like this article, you would also like the book

Comments

Popular posts from this blog

Send e-mail with attachment through OSB

Oracle Service Bus (OSB) contains a good collection of adapter to integrate with any legacy application, including ftp, email, MQ, tuxedo. However e-mail still recognize as a stable protocol to integrate with any application asynchronously. Send e-mail with attachment is a common task of any business process. Inbound e-mail adapter which, integrated with OSB support attachment but outbound adapter doesn't. This post is all about sending attachment though JavaCallout action. There are two ways to handle attachment in OSB: 1) Use JavaCallout action to pass the binary data for further manipulation. It means write down a small java library which will get the attachment and send the e-mail. 2) Use integrated outbound e-mail adapter to send attachment, here you have to add a custom variable named attachment and assign the binary data to the body of the attachment variable. First option is very common and easy to implement through javax.mail api, however a much more developer manage t

Tip: SQL client for Apache Ignite cache

A new SQL client configuration described in  The Apache Ignite book . If it got you interested, check out the rest of the book for more helpful information. Apache Ignite provides SQL queries execution on the caches, SQL syntax is an ANSI-99 compliant. Therefore, you can execute SQL queries against any caches from any SQL client which supports JDBC thin client. This section is for those, who feels comfortable with SQL rather than execute a bunch of code to retrieve data from the cache. Apache Ignite out of the box shipped with JDBC driver that allows you to connect to Ignite caches and retrieve distributed data from the cache using standard SQL queries. Rest of the section of this chapter will describe how to connect SQL IDE (Integrated Development Environment) to Ignite cache and executes some SQL queries to play with the data. SQL IDE or SQL editor can simplify the development process and allow you to get productive much quicker. Most database vendors have their own front-en

Load balancing and fail over with scheduler

Every programmer at least develop one Scheduler or Job in their life time of programming. Nowadays writing or developing scheduler to get you job done is very simple, but when you are thinking about high availability or load balancing your scheduler or job it getting some tricky. Even more when you have a few instance of your scheduler but only one can be run at a time also need some tricks to done. A long time ago i used some data base table lock to achieved such a functionality as leader election. Around 2010 when Zookeeper comes into play, i always preferred to use Zookeeper to bring high availability and scalability. For using Zookeeper you have to need Zookeeper cluster with minimum 3 nodes and maintain the cluster. Our new customer denied to use such a open source product in their environment and i was definitely need to find something alternative. Definitely Quartz was the next choose. Quartz makes developing scheduler easy and simple. Quartz clustering feature brings the HA and