1
votes

I had created a setup of two node cluster for Apache Ignite. I am using this cluster as DataBase Caching use-case(https://ignite.apache.org/use-cases/caching/database-caching.html). Now When I created the IgniteRepository in my spring boot application and when I retrieve entry from DB then the entry is cached in only one node in cluster while I set the cluster mode to REPLICATED, Which says that data is cached by each node in cluster (https://apacheignite.readme.io/docs/cache-modes). Please help me with this, Am I doing something wrong with my cluster configuration or Ignite has such an implementation.

I have one observation which is, when I used

ignite.cache("EmployeesCache").loadCache(null);"

in my spring IgniteConfig it loads all the table data to both the node while starting up. But, When I start application with empty cache i.e. commenting out above line and then use

"getById(id)"

operation then replication is not happening properly.

My Code for this is below:

Spring Ignite Configuration:

@Bean("igniteInstance")
public Ignite startIgniteForDataBaseService() {
    Ignite ignite = Ignition.start("META-INF/EmployeeCluster-client.xml");
   // ignite.cache("EmployeesCache").loadCache(null);
    return ignite;
}

Client XML :

<?xml version="1.0" encoding="UTF-8"?>

<!-- This file was generated by Ignite Web Console (01/07/2019, 12:15) -->

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:util="http://www.springframework.org/schema/util"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd
                       http://www.springframework.org/schema/util
                       http://www.springframework.org/schema/util/spring-util.xsd">

<!-- Data source beans will be initialized from external properties file. -->
<bean id="dsMySQL_Employees" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
    <property name="URL" value="jdbc:mysql://192.168.138.134:3306/employees"/>
    <property name="user" value="dbadmin"/>
    <property name="password" value="admin"/>
</bean>

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="clientMode" value="true"/>
    <property name="igniteInstanceName" value="EmployeeCluster"/>

    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <property name="ipFinder">
                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
                    <property name="addresses">
                        <list>
                            <value>127.0.0.1:47500..47510</value>
                        </list>
                    </property>
                </bean>
            </property>
        </bean>
    </property>

    <property name="cacheConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <property name="name" value="EmployeesCache"/>
                <property name="cacheMode" value="REPLICATED"/>
                <property name="atomicityMode" value="ATOMIC"/>

                <property name="cacheStoreFactory">
                    <bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">
                        <property name="dataSourceBean" value="dsMySQL_Employees"/>
                        <property name="dialect">
                            <bean class="org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect">
                            </bean>
                        </property>

                        <property name="types">
                            <list>
                                <bean class="org.apache.ignite.cache.store.jdbc.JdbcType">
                                    <property name="cacheName" value="EmployeesCache"/>
                                    <property name="keyType" value="java.lang.Integer"/>
                                    <property name="valueType" value="com.techacademy.model.Employees"/>
                                    <property name="databaseSchema" value="employees"/>
                                    <property name="databaseTable" value="employees"/>

                                    <property name="keyFields">
                                        <list>
                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.INTEGER"/>
                                                </constructor-arg>
                                                <constructor-arg value="emp_no"/>
                                                <constructor-arg value="int"/>
                                                <constructor-arg value="empNo"/>
                                            </bean>
                                        </list>
                                    </property>

                                    <property name="valueFields">
                                        <list>
                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.INTEGER"/>
                                                </constructor-arg>
                                                <constructor-arg value="emp_no"/>
                                                <constructor-arg value="int"/>
                                                <constructor-arg value="empNo"/>
                                            </bean>
                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.DATE"/>
                                                </constructor-arg>
                                                <constructor-arg value="birth_date"/>
                                                <constructor-arg value="java.sql.Date"/>
                                                <constructor-arg value="birthDate"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.VARCHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="first_name"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="firstName"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.VARCHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="last_name"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="lastName"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.CHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="gender"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="gender"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.DATE"/>
                                                </constructor-arg>
                                                <constructor-arg value="hire_date"/>
                                                <constructor-arg value="java.sql.Date"/>
                                                <constructor-arg value="hireDate"/>
                                            </bean>
                                        </list>
                                    </property>
                                </bean>
                            </list>
                        </property>
                    </bean>
                </property>

                <property name="readThrough" value="true"/>
                <property name="writeThrough" value="true"/>

                <property name="queryEntities">
                    <list>
                        <bean class="org.apache.ignite.cache.QueryEntity">
                            <property name="keyType" value="java.lang.Integer"/>
                            <property name="valueType" value="com.techacademy.model.Employees"/>
                            <property name="keyFieldName" value="empNo"/>

                            <property name="keyFields">
                                <list>
                                    <value>empNo</value>
                                </list>
                            </property>

                            <property name="fields">
                                <map>
                                    <entry key="birthDate" value="java.sql.Date"/>
                                    <entry key="firstName" value="java.lang.String"/>
                                    <entry key="lastName" value="java.lang.String"/>
                                    <entry key="gender" value="java.lang.String"/>
                                    <entry key="hireDate" value="java.sql.Date"/>
                                    <entry key="empNo" value="java.lang.Integer"/>
                                </map>
                            </property>

                            <property name="aliases">
                                <map>
                                    <entry key="empNo" value="emp_no"/>
                                    <entry key="birthDate" value="birth_date"/>
                                    <entry key="firstName" value="first_name"/>
                                    <entry key="lastName" value="last_name"/>
                                    <entry key="hireDate" value="hire_date"/>
                                </map>
                            </property>
                        </bean>
                    </list>
                </property>
            </bean>
        </list>
    </property>
</bean>

Server XML:

<?xml version="1.0" encoding="UTF-8"?>

<!-- This file was generated by Ignite Web Console (01/07/2019, 12:15) -->

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:util="http://www.springframework.org/schema/util"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd
                       http://www.springframework.org/schema/util
                       http://www.springframework.org/schema/util/spring-util.xsd">

<!-- Data source beans will be initialized from external properties file. -->
<bean id="dsMySQL_Employees" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource">
    <property name="URL" value="jdbc:mysql://192.168.138.134:3306/employees"/>
    <property name="user" value="dbadmin"/>
    <property name="password" value="admin"/>
</bean>

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="igniteInstanceName" value="EmployeeCluster"/>

    <property name="discoverySpi">
        <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
            <property name="ipFinder">
                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
                    <property name="addresses">
                        <list>
                            <value>127.0.0.1:47500..47510</value>
                        </list>
                    </property>
                </bean>
            </property>
        </bean>
    </property>

    <property name="cacheConfiguration">
        <list>
            <bean class="org.apache.ignite.configuration.CacheConfiguration">
                <property name="name" value="EmployeesCache"/>
                <property name="cacheMode" value="REPLICATED"/>
                <property name="atomicityMode" value="ATOMIC"/>

                <property name="cacheStoreFactory">
                    <bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">
                        <property name="dataSourceBean" value="dsMySQL_Employees"/>
                        <property name="dialect">
                            <bean class="org.apache.ignite.cache.store.jdbc.dialect.MySQLDialect">
                            </bean>
                        </property>

                        <property name="types">
                            <list>
                                <bean class="org.apache.ignite.cache.store.jdbc.JdbcType">
                                    <property name="cacheName" value="EmployeesCache"/>
                                    <property name="keyType" value="java.lang.Integer"/>
                                    <property name="valueType" value="com.techacademy.model.Employees"/>
                                    <property name="databaseSchema" value="employees"/>
                                    <property name="databaseTable" value="employees"/>

                                    <property name="keyFields">
                                        <list>
                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.INTEGER"/>
                                                </constructor-arg>
                                                <constructor-arg value="emp_no"/>
                                                <constructor-arg value="int"/>
                                                <constructor-arg value="empNo"/>
                                            </bean>
                                        </list>
                                    </property>

                                    <property name="valueFields">
                                        <list>
                                         <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.INTEGER"/>
                                                </constructor-arg>
                                                <constructor-arg value="emp_no"/>
                                                <constructor-arg value="int"/>
                                                <constructor-arg value="empNo"/>
                                            </bean>
                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.DATE"/>
                                                </constructor-arg>
                                                <constructor-arg value="birth_date"/>
                                                <constructor-arg value="java.sql.Date"/>
                                                <constructor-arg value="birthDate"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.VARCHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="first_name"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="firstName"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.VARCHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="last_name"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="lastName"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.CHAR"/>
                                                </constructor-arg>
                                                <constructor-arg value="gender"/>
                                                <constructor-arg value="java.lang.String"/>
                                                <constructor-arg value="gender"/>
                                            </bean>

                                            <bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
                                                <constructor-arg>
                                                    <util:constant static-field="java.sql.Types.DATE"/>
                                                </constructor-arg>
                                                <constructor-arg value="hire_date"/>
                                                <constructor-arg value="java.sql.Date"/>
                                                <constructor-arg value="hireDate"/>
                                            </bean>
                                        </list>
                                    </property>
                                </bean>
                            </list>
                        </property>
                    </bean>
                </property>

                <property name="readThrough" value="true"/>
                <property name="writeThrough" value="true"/>

                <property name="queryEntities">
                    <list>
                        <bean class="org.apache.ignite.cache.QueryEntity">
                            <property name="keyType" value="java.lang.Integer"/>
                            <property name="valueType" value="com.techacademy.model.Employees"/>
                            <property name="keyFieldName" value="empNo"/>

                            <property name="keyFields">
                                <list>
                                    <value>empNo</value>
                                </list>
                            </property>

                            <property name="fields">
                                <map>
                                    <entry key="birthDate" value="java.sql.Date"/>
                                    <entry key="firstName" value="java.lang.String"/>
                                    <entry key="lastName" value="java.lang.String"/>
                                    <entry key="gender" value="java.lang.String"/>
                                    <entry key="hireDate" value="java.sql.Date"/>
                                    <entry key="empNo" value="java.lang.Integer"/>
                                </map>
                            </property>

                            <property name="aliases">
                                <map>
                                    <entry key="empNo" value="emp_no"/>
                                    <entry key="birthDate" value="birth_date"/>
                                    <entry key="firstName" value="first_name"/>
                                    <entry key="lastName" value="last_name"/>
                                    <entry key="hireDate" value="hire_date"/>
                                </map>
                            </property>
                        </bean>
                    </list>
                </property>
            </bean>
        </list>
    </property>
</bean>

Ingite Repository:

@RepositoryConfig(cacheName = "EmployeesCache")
public interface EmployeeRepository extends IgniteRepository<Employees,Integer> {
}

Rest Controller:

  @RestController
  public class RetrieveEmployeeController {

    @Autowired
    private EmployeeRepository employeeRepository;

    @GetMapping("/employee/{id}")
    public Employees getEmployeeDetails(@PathVariable("id") Integer id){
        return  employeeRepository.findById(id).orElseGet(null);
    }
  }

I was expecting that when I use findById data will be replicated on both the node but it is not replicating on other node. The current output cache statistics are below:

visor> cache -a
Time of the snapshot: 2019-01-07 13:22:49
+================================================================================================================================================================+
|       Name(@)       |    Mode    | Nodes | Total entries (Heap / Off-heap) | Primary entries (Heap / Off-heap) |   Hits    |  Misses   |   Reads   |  Writes   |
+================================================================================================================================================================+
| EmployeesCache(@c0) | REPLICATED | 2     | 1 (0 / 1)                       | min: 0 (0 / 0)                    | min: 0    | min: 0    | min: 0    | min: 0    |
|                     |            |       |                                 | avg: 0.50 (0.00 / 0.50)           | avg: 0.00 | avg: 0.00 | avg: 0.00 | avg: 0.00 |
|                     |            |       |                                 | max: 1 (0 / 1)                    | max: 0    | max: 0    | max: 0    | max: 0    |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------+

Cache 'EmployeesCache(@c0)':
+-------------------------------------------------------+
| Name(@)                         | EmployeesCache(@c0) |
| Total entries (Heap / Off-heap) | 1 (0 / 1)           |
| Nodes                           | 2                   |
| Total size Min/Avg/Max          | 0 / 0.50 / 1        |
|   Heap size Min/Avg/Max         | 0 / 0.00 / 0        |
|   Off-heap size Min/Avg/Max     | 0 / 0.50 / 1        |
+-------------------------------------------------------+

Nodes for: EmployeesCache(@c0)
+====================================================================================================================+
|       Node ID8(@), IP        | CPUs | Heap Used | CPU Load |   Up Time    | Size (Primary / Backup)  | Hi/Mi/Rd/Wr |
+====================================================================================================================+
| 90CD3FAD(@n1), 192.168.137.1 | 8    | 5.49 %    | 0.07 %   | 00:50:35.127 | Total: 1 (1 / 0)         | Hi: 0       |
|                              |      |           |          |              |   Heap: 0 (0 / <n/a>)    | Mi: 0       |
|                              |      |           |          |              |   Off-Heap: 1 (1 / 0)    | Rd: 0       |
|                              |      |           |          |              |   Off-Heap Memory: <n/a> | Wr: 0       |
+------------------------------+------+-----------+----------+--------------+--------------------------+-------------+
| AF07CA98(@n0), 192.168.137.1 | 8    | 28.71 %   | 0.00 %   | 00:50:40.230 | Total: 0 (0 / 0)         | Hi: 0       |
|                              |      |           |          |              |   Heap: 0 (0 / <n/a>)    | Mi: 0       |
|                              |      |           |          |              |   Off-Heap: 0 (0 / 0)    | Rd: 0       |
|                              |      |           |          |              |   Off-Heap Memory: 0     | Wr: 0       |
+--------------------------------------------------------------------------------------------------------------------+
'Hi' - Number of cache hits.
'Mi' - Number of cache misses.
'Rd' - number of cache reads.
'Wr' - Number of cache writes.

Aggregated queries metrics:
  Minimum execution time: 00:00:00.000
  Maximum execution time: 00:00:00.000
  Average execution time: 00:00:00.000
  Total number of executions: 0
  Total number of failures:   0
1
I was able to reproduce this issue. It looks like this is related to IgniteRepository. As a workaround, you can replace employeeRepository.findById(id).orElseGet(null) by Ignition.ignite("EmployeeCluster").cache("EmployeesCache"). I will check this issue more deeply and return back with my findings. - Roman Guseinov

1 Answers

1
votes

I was able to reproduce this on the master branch and created a Jira ticket to fix this IGNITE-10950 Lost backup entries when using spring data and cache store. This way you are able to track the progress of resolving this issue.

For now, as a workaround, you can use IgniteCache#get instead of IgniteRepository#findById.