zoukankan      html  css  js  c++  java
  • 使用redis做数据缓存时存在的问题

    缓存击穿

    大量并发请求同时访问一个在redis中不存在的数据时,就会绕过redis去直接访问底层数据库,对数据库造成极大的访问压力

    解决方案

    使用双重检测锁

    缓存穿透

    当请求访问redis中的某个资源时,若返回的结果为null,则会绕过redis去访问底层数据库,若底层数据库中没有相关数据,则返回结果仍然是null,且底层数据库会将null写入redis中,但由于redis中的数据也是null,redis就失去了缓存的作用,后续并发请求仍然会去访问底层数据库,给数据库造成了访问压力

    解决方案

    若底层数据库中也没有对应数据,则不要返回null,可以返回一个非正常数值或是一个空集合并写入redis中,且写入redis中的无用数据可以设置一个较短的过期时间。如此一来,后续的请求则会直接从redis中获取数据(只不过获得的数据也是无用的)

    缓存雪崩

    redis中的数据在同一时刻大量过期,导致请求这些数据的大量并发请求绕过redis去访问底层数据库,对数据库造成访问压力。

    解决方案

    • 为redis中的数据设置不同的过期时间
    • 在流量洪峰到达前提前缓存热点数据,过期时间设置到流量最低的时段

    项目中的一个代码片段

    public ResultVO listIndexImgs() {
            List<IndexImg> indexImgs = null;
            try {
                //尝试从redis中查询轮播图信息,可能查不到
                String imgsStr = stringRedisTemplate.boundValueOps("indexImgs").get();
                if (imgsStr != null) {
                    //从redis中查询到轮播图信息
                    //代码含义:将json字符串转换为ArrayList集合,
                    JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                    //readValue 方法可以将json字符串转换成指定的对象
                    indexImgs = objectMapper.readValue(imgsStr, javaType);
                } else {
                    //双重检测锁
                    synchronized (this){
                        //再次查询redis(防止缓存击穿)
                        String s = stringRedisTemplate.boundValueOps("indexImgs").get();
                        if (s==null){
                            //高并发访问的第一次访问会进入此处
                            indexImgs = indexImgMapper.listIndexImgs();
                            if(indexImgs!=null){
                                stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(indexImgs));
                                stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.DAYS);
                            }else {
                                //防止缓存穿透
                                List<IndexImg> nullImgsList = new ArrayList<>();
                                stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(nullImgsList));
                                stringRedisTemplate.boundValueOps("indexImgs").expire(10, TimeUnit.SECONDS);
                            }
                        }else {
                            //高并发对同一资源的后续访问会进入这,即后续会直接从redis中查找数据
                            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                            indexImgs = objectMapper.readValue(s, javaType);
                        }
                    }
                }
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
    
            if (indexImgs!=null){
                return new ResultVO(ResStatus.OK,"success",indexImgs);
            }else {
                return new ResultVO(ResStatus.NO,"fail",null);
            }
    
        }
    
  • 相关阅读:
    LeetCode 226. Invert Binary Tree
    LeetCode 221. Maximal Square
    LeetCode 217. Contains Duplicate
    LeetCode 206. Reverse Linked List
    LeetCode 213. House Robber II
    LeetCode 198. House Robber
    LeetCode 188. Best Time to Buy and Sell Stock IV (stock problem)
    LeetCode 171. Excel Sheet Column Number
    LeetCode 169. Majority Element
    运维工程师常见面试题
  • 原文地址:https://www.cnblogs.com/whyblogs/p/15064432.html
Copyright © 2011-2022 走看看