Redis缓存问题—缓存穿透、缓存击穿与缓存雪崩

概述

  • Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存。
  • 在缓存使用的过程中也存在一些典型的问题:缓存击穿、缓存穿透、缓存雪崩
Redis缓存问题—缓存穿透、缓存击穿与缓存雪崩

缓存击穿

  • 缓存击穿,大并发集中对某一数据进行访问,并且缓存中不存在访问的数据(第一次访问或者缓存过期),持续的大并发就穿破缓存,直接请求数据库。
  • 双重检测锁机制(提升效率)
  • ItemService
<code>public Item queryItemById(String itemId){
Item item = itemCacheHander.getItemFromCache(itemId);
if(item == null) {
synchronized (this) {
item = itemCacheHander.getItemFromCache(itemId);
if (item == null) {
System.out.println("--------------查询数据库");
item = itemDAO.queryItem(itemId);
itemCacheHander.addItemToCache(item);
}
}
}
return item;
}/<code>

缓存穿透

  • 缓存穿透,是指查询一个数据库不存在的数据。首先查询缓存,缓存中不存在则查询数据库,数据查询到的数据依然为空,设置到缓存中也为空;因此后续所有对次数据的查询都会先查询缓存,缓存不存在继而又查询数据库。
  • 即使数据库查询为空,也向缓冲中写入非空值
  • ItemCacheHandler
<code>/**
* 存缓存
* @param item
*/
public void addItemToCacheEx(Item item){
String json = new Gson().toJson(item);
//设置过期时间
redisTemplate.boundValueOps("item-"+item.getItemId()).set(json,5);
}/<code>
  • ItemService
<code>public Item queryItemById(String itemId){
Item item = itemCacheHander.getItemFromCache(itemId);
if(item == null) {
synchronized (this) {
item = itemCacheHander.getItemFromCache(itemId);
if (item == null) {
System.out.println("--------------查询数据库");
item = itemDAO.queryItem(itemId);
// 如果从数据库查询信息为null,则创建一个对象写入到缓冲,并设置过期时间
if(item == null) {
item = new Item();
item.setItemId(itemId);
itemCacheHander.addItemToCacheEx(item);
}else {
itemCacheHander.addItemToCache(item);
}

}

}
}
return item;
}/<code>

缓存雪崩

  • 缓存雪崩,是指在某一个时间段,缓存集中过期失效,则大量的并发访问查询都落到了数据库上。
  • 例如马上就要到双十一零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。


分享到:


相關文章: