在高并发应用中缓存就是核心机制。最近在研究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

Ehcache3开发入门简介的更多相关文章

  1. HealthKit开发快速入门教程之HealthKit开发概述简介

    HealthKit开发快速入门教程之HealthKit开发概述简介 2014年6月2日召开的年度开发者大会上,苹果发布了一款新的移动应用平台,可以收集和分析用户的健康数据.该移动应用平台被命名为“He ...

  2. JavaWeb学习总结(一)——JavaWeb开发入门

    http://www.cnblogs.com/xdp-gacl/p/3729033.html 只为成功找方法,不为失败找借口! JavaWeb学习总结(一)--JavaWeb开发入门 一.基本概念 1 ...

  3. Arduino可穿戴开发入门教程(大学霸内部资料)

    Arduino可穿戴开发入门教程(大学霸内部资料) 试读下载地址:链接:http://pan.baidu.com/s/1mg9To28 密码:z5v8 介绍:Arduino可穿戴开发入门教程(大学霸内 ...

  4. 掌握 Ajax,第 1 部分: Ajax 入门简介

    转:http://www.ibm.com/developerworks/cn/xml/wa-ajaxintro1.html 掌握 Ajax,第 1 部分: Ajax 入门简介 理解 Ajax 及其工作 ...

  5. Hadoop开发环境简介(转)

    1.Hadoop开发环境简介 1.1 Hadoop集群简介 Java版本:jdk-6u31-linux-i586.bin Linux系统:CentOS6.0 Hadoop版本:hadoop-1.0.0 ...

  6. (转)Web Service入门简介(一个简单的WebService示例)

    Web Service入门简介 一.Web Service简介 1.1.Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从I ...

  7. 【转载】Servlet Filter(过滤器)、Filter是如何实现拦截的、Filter开发入门

    Servlet Filter(过滤器).Filter是如何实现拦截的.Filter开发入门 Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过F ...

  8. 【Electron】Electron开发入门

    Electron简介: Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序,并且跨平台(win,mac,linux等各种PC端平台).与其它各种 ...

  9. Python云端系统开发入门——框架基础

    Django框架基础 这是我学习北京理工大学嵩天老师的<Python云端系统开发入门>课程的笔记,在此我特别感谢老师的精彩讲解和对我的引导. 1.Django简介与安装 Django是一个 ...

随机推荐

  1. 学习日 day1

    今天第一天开始写博客,希望以后能坚持,每天写,一是记录自己学习的历程,更重要的是复习每天学过的东西. 今天学习的内容:time模块的相关语法 导入方式 首行输入import time即可 time.t ...

  2. 【转】GT 的性能测试方案解析

    前言 本文将整理腾讯GT各个性能测试项的测试方法,目的是为了帮助移动性能专项测试同学快速过一遍腾讯GT各个性能数据是如何获取的.另外对腾讯GT还不了解或者不知道它能做什么的同学可以看看这篇文章:htt ...

  3. Lozad.js 简单使用

    GayHub位置:https://github.com/ApoorvSaxena/lozad.js 导入: <script type="text/javascript" sr ...

  4. 516. Longest Palindromic Subsequence最长的不连续回文串的长度

    [抄题]: Given a string s, find the longest palindromic subsequence's length in s. You may assume that ...

  5. HTML中关于class内容空格多类名的问题详解

    之所以想谈谈这个,不明所以.所以转载下来方便自己看看. 问:像 class="info fl" 这种class定义是何意思? 答:这里的空格隔开后,它们所代表的是两个类名,分别为i ...

  6. Log4Net web.config配置

     1 .[assembly: log4net.Config.XmlConfigurator(ConfigFile = "web.config", Watch = true)]  写 ...

  7. boost asio 学习(九) boost::asio 网络封装

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=10 9. A ...

  8. ios下面的按钮和inout框

    在ios系统中,按钮和输入框,会默认给你加一个圆角和阴影,可以用css去掉这个自带的属性 input[type=button], input[type=submit], input[type=file ...

  9. strftime使用%F格式化日期失败

    报错:invalid format directive 解决:把%F换成%Y-%m-%d

  10. MFC为多个控件绑定同一个函数

    方式一: afx_msg void OnButtonClick(UINT nID); ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON_1, IDC_BUTTON_XX, ...