谈到redis缓存,那么什么样的数据适合缓存呢?
分析一个数据是否适合缓存,我们要从访问频率、读写比例、数据一致性等要求去分析.
那么什么又是缓存击穿呢(服务器宕机不在此讨论范围中,服务高可用)?
在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,缓存失去存在的意义。
如何解决呢?
一般情况下,加锁访问数据库,伪代码如下
static Lock reenLock = new ReentrantLock();
//最后使用互斥锁的方式来实现.
public List<String> getData() throws InterruptedException {
List<String> result = new ArrayList<String>();
// 从缓存读取数据
result = getDataFromCache();
if (result.isEmpty()) {
if (reenLock.tryLock()) {
try {
System.out.println("我拿到锁,从DB获取数据库后写入缓存");
// 从数据库查询数据
result = getDataFromDB();
// 将查询到的数据写入缓存
setDataToCache(result);
} finally {
reenLock.unlock();// 释放锁
}
} else {//我没有拿到锁
result = getDataFromCache();// 先查一下缓存
if (result.isEmpty()) {
System.out.println("我没拿到锁,缓存也没数据,等一下");
Thread.sleep(100);//
return getData();// 递归调用重试
}
}
}
return result;
}
或者采用, 队列的方式保证缓存的单线程(进程)写,写数据时加一个标识到队列中,下一个线程过来发现队列有值,不查询数据库,延时再次调用方法。
首先预防高并发访问数据库,防止缓存数据失效:
对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免对底层存储系统的查询压力。一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短。热点数据定时更新,过期时间分散开。预防后,高并发下缓存失效该如何处理呢?
一,首先
对于,缓存对象key不变的,value值是变动的,
1,比如说网页首页要展示的一些大广告推广,这些推广是会一直展示的,但数目一段时间内是有限制的,不会一直更新,展示时间也会有条件限制,更新频率半个小时,具体时间或者实时性可根据业务自行决定,某一段时间,此缓存失效,但并发量高,访问数据库,加锁瞬间影响性能,比如秒杀活动,可用双缓存策略,俩服务布双份数据,也就是再加一个缓存服务器,此备用的缓存服务,定时更新若场景为秒杀,可适当多频率同步。主服务缓存失效后,访问备用的缓存服务器,然后更新主服务器缓存,修改主服务器缓存数据。主缓存服务器过期时间短,备用过期时间长点。