java中的本地缓存【自己构造单例、guava、ehcache:问题:为什么构造缓存、如何构造缓存、如何保证集群内部缓存的一致性】*****很重要
2015-05-07 11:22
926 查看
文章来源:
http://blog.sina.com.cn/s/blog_6940cab30102uwmh.html
java中的本地缓存,工作后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下。自己构造单例、guava、ehcache基本上涵盖了目前的大多数行为了。
为什么要有本地缓存?
在系统中,有些数据,数据量小,但是访问十分频繁(例如国家标准行政区域数据),针对这种场景,需要将数据搞到应用的本地缓存中,以提升系统的访问效率,减少无谓的数据库访问(数据库访问占用数据库连接,同时网络消耗比较大),但是有一点需要注意,就是缓存的占用空间以及缓存的失效策略。
为什么是本地缓存,而不是分布式的集群缓存?
目前的数据,大多是业务无关的小数据缓存,没有必要搞分布式的集群缓存,目前涉及到订单和商品的数据,会直接走DB进行请求,再加上分布式缓存的构建,集群维护成本比较高,不太适合紧急的业务项目。
这里介绍一下缓存使用的三个阶段(摘自info架构师文档)
本地缓存在那个区域?
目前考虑的是占用了JVM的heap区域,再细化一点的就是heap中的old区,目前的数据量来看,都是一些小数据,加起来没有几百兆,放在heap区域最快最方便。后期如果需要放置在本地缓存的数据大的时候,可以考虑在off-heap区域(direct-memory 或者 big-memory),但是off-heap区域的话,需要考虑对象的序列化(因为off-heap区域存储的是二进制的数据),另外一个的话就是off-heap的GC问题。其实,如果真的数据量比较大,那其实就可以考虑搞一个集中式的缓存系统,可以是单机,也可以是集群,来承担缓存的作用。
搞一个单例模式,里面有个Map的变量来放置数据
关于单例模式,一个既简单又复杂的模式(http://iamzhongyong.iteye.com/blog/1539642)
非常典型的代码如下:
public class SingletonMap {
//一个本地的缓存Map
private Map localCacheStore = new HashMap();
//一个私有的对象,非懒汉模式
private static SingletonMap singletonMap = new SingletonMap();
//私有构造方法,外部不可以new一个对象
private SingletonMap(){
}
//静态方法,外部获得实例对象
public static SingletonMap getInstance(){
return singletonMap;
}
//获得缓存中的数据
public Object getValueByKey(String key){
return localCacheStore.get(key);
}
//向缓存中添加数据
public void putValue(String key , Object value){
localCacheStore.put(key, value);
}
}
这种能不能用?可以用,但是非常局限
但是这种的就是本地缓存了吗?答案显然不是,为啥呢?
1、 没有缓存大小的设置,无法限定缓存体的大小以及存储数据的限制(max size limit);
2、 没有缓存的失效策略(eviction policies);
3、 没有弱键引用,在内存占用吃紧的情况下,JVM是无法回收的(weak rererences keys);
4、 没有监控统计(statistics);
5、 持久性存储(persistent store);
所以,这种就直接废掉了。。。
引入EhCache来构建缓存(详细介绍: http://raychase.iteye.com/blog/1545906)
EhCahce的核心类:
A、CacheManager:Cache的管理类;
B、Cache:具体的cache类信息,负责缓存的get和put等操作
C、CacheConfiguration :cache的配置信息,包含策略、最大值等信息
D、Element:cache中单条缓存数据的单位
典型的代码如下:
public static void main(String[] args) {
//EhCache的缓存,是通过CacheManager来进行管理的
CacheManager cacheManager = CacheManager.getInstance();
//缓存的配置,也可以通过xml文件进行
CacheConfiguration conf = new CacheConfiguration();
conf.name("cache_name_default");//设置名字
conf.maxEntriesLocalHeap(1000);//最大的缓存数量
conf.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);//设置失效策略
//创建一个缓存对象,并把设置的信息传入进去
Cache localCache = new Cache(conf);
//将缓存对象添加到管理器中
cacheManager.addCache(localCache);
localCache.put(new Element("iamzhongyong", new Date()));
System.out.println(localCache.getSize());
System.out.println(localCache.getStatistics().toString());
System.out.println(localCache.getName());
System.out.println(localCache.get("iamzhongyong").toString());
System.out.println(localCache.get("iamzhongyong").getObjectValue());
}
当然,Cache的配置信息,可以通过配置文件制定了。。。
优点:功能强大,有失效策略、最大数量设置等,缓存的持久化只有企业版才有,组件的缓存同步,可以通过jgroup来实现
缺点:功能强大的同时,也使其更加复杂
引入guava的cacheBuilder来构建缓存
这个非常强大、简单,通过一个CacheBuilder类就可以满足需求。
缺点就是如果要组件同步的话,需要自己实现这个功能。
典型的代码如下:
public class GuavaCacheBuilderTest {
public static void main(String[] args) throws Exception{
GuavaCacheBuilderTest cache = new GuavaCacheBuilderTest();
cache.getNameLoadingCache("bixiao");
}
public void getNameLoadingCache(String name) throws Exception{
LoadingCache cache = CacheBuilder.newBuilder()
.maximumSize(20)//设置大小,条目数
.expireAfterWrite(20, TimeUnit.SECONDS)//设置失效时间,创建时间
.expireAfterAccess(20, TimeUnit.HOURS) //设置时效时间,最后一次被访问
.removalListener(new RemovalListener() { //移除缓存的监听器
public void onRemoval(RemovalNotification notification) {
System.out.println("有缓存数据被移除了");
}})
.build(new CacheLoader(){ //通过回调加载缓存
@Override
public String load(String name) throws Exception {
return name + "-" + "iamzhongyong";
}
});
System.out.println(cache.get(name));
//cache.invalidateAll();
}
}
缓存预热怎么搞?
A、全量预热,固定的时间段移除所有,然后再全量预热
适用场景:
1、数据更新不频繁,例如每天晚上3点更新即可的需求;
2、数据基本没有变化,例如全国区域性数据;
B、增量预热(缓存查询,没有,则查询数据库,有则放入缓存)
适用场景:
1、 数据更新要求缓存中同步更新的场景
集群内部,缓存的一致性如何保证?
如果采用ehcache的话,可以使用框架本身的JGroup来实现组内机器之间的缓存同步。
如果是采用google的cacheBuilder的话,需要自己实现缓存的同步。
A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新即可,然后定时程序定时去清理缓存;
B、需要实时生效数据:启动时可预热也可不预热,但是缓存数据变更后,集群之间需要同步
原文:/article/4429760.html
http://blog.sina.com.cn/s/blog_6940cab30102uwmh.html
java中的本地缓存,工作后陆续用到,一直想写,一直无从下手,最近又涉及到这方面的问题了,梳理了一下。自己构造单例、guava、ehcache基本上涵盖了目前的大多数行为了。
为什么要有本地缓存?
在系统中,有些数据,数据量小,但是访问十分频繁(例如国家标准行政区域数据),针对这种场景,需要将数据搞到应用的本地缓存中,以提升系统的访问效率,减少无谓的数据库访问(数据库访问占用数据库连接,同时网络消耗比较大),但是有一点需要注意,就是缓存的占用空间以及缓存的失效策略。
为什么是本地缓存,而不是分布式的集群缓存?
目前的数据,大多是业务无关的小数据缓存,没有必要搞分布式的集群缓存,目前涉及到订单和商品的数据,会直接走DB进行请求,再加上分布式缓存的构建,集群维护成本比较高,不太适合紧急的业务项目。
这里介绍一下缓存使用的三个阶段(摘自info架构师文档)
本地缓存在那个区域?
目前考虑的是占用了JVM的heap区域,再细化一点的就是heap中的old区,目前的数据量来看,都是一些小数据,加起来没有几百兆,放在heap区域最快最方便。后期如果需要放置在本地缓存的数据大的时候,可以考虑在off-heap区域(direct-memory 或者 big-memory),但是off-heap区域的话,需要考虑对象的序列化(因为off-heap区域存储的是二进制的数据),另外一个的话就是off-heap的GC问题。其实,如果真的数据量比较大,那其实就可以考虑搞一个集中式的缓存系统,可以是单机,也可以是集群,来承担缓存的作用。
搞一个单例模式,里面有个Map的变量来放置数据
关于单例模式,一个既简单又复杂的模式(http://iamzhongyong.iteye.com/blog/1539642)
非常典型的代码如下:
public class SingletonMap {
//一个本地的缓存Map
private Map localCacheStore = new HashMap();
//一个私有的对象,非懒汉模式
private static SingletonMap singletonMap = new SingletonMap();
//私有构造方法,外部不可以new一个对象
private SingletonMap(){
}
//静态方法,外部获得实例对象
public static SingletonMap getInstance(){
return singletonMap;
}
//获得缓存中的数据
public Object getValueByKey(String key){
return localCacheStore.get(key);
}
//向缓存中添加数据
public void putValue(String key , Object value){
localCacheStore.put(key, value);
}
}
这种能不能用?可以用,但是非常局限
但是这种的就是本地缓存了吗?答案显然不是,为啥呢?
1、 没有缓存大小的设置,无法限定缓存体的大小以及存储数据的限制(max size limit);
2、 没有缓存的失效策略(eviction policies);
3、 没有弱键引用,在内存占用吃紧的情况下,JVM是无法回收的(weak rererences keys);
4、 没有监控统计(statistics);
5、 持久性存储(persistent store);
所以,这种就直接废掉了。。。
引入EhCache来构建缓存(详细介绍: http://raychase.iteye.com/blog/1545906)
EhCahce的核心类:
A、CacheManager:Cache的管理类;
B、Cache:具体的cache类信息,负责缓存的get和put等操作
C、CacheConfiguration :cache的配置信息,包含策略、最大值等信息
D、Element:cache中单条缓存数据的单位
典型的代码如下:
public static void main(String[] args) {
//EhCache的缓存,是通过CacheManager来进行管理的
CacheManager cacheManager = CacheManager.getInstance();
//缓存的配置,也可以通过xml文件进行
CacheConfiguration conf = new CacheConfiguration();
conf.name("cache_name_default");//设置名字
conf.maxEntriesLocalHeap(1000);//最大的缓存数量
conf.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU);//设置失效策略
//创建一个缓存对象,并把设置的信息传入进去
Cache localCache = new Cache(conf);
//将缓存对象添加到管理器中
cacheManager.addCache(localCache);
localCache.put(new Element("iamzhongyong", new Date()));
System.out.println(localCache.getSize());
System.out.println(localCache.getStatistics().toString());
System.out.println(localCache.getName());
System.out.println(localCache.get("iamzhongyong").toString());
System.out.println(localCache.get("iamzhongyong").getObjectValue());
}
当然,Cache的配置信息,可以通过配置文件制定了。。。
优点:功能强大,有失效策略、最大数量设置等,缓存的持久化只有企业版才有,组件的缓存同步,可以通过jgroup来实现
缺点:功能强大的同时,也使其更加复杂
引入guava的cacheBuilder来构建缓存
这个非常强大、简单,通过一个CacheBuilder类就可以满足需求。
缺点就是如果要组件同步的话,需要自己实现这个功能。
典型的代码如下:
public class GuavaCacheBuilderTest {
public static void main(String[] args) throws Exception{
GuavaCacheBuilderTest cache = new GuavaCacheBuilderTest();
cache.getNameLoadingCache("bixiao");
}
public void getNameLoadingCache(String name) throws Exception{
LoadingCache cache = CacheBuilder.newBuilder()
.maximumSize(20)//设置大小,条目数
.expireAfterWrite(20, TimeUnit.SECONDS)//设置失效时间,创建时间
.expireAfterAccess(20, TimeUnit.HOURS) //设置时效时间,最后一次被访问
.removalListener(new RemovalListener() { //移除缓存的监听器
public void onRemoval(RemovalNotification notification) {
System.out.println("有缓存数据被移除了");
}})
.build(new CacheLoader(){ //通过回调加载缓存
@Override
public String load(String name) throws Exception {
return name + "-" + "iamzhongyong";
}
});
System.out.println(cache.get(name));
//cache.invalidateAll();
}
}
缓存预热怎么搞?
A、全量预热,固定的时间段移除所有,然后再全量预热
适用场景:
1、数据更新不频繁,例如每天晚上3点更新即可的需求;
2、数据基本没有变化,例如全国区域性数据;
B、增量预热(缓存查询,没有,则查询数据库,有则放入缓存)
适用场景:
1、 数据更新要求缓存中同步更新的场景
集群内部,缓存的一致性如何保证?
如果采用ehcache的话,可以使用框架本身的JGroup来实现组内机器之间的缓存同步。
如果是采用google的cacheBuilder的话,需要自己实现缓存的同步。
A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新即可,然后定时程序定时去清理缓存;
B、需要实时生效数据:启动时可预热也可不预热,但是缓存数据变更后,集群之间需要同步
原文:/article/4429760.html
相关文章推荐
- 如何通过2级缓存解决性能问题(ehcache)
- JNI学习笔记5——本地方法处理java数组/引用问题/缓存jfieldID/jmethodID
- 本地方法处理java数组/引用问题/缓存jfieldID/jmethodID
- XBRL官网不保证24X7可用,这就是为什么开发XBRL应用要建立Schema文件的本地缓存
- 回复:String中如果有中文,如何保证length()返回的长度 在 Java 中字符串是以 Unicode 方式编码的,所以,无论中英文都算的长度为 1。根据你的描述,估计是想要取得英文长度为 1 中文长度为 2 的总长度吧。这个,理论上可以构造 An
- Java初学者如何自学和自己定位解决问题 推荐
- java中关于构造函数内部调用自己的问题
- 关于Ehcache集群缓存在应用重启后的加载问题
- java打开本地程序,如何自己退出,在不影响
- ehcache缓存内存和硬盘问题-初学者(java)
- 问题:客户端从服务器分页获取列表,如何保证流量最少,且客户端和Server数据的一致性?
- 用EhCache缓存Shiro的本地会话,当用户没有安全退出就直接关闭浏览器,会话可能在缓存里孤立的问题。
- EhCache缓存在集群环境中同步问题
- 如何给web项目添加redis服务 JAVA几种缓存技术 ehcache和redis哪个更好
- 【java】:如何自己构造一个package(包)
- 如何获取网页验证码图片并保存到本地(Java实现) [问题点数:40分,结帖人lanxuezaipiao]
- 如何保证Java对象内部属性的不可变状态
- solr入门之设计自己的Java本地缓存工具类
- 牛客网Java刷题知识点之什么是内部类、为什么要使用内部类、内部类如何使用外部类的属性和方法、成员内部类、局部内部类、静态内部类、匿名内部类
- 如何比较Keras, TensorLayer, TFLearn ?——如果只是想玩玩深度学习,想快速上手 -- Keras 如果工作中需要解决内部问题,想快速见效果 -- TFLearn 或者 Tensorlayer 如果正式发布的产品和业务,自己设计网络模型,需要持续开发和维护 -- Tensorlayer