zoukankan      html  css  js  c++  java
  • Ehcache3开发入门简介

    在高并发应用中缓存就是核心机制。最近在研究Ehcache,发现这是一个更加灵活易用的缓存框架(相对于Redis、Memcache),Ehcache更加小巧轻便。而且都有持久化机制,不用担心JVM和服务器重启的数据丢失。我用四个字来形容:拎包入住。

    著名的Hibernate的默认缓存策略就是用Ehcache,Liferay的缓存也是依赖Ehcache,可见其健壮性。与其黑盒的瞎眼使用,不如来研究下这后边的机制。

    Ehcache的架构

    主要的特点:

    1. 缓存数据有三级:内存、堆外缓存Off-Heap、Disk缓存,因此无需担心容量问题。还可以通过RMI、可插入API等方式进行分布式缓存。
    2. 缓存数据会在虚拟机重启的过程中写入磁盘,持久化。
    3. 具有缓存和缓存管理器的侦听接口。
    4. 支持多缓存管理器实例,以及一个实例的多个缓存区域。
    Maven写法:
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.3.0</version>
    </dependency>
    
    Gradle写法:
    compile group: 'org.ehcache', name: 'ehcache', version: '3.3.0'

     还需注意,工程要有slf4j-api-1.7.XX的依赖。

    通用的读写使用CacheManager

    兼容3.0和2.0版
    代码可读性很好,就不解释了,详情见官网API:http://www.ehcache.org/documentation/3.3

    import org.ehcache.Cache;
    import org.ehcache.CacheManager;
    import org.ehcache.UserManagedCache;
    import org.ehcache.config.builders.CacheConfigurationBuilder;
    import org.ehcache.config.builders.CacheManagerBuilder;
    import org.ehcache.config.builders.ResourcePoolsBuilder;
    import org.ehcache.config.builders.UserManagedCacheBuilder;
    
    public class Main {
    
        public static void main(String[] args) {
            CacheManager cacheManager
            = CacheManagerBuilder.newCacheManagerBuilder() 
            .withCache("preConfigured",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))) 
            .build(); 
        cacheManager.init();
        
        Cache<Long, String> preConfigured =
            cacheManager.getCache("preConfigured", Long.class, String.class); 
    
        Cache<Integer, String> myCache = cacheManager.createCache("myCache", 
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, ResourcePoolsBuilder.heap(10)).build());
    
        for (int i=0;i<=20;i++){
            //
            myCache.put(i, "@"+i);
            //
            String value = myCache.get(i);
            System.out.println("get at "+i+":"+value);
        }
        
        cacheManager.removeCache("preConfigured"); 
        cacheManager.close(); 
        }
    
    }

    3.0的读写新泛型方法UserManagedCache

    很明显,更加简洁了

    import org.ehcache.UserManagedCache;
    import org.ehcache.config.builders.UserManagedCacheBuilder;
    
    
    public class Main {
    
        public static void main(String[] args) {
            UserManagedCache<Integer, String> userManagedCache =
                UserManagedCacheBuilder.newUserManagedCacheBuilder(Integer.class, String.class)
                    .build(false); 
            userManagedCache.init();         
    
            for (int i=0;i<=20;i++){
                //
                userManagedCache.put(i, "#"+i);
                //
                String value = userManagedCache.get(i);
                System.out.println("get at "+i+":"+value);
            }
    
            userManagedCache.close();
        }
    
    }

    三层缓存策略

    之前的版本是2级缓存,内存和磁盘,新版增加了更灵活的一级,堆外缓存(off-heap),这既是独立的进程缓存,还是JVM堆外的系统缓存,可以想象一下,JVM堆是非常宝贵的,如果占用过大会带来GC性能问题,堆外缓存很好的解决了这个问题,现在服务器内存越来越大,而磁盘缓存的io性能又比较低,off-heap缓存就是折中的方案,既保证了高速性能,又可以有一定的容量。off-heap缓存性能的占用主要是序列化、反序列化的过程。一旦对象被序列化,在返回Java堆的时候必需反序列化才可以使用。这是一笔性能开销。但off-heap还是要比本地磁盘、网络存储、RDBMS数据库IO等记录数据的系统要快非常多。还应指出的是,序列化/反序列化的性能开销远没有很多用户想象的那么大。off-heap已经针对字节缓冲区做了优化,本身也包含一些优化机制,可以对使用标准Java序列化的对象进行优化,能使复杂Java对象的性能提升两倍,使byte数组的性能提升四倍。

    个人是这样理解的:

    1. 常被查询、最重要、数据量较小的数据存放在堆缓存,不用担心JVM的重启,有持久化机制;
    2. 常被查询、数据量中等的数据存放在堆外缓存,几个G就好了,不用担心服务器的重启,有持久化机制;
    3. 不常用、大量的数据、但又不想占用数据库IO的数据,放在Disk缓存,容量自便;

      理解了三级缓存机制,现在还有一个黑盒问题有待了解,即EHcache的持久化策略算法,Redis的持久化策略是2种,即RDB快照和AOF追加日志,让用户在性能和完整性之间来自由选择,这非常灵活。目前还没查到EHcache的持久化策略,本好奇猫有点沮丧。

    import java.io.File;
    import org.ehcache.Cache;
    import org.ehcache.PersistentCacheManager;
    import org.ehcache.UserManagedCache;
    import org.ehcache.config.builders.CacheConfigurationBuilder;
    import org.ehcache.config.builders.CacheManagerBuilder;
    import org.ehcache.config.builders.ResourcePoolsBuilder;
    import org.ehcache.config.builders.UserManagedCacheBuilder;
    import org.ehcache.config.units.EntryUnit;
    import org.ehcache.config.units.MemoryUnit;
    
    public class Main {
    
        public static void main(String[] args) {
    
            PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(getStoragePath() + File.separator + "myData")) 
            .withCache("threeTieredCache",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class,
                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                        .heap(10, EntryUnit.ENTRIES)  //
                        .offheap(1, MemoryUnit.MB)    //堆外
                        .disk(20, MemoryUnit.GB)      //磁盘
                    )
            ).build(true);
    
            Cache<Integer, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Integer.class, String.class);
    
            //
            for (int i=0;i<=20000;i++){
                threeTieredCache.put(i, "$"+i);
            }
            
            //
            for (int i=0;i<=200000;i++){
                String value = threeTieredCache.get(i);
                System.out.println("get at "+i+":"+value);
            }
    
            persistentCacheManager.close();
        }
    
        private static String getStoragePath() {
            // TODO Auto-generated method stub
            return "d:";
        }
    
    }

    发现数据量大了之后会写入磁盘:

    一些实战使用方法,欢迎拍砖

    一般MVC应用的后端是Model - Persistent DAO - Service的分层
    比如,我们有User的Model,UserService的Service。

    //写方式:
    
    user = new User
    userService.put(k, v) //系统持久化
    cache.put(k, v) //缓存写入
    
    
    //读:
    
    user = cache.get(k)
    if(user == null) {
        user = userService.get(k)
        cache.put(k, v)
    }

    集群

    不用集群的多级缓存

    应用程序直接访问一个或者多个Cache Manager,而一个Cache Manager管理Caches集合。Caches集合可以多级存储。

    使用集群

    一些更高级的用法

    事务缓存

    对读写原子性有要求的必读:
    http://www.ehcache.org/documentation/3.3/xa.html

    线程池的使用

    用于异步操作,这将大幅度提升效率:
    http://www.ehcache.org/documentation/3.3/thread-pools.html

  • 相关阅读:
    deleted
    deleted
    deleted
    deleted
    deleted
    deleted
    POJ 1840 Eqs(乱搞)题解
    UVALive 6955 Finding Lines(随机化优化)题解
    CodeForces 828E DNA Evolution(树状数组)题解
    UVA 11019 Matrix Matcher(二维hash + 尺取)题解
  • 原文地址:https://www.cnblogs.com/starcrm/p/6605663.html
Copyright © 2011-2022 走看看