(四)apache ignite-In-memory caching

到目前为止,我们已经介绍了Apache Ignite及其体系结构的基本功能。现在,是时候深入了解Apache Ignite的实现了,并观察它如何提高应用程序性能。在前几章中,我们已经讨论了很多关于Ignite特性和体系结构的内容,现在我们将介绍所有最重要的引爆内存数据网格特性,并解释用例,以了解应该如何以及何时使用这些特性。本章的主要目标是演示如何使用Apache Ignite来加速应用程序性能而不改变代码。IMDG或内存数据网格不是内存中的关系数据库、NoSQL数据库或关系数据库。但是,它是一个分布式键值存储,可以将其想象为一个分布式分区散列映射,其中集群中的每个节点都有自己的数据部分。数据模型分布在单个位置或多个位置的多个服务器上。这种分布称为数据结构。这种分布式模型也称为共享的无架构。IMDG具有以下特点:

  • 所有服务器都可以在每个节点上活动。
  • 所有数据都存储在服务器的RAM中。
  • 可以不受干扰地添加或删除服务器,以增加可用的RAM数量。
  • 数据模型是非关系型的,并且是基于对象的。
  • 分布式应用程序是用平台独立语言编写的。
  • 数据结构具有弹性,允许对单个服务器或多个服务器进行非破坏性的自动检测和恢复。
    正如我们前面讨论的,Apache Ignite实现了JCache规范来开发内存数据网格。然而,Ignite为内存数据网格提供了许多高级功能。在本章中,我们将讨论以下主题:
  • Apache Ignite 作为一个 2nd 级别的cache。
  • Java方法的缓存。
  • Web sessions集群。
  • Apache Ignite作为一个 big memory, off-heap memory。

2nd级别缓存

通过避免昂贵的数据库调用,将数据保持在应用程序的本地,第二级缓存可以提高应用程序的性能。二级缓存由持久性提供程序完全管理,通常对应用程序是透明的。也就是说,应用程序在不知道缓存的情况下通过实体管理器读取、写入和提交数据。
还有基于持久性提供者(如MyBatis或Hibernate)的一级缓存。第1级用于缓存当前数据库会话中从数据库检索的对象。当前端(web页面或web服务)调用一个服务时,将打开一个HTTP会话并重用它,直到服务方法返回。在服务方法返回之前执行的所有操作都将共享L1缓存,因此相同的对象不会从数据库中检索两次。完成数据库会话后,从数据库检索的对象将不可用。在大多数持久性提供程序中,默认情况下总是启用第1级缓存。


image.png

与第一级缓存不同,二级缓存能够跨越数据库会话,存储数据库对象和查询结果(查询缓存)。它位于持久性提供者和数据库之间。持久性上下文共享缓存,使第二级缓存在整个应用程序中都可用。因此,由于实体被加载到共享缓存中并从共享缓存中可用,因此数据库流量大大减少。因此,简而言之,二级缓存提供了以下好处:

  1. 通过避免昂贵的数据库调用来提高性能。
  2. 数据对应用程序保持透明。
  3. CRUD操作可以通过普通的持久性管理器函数执行。
  4. 通过使用二级缓存,您可以在不更改代码的情况下加速应用程序的性能。

MyBatis二级缓存

在Ignite中,MyBatis的第2级缓存存储的是实体数据,而不是实体或对象本身。数据以序列化格式存储,看起来像hashmap,其中键是实体Id,值是原始值的列表。
在这里,我们的目标是最小化查询执行时间。接下来,我们将开发一个使用MyBatis和Ignite的应用程序,以实现计算性能提升。

Step1

创建一个java项目

mvn archetype:generate -DgroupId=com.mycookcode.bigData.ignite -DartifactId=ignite-mybatis -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Step2

在maven配置文件中添加以下依赖:

    
      org.apache.ignite
      ignite-core
      ${ignite.version}
    

    
      org.apache.ignite
      ignite-spring
      ${ignite.version}
    

    
      org.mybatis.caches
      mybatis-ignite
      1.0.6
    

    
      org.mybatis
      mybatis-spring
      1.3.2
    

    
      org.mybatis
      mybatis
      3.4.6
    


    
    
      mysql
      mysql-connector-java
      8.0.12
    

在这个项目中,我们将使用spring框架,因此必须添加一些spring相关的依赖项。此外,我们还添加了MyBatis核心库和mybatise-ignite库,以集成Apache Ignite作为二级缓存。在编译时,Maven使用这些信息在Maven存储库中查找上述所有库。Maven首先查看本地计算机上的存储库。如果库不存在,它将从公共Maven存储库下载它们,并将它们存储在本地存储库中。

Step3

现在,我们必须在项目的资源目录中添加spring上下文XML文件,以将其添加到java类路径中。spring上下文文件的完整版本将类似。让我们详细地看一下spring-core.xml文件。




    
    

    

    

    
        
    

    
    
        
    


    
    
        
    

     
    
        
        
        
        

        
            
                
                    
                    
                    
                    
                    
                    
                    
                
            
        
        
        
            
                
                    
                        
                            
                                
                                127.0.0.1:47500..47509
                            
                        
                    
                
            
        

    


    
    
        
        
    

    
        
        
    

    
    
        
        
        
        
    

    
        
    


 

Step4

现在,我们将添加UserMapper.xml到类路径中。注意,以下xml文件是位于绝对类路径(/resources/mapper/ usermap.xml)中。





    
    

映射器名称空间(mapper namespace)和缓存类型是配置中最重要的部分。注意,对于每个映射器名称空间,在Ignite集群中将创建一个复制缓存。在这种情况下,缓存名称将是com.mycookcode.bigData.ignite.mapper.UserMapper。对于缓存类型,我们声明了Ignite cache适配器的接口。接下来,我们添加了SQL查询,它是参数类型和返回值的类型。我们使用非常简单的SQL查询来通过雇员名获取雇员。在这里,我们已经通过XML完成了所有声明性配置。现在我们准备向应用程序添加业务逻辑。

Step5

从文件夹脚本中执行以下DDL和DML脚本,以创建数据库表,并向表中插入几行。为了简单起见,我们使用Oracle数据库中著名的emp和dept实体。我稍微修改了DDL/DML脚本,让它们运行到MySQL中。department (dept)和employee (emp)表的结构非常简单,它们彼此之间有一对多的关系。

create table dept(
  deptno integer,
  dname  text,
  loc    text,
  constraint pk_dept primary key (deptno)
);
create table emp(
  empno    integer,
  ename    text,
  job      text,
  mgr      integer,
  hiredate date,
  sal      integer,
  comm     integer,
  deptno   integer,
  constraint pk_emp primary key (empno),
  constraint fk_deptno foreign key (deptno) references dept (deptno)
);

Step6

既然已经设置了项目和构建系统,就可以继续创建web服务了。
此时,soap web服务只包含一个web方法getEmployee。

package com.mycookcode.bigData.ignite;

import com.mycookcode.bigData.ignite.dao.UserServices;
import com.mycookcode.bigData.ignite.dto.Employee;

import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService(name="BusinessRulesServices",
            serviceName = "BusinessRulesServices",
            targetNamespace = "http://com.ignite.rules/services")
public class WebServices {


    private UserServices userServices;

    @WebMethod(exclude = true)
    public void setDao(UserServices userServices){
        this.userServices = userServices;
    }

    @WebMethod(operationName = "getEmploee")
    public Employee getEmploee(String ename) {return userServices.getEmploee(ename);}
}

您可以从源代码中获得其他所有的类,比如DTO。

Step7

要运行web服务,我们将使用带有maven构建的one-jar插件。通过以下命令构建项目。

mvn clean install

Step8

运行web服务。

java -jar ./target/ignite-mybatis-1.0-SNAPSHOT.one-jar.jar

如果一切顺利,您应该会在控制台上看到以下日志:

image.png

web service服务运行在本地的7001端口上。可以通过这个URL web服务http://localhost:7001/invokeRules?wsdl发现web服务WSDL。现在可以使用soap客户机调用web服务,我将使用chrome浏览器中的开发者工具控制台来测试服务。当我第一次调用服务时,调用时间大约是259毫秒,因为查询结果还没有在缓存中。
image.png

再次调用Web方法。
image.png

这一次,响应时间是79毫秒,响应速度明显提高。MyBatis只返回Ignite缓存的结果。它几乎是实时的响应。让我们来看一下Ignite缓存中的缓存条目。Ignitevisor命令扫描可以帮助您找到缓存中的所有条目。
image.png

Cache Key = org.apache.ibatis.cache.CacheKey [idHash=1538632341, hash=872929822, checksum=\
2936898376, count=6, multiplier=37, hashcode=872929822, updateList=[com.blu.imdg.mapper.Us\
erMapper.getEmploee, 0, 2147483647, SELECT * FROM emp WHERE ename = ?, KING, SqlSessionFac\
toryBean]]
Key Value = [com.blu.imdg.dto.Employee [idHash=545458831, hash=342167489, date=null, ename\ =KING, mgr=null, empno=7839, job=PRESIDENT, deptno=10, sal=5000]]

在emp表中有一些行(总共12行),并且在字段ename上没有任何索引。让我们在表emp的字段ename上创建唯一的索引,并重新执行服务调用。

CREATE UNIQUE INDEX ename_idx ON emp (ename);

在字段ename上创建一个btree索引。现在,在SOAP消息中更改雇员表的ename字段,例如,FORD并再次执行web方法。


image.png

现在的响应时间是84毫秒,你可能会认为差别不大。但是在生产系统中,将拥有数百万行,而不是数据库表中的13行。此外,当表上有索引时,DML操作每次都会重新索引数据库表,这也会降低应用程序的性能。大多数时候,Ignite缓存的响应时间不会改变,因为没有额外的开销来消耗DB连接、SQL查询的软/硬解析。

Calculate application speedup计算应用加速:

可以使用Amdahl's law计算应用程序的加速比。公式:1/((1 - Proportion speed up) + Proportion speed up / speed up)


image.png
  • P是可以并行的比例
  • S是这部分并行可以加速S倍 (S可以理解是CPU核的个数,即新代码的执行时间为原来执行时间的1/S)
    另外,请注意,对于web应用程序,系统应该包括浏览器展现时间和网络延迟。
    在使用缓存时,应用程序的性能至少取决于以下两个因素:
  • 应用程序检索缓存数据片段的次数;
  • 缓存减少了响应时间的比例。
    假设我们有一个web应用程序,未加缓存的整个页面呈现时间是259毫秒。现在,让我们从数据库级缓存计算速度。在我们的例子中:
  • 打开页面时间:259毫秒。
  • 数据库时间:84毫秒。
  • 缓存检索时间:79毫秒。
  • 比例:84/259~32.4%
    预期的系统加速率应该是:
    1/((1-0.324)+0.324/(84/79))=1/(0.676+0.305)~1.01倍的系统加速。
    虽然1.01倍的系统速度不是很令人印象深刻,但在生产环境中,缓存后的结果将与没缓存前的结果有很大不同。

你可能感兴趣的:((四)apache ignite-In-memory caching)