本部分,缓存实现了如下功能
缓存置入 缓存获取 缓存过期 缓存情空 缓存覆盖(实现用户自定义和默认配置)
缓存类型 | 概述 |
---|---|
边缘缓存 | https://www.jianshu.com/p/73034ee83f39,https://blog.csdn.net/weixin_43700280/article/details/85009717 |
页面缓存 | 动态语言生成的静态代码比如,php,jsp等 |
数据库缓存 | https://www.cnblogs.com/hadley/p/9557596.html 预留缓存Cache-aside,Read-through,write-through |
应用缓存 | 不管是本地内存还是磁盘,其速度快,成本低,在有些场合非常有效;分布式缓存这种东西存在的目的就是为了提供比RDB更高的TPS和扩展性,同时有帮你承担了数据同步的痛苦;优秀的分布式缓存系统有大家所熟知的Memcached、Redis(当然也许你把它看成是NoSQL,但是我个人更愿意把分布式缓存也看成是NoSQL),还有国内阿里自主开发的Tair等; |
平台级缓存框架 | https://blog.csdn.net/frankenjoy123/article/details/57952492;https://blog.csdn.net/d12345678a/article/details/77837039;https://blog.csdn.net/zjttlance/article/details/80234341 |
Web代理 | http://www.people.com.cn/GB/channel5/569/20000731/166044.html |
应用级缓存 | http://www.importnew.com/21570.html; |
nginx本地缓存,抗的是热数据的高并发访问。我们以电商为例,一般来讲,商品的购买总是有热点的,比如访问某些知名品牌的次数会比小众品牌次数多。这些热数据,由于经常被访问,我们可以利用nginx本地缓存。由于nginx本地内存有限,我们只cache住部分热数据,其余不怎么热的数据,流量可以走redis。
redis大规模分布式缓存集群,抗的是很高的离散访问,支撑海量的数据,高并发的访问,提供高可用的服务。
tomcat 的jvm堆内存缓存,主要是抗redis大规模灾难(比如雪崩),如果redis出现了大规模的宕机,导致nginx大量流量直接涌入数据生产服务,那么最后的tomcat堆内存缓存至少可以再抗一下,不至于让数据库直接裸奔。同时tomcat jvm堆内存缓存,也可以抗住redis没有cache住的最后那少量的部分缓存。
分布式缓存可采用Redis、MemCache等来实现,在没有Redis之前,如何保证集群共用一份缓存呢,在我理解,单独设计缓存集群服务器,所有的访问都可通过RPC机制去获取数据是否存在,带来的问题是高频读取,读压力的问题,可以通过负载均衡等手段实现。
在本部分所做的缓存设计属于单服务器缓存,主要用来管理和减轻由java生成的代码级缓存的读操作压力,应属于jvm堆内存部分。
缓存预热、缓存穿透、缓存雪崩,缓存更新以后梳理。本部分只介绍框架设计。
核心:接口设计-可配置设计-多并发机制处理设计
基础接口设计
put 用于置入缓存对象、get用于获取缓存对象、Remove用于移除缓存对象、RemoveAll用于将缓存清空。
配置接口,setExpiredTime设置过期时间、isCover设置是否覆盖,true覆盖同key值缓存对象,false不覆盖同key值缓存对象。
为什么需要设计是否覆盖这个问题,由于在一定时间内,重复key的数据如果value不一致,会导致缓存的结果查询不一致。
主要应用场景,缓存优先。先产生的数据起效场景,当然这种可以用队列来做,FIFO。针对短期有效数据通过缓存来设计,比如2分钟内抢蛋糕时间,有10个蛋糕100个人抢,假如A蛋糕20个去预定,那么只有第一个起效。
package com.hecore.cache.core;
import com.hecore.cache.iface.IHecoreCache;
import com.hecore.cache.pojo.CacheConf;
import com.hecore.cache.pojo.CacheObj;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
/**
* IHecoreCache 接口的默认实现,可用于单实例(注意多线程将会造成数据的不正确).
* 1.构造类实现定时清理功能,生命周期。
*/
public class HecoreCache implements IHecoreCache{
/**
* 安全的并发包
*/
private ConcurrentHashMap map=new ConcurrentHashMap<>();
private int interval= 90 * 1000;
private Timer timer;
private CacheConf conf=null;
public HecoreCache(CacheConf conf){
this.conf=conf;
CacheObj.DEFAULT_EXPIRE_TIME=conf.setExpiredTime(conf);
timerClearMap();
}
private void timerClearMap() {
timer = new Timer("HecoreCache", true);
timer.schedule(
new TimerTask() {
public void run() {
for (Map.Entry e : map.entrySet()) {
if (e.getValue().isExpired()) {
map.remove(e.getKey());
}
}
}
},
interval,
interval
);
}
/**
* 防止覆盖,保证数据的一致性
* @param cacheObj
*/
@Override
public void put(CacheObj cacheObj) {
if(conf.isCover(conf)){
map.put(cacheObj.getKey(),cacheObj);
}else{//不覆盖
if(!map.containsKey(cacheObj.getKey())){
map.put(cacheObj.getKey(),cacheObj);
}
}
}
/**
* @param key 为null 不应当存在于map中,属于无效值
* @return
*/
@Override
public CacheObj get(String key) {
return key!=null?map.get(key):null;
}
@Override
public void remove(String key) {
map.remove(key);
}
@Override
public void removeAll() {
map.clear();
}
/**
* 防止再次加载造成数据重复
* @param key
* @return
*/
public boolean contains(String key) {
return map.containsKey(key);
}
}
package com.hecore.cache.manager;
import com.hecore.cache.core.HecoreCache;
import com.hecore.cache.exception.HecoreExceotion;
import com.hecore.cache.iface.IHecoreCache;
import com.hecore.cache.pojo.CacheConf;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 用于多实例并发处理,保证只有唯一一个HecoreCache.
*/
public class HecoreCacheManager {
private static HecoreCacheManager me=new HecoreCacheManager();
// 类锁,如果作为静态变量就变成了类实例锁。那么每个线程进入都会等待全局的lock释放锁.,每时每刻只有一个线程会获取到。
private Lock lock=new ReentrantLock();
public HecoreCacheManager() {
if(conf==null){
lock.lock();
conf=new CacheConf(360,true);
lock.unlock();
}
}
public HecoreCacheManager(CacheConf conf) {
this.conf = conf;
this.conf=conf;
}
private CacheConf conf=null;
// 解决内存可见性问题,在什么场景下出现
private volatile IHecoreCache iHecoreCache=null; // 设置为volatile 并发过程中线程可见。
private void setHecoreCache(IHecoreCache iHecoreCache){
if (iHecoreCache == null)
throw new HecoreExceotion("null exception");
this.iHecoreCache=iHecoreCache;
}
public IHecoreCache getiHecoreCache(){
if (iHecoreCache == null){
lock.lock();
if (iHecoreCache==null)
iHecoreCache=new HecoreCache(conf);
lock.unlock();
}
return iHecoreCache;
}
}
HecoreCacheManager hcm=new HecoreCacheManager(new CacheConf(180,false));
IHecoreCache iHecoreCache=hcm.getiHecoreCache();
iHecoreCache.put(new CacheObj("hecore","234"));
iHecoreCache.put(new CacheObj("hecore","123"));
System.out.println(iHecoreCache.get("hecore"));
当
HecoreCacheManager hcm=new HecoreCacheManager(new CacheConf(180,true));
测试结果为 hecore:123