文章开始之前先做个找工作的介绍吧,由于这次疫情影响,我一个UI朋友的公司破产之后他现在处于找工作阶段,一直没有找到自己合适的,三年工作经验左右,坐标深圳,如果有招UI的朋友可以联系我。
作品: http://yiming.zcool.com.cn/
目录
缓存是互联网开发中必不可少的一部分,它能降低我们数据库的并发数,提高我们系统的性能,比如我们经常使用的redis、emCached等等,其中redis应该是大部分的人选,为什么?因为速度快,易上手,是很多开发者的首选,但是缓存同样存在这问题,如果使用的不恰当,也可能会造成非常严重的后果,这时候你可能就会有疑问,缓存只是存储一些数据而已,怎么会造成严重的后果呢?下面我就带大家一起来分析分析。
什么是缓存
缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。
比如我们的redis、他就是缓存中比较常见的一种,他的并发读写能力能达到10w/s左右的速度,这个速度是相当不错的,相对于传统的数据存储来说,比如数据库,快了不知道多少倍,传统的数据库(mysql)操作的都是磁盘,而redis操作的是内存(ram),所以他们的速度肯定是没法比较的,由于传统数据库的读写较慢,所以并发较高的时候就会造成性能瓶颈问题,这也是为什么需要引入缓存的原因之一。
人在地上走,锅从天上来
我是一个快乐的程序狗,每天最快乐的事情就是codding,最大的愿望就是能准时6点下班,然后回家,但是今天肯定是走不了了,现在是17:30,我们的测试小哥哥给我提了一个很诡异的bug,难受啊,我的准时下班梦,但是作为一个程序狗,肯定都有着一颗和bug战斗到底的决心,究竟是什么bug呢?
bug是这样的:并发请求订单信息,没过几秒就抛出系统错误。这个bug看着没几个字,但是一看就知道不好解决,尤其是像这种并发bug,能让人瞬间白了头,随后我找到了测试,让他们复现了这个神秘的bug,而我也找到了产生这个bug的来源,并且快速的修复了他,到底是什么问题呢?是因为小明(同事)在编写代码的时候考虑的不是很周全导致的,所以开发一定要想仔细了再动手,否则吃亏的就是自己啊。
缓存穿透
什么是缓存穿透
缓存穿透指的是:同一时刻,大量的并发请求数据库中不存在的信息,他既不会命中缓存,也不会命中数据库,但是他会查找数据库。
上面的bug也是因为它产生的,测试的小哥哥查询的订单都是数据库不存在的,所以这个时候这些并发请求都不会命中缓存(redis),将直达数据库(mysql),由于大量的并发请求到达数据库,而数据库承受不住这么高的并发,从而导致数据库奔溃,这就是缓存穿透。
重现bug
1.新建数据表:订单表,结构如下:
2.编写测试代码
OrderBo.java
package com.ymy.bo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class OrderBo implements Serializable {
/**
* 自增id
*/
private Long id;
/**
*订单编号
*/
private Long orderCode;
/**
*订单价格
*/
private BigDecimal orderPrice;
/**
*商品名称
*/
private String peoductName;
/**
*创建时间
*/
private String createTime;
}
OrderController.java
package com.ymy.controller;
import com.ymy.bo.OrderBo;
import com.ymy.service.OrderService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
private OrderService orderService;
public OrderController(OrderService orderService){
this.orderService = orderService;
}
@RequestMapping(value = "/detail",method = RequestMethod.GET)
public OrderBo getDetail(@RequestParam("id") Long id){
return orderService.getDetail(id);
}
}
OrderService.java
package com.ymy.service;
import com.ymy.bo.OrderBo;
import com.ymy.mapper.OrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class OrderService {
private RedisTemplate redisTemplate;
private OrderMapper orderMapper;
public OrderService(RedisTemplate redisTemplate,OrderMapper orderMapper){
this.redisTemplate = redisTemplate;
this.orderMapper = orderMapper;
}
/**
* 通过id查询订单详情
* @param id
* @return
*/
public OrderBo getDetail(Long id) {
//缓存中查询词词订单
OrderBo orderBo = (OrderBo) redisTemplate.opsForValue