原创:https://www.cnblogs.com/andychou/p/8342007.html
为什么是本地缓存,而不是分布式的集群缓存?
目前的数据,大多是业务无关的小数据缓存,没有必要搞分布式的集群缓存,目前涉及到订单和商品的数据,会直接走DB进行请求,再加上分布式缓存的构建,集群维护成本比较高,不太适合紧急的业务项目。
本地缓存在那个区域?
目前考虑的是占用了JVM的heap区域,再细化一点的就是heap中的old区,目前的数据量来看,都是一些小数据,加起来没有几百兆,放在heap区域最快最方便。后期如果需要放置在本地缓存的数据大的时候,可以考虑在off-heap区域,但是off-heap区域的话,需要考虑对象的序列化(因为off-heap区域存储的是二进制的数据),另外一个的话就是off-heap的GC问题。其实,如果真的数据量比较大,那其实就可以考虑搞一个集中式的缓存系统,可以是单机,也可以是集群,来承担缓存的作用。
有哪些本地缓存:
EhCache来构建缓存、引入guava的cacheBuilder来构建缓存(
Guava Cache与ConcurrentMap很相似,但也不完全一样。
最基本的区别是ConcurrentMap会一直保存所添加的元素,直到显式的移除;
Guava Cache为了限制内存的占用,通常都是设定为自动回收元素。在某些场景下,尽管LoadingCahe不回收元素,但是它还是很有用的,因为它会自动加载缓存。
Guava Cache适用场景:
- 你愿意消耗一部分内存来提升速度;
- 你已经预料某些值会被多次调用;
- 缓存数据不会超过内存总量;
Guava Cache是一个全内存的本地缓存实现,它提供了线程安全的实现机制。整体上来说Guava cache 是本地缓存的不二之选,简单易用,性能好
)
集群内部,缓存的一致性如何保证?
如果采用ehcache的话,可以使用框架本身的JGroup来实现组内机器之间的缓存同步。
如果是采用google的cacheBuilder的话,需要自己实现缓存的同步。
A、非实时生效数据:数据的更新不会时时发生,应用启动的时候更新即可,然后定时程序定时去清理缓存;
B、需要实时生效数据:启动时可预热也可不预热,但是缓存数据变更后,集群之间需要同步
本地缓存?
一般来说我们可以直接使用jdk里提供的数据结构来作为缓存,但这样有个问题就是缓存的一些机制,比如缓存过期的淘汰策略,缓存的初始化,缓存最大容量的设置,缓存的共享等等一些列的问题需要自己去考虑和实现。
第二种方法就是我们可以使用一些业界开源的,成熟的一些第三方的工具来帮助我们实现缓存。这其中有:EHCache,cahce4j等等好多框架和工具。但从我使用的来看我认为google里guava包内的缓存工具是我使用过的最方便,简单的缓存框架。
下面就来介绍这个Guava包内的CacheBuilder。
注意:Guava Cache是单个应用运行时的本地缓存,单机版的缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached或Redis;
@Component
public class LocalCache {
private static final CopyOnWriteArraySet<Integer> COPY_ON_WRITE_ARRAY_SET = new CopyOnWriteArraySet<>();
private static final Cache<String, Object> CACHE = CacheBuilder.newBuilder().build();
public void cache(String key, Object value) {
CACHE.put(key, value);
}
public Object getCache(String key) {
Object value = CACHE.getIfPresent(key);
CACHE.invalidate(key);
return value;
}
public void putSet(int type) {
COPY_ON_WRITE_ARRAY_SET.add(type);
}
public boolean ifExist(int type) {
return COPY_ON_WRITE_ARRAY_SET.contains(type);
}
public boolean removeSet(int type) {
return COPY_ON_WRITE_ARRAY_SET.remove(type);
}
public static CopyOnWriteArraySet<Integer> getCopyOnWriteArraySet() {
return COPY_ON_WRITE_ARRAY_SET;
}
}
@Slf4j
public class LocalCacheLock {
private String lockKey;
private Object lock;
private static Cache<String, Object> cache = CacheBuilder.newBuilder().build();
public LocalCacheLock(int s1, int s2) {
this.lockKey = s1 + "--" + s2;
Object value = cache.getIfPresent(lockKey);
if (value == null) {
this.lock = s1 + "--" + s2;
cache.put(lockKey, this.lock);
} else {
this.lock = value;
}
}
public void lock() {
synchronized (lock) {
try {
lock.wait(5000);
} catch (InterruptedException e) {
log.error("thread was interrupted:", e);
}
}
}
public void unLock() {
synchronized (lock) {
lock.notifyAll();
}
}
public String getLockKey() {
return lockKey;
}
}
简单使用:
localCache.putSet(key);
LocalCacheLock lock = new LocalCacheLock( aaaa, bbbb);
// 业务代码
。。。。
lock.lock(); // 锁定等待
localCache.getCache(lock.getLockKey());