zoukankan      html  css  js  c++  java
  • 高并发下redis缓存穿透问题解决方案

    一、使用场景

      我们在日常的开发中,经常会遇到查询数据列表的问题,有些数据是不经常变化的,如果想做一下优化,在提高查询的速度的同时减轻数据库的压力,那么redis缓存绝对是一个好的解决方案。

    二、需求

      假设有10000个请求,想达到第一次请求从数据库中获取,其他9999个请求从redis中获取这种效果。

    三、代码实现

    3.1、常规写法

    public List<UsersDO> getAllUserWithNoPage2(){
            try{
    
                //序列化器,将key的值设置为字符串
                RedisSerializer redisSerializer=new StringRedisSerializer();
                redisTemplate.setKeySerializer(redisSerializer);
    
                //查缓存
                List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers");
    
                if(null==list){
    
                    UsersQuery query=new UsersQuery();
                    list=usersDOMapper.selectByExample(query);
                    redisTemplate.opsForValue().set("allUsers", list);
                    System.out.println("从数据库中取数据");
                }
                else{
                    System.out.println("从缓存中取数据");
                }
                return list;
            }
            catch (Exception e) {
                logger.error("UserService.getAllUserWithNoPage error",e);
            }
            return null;
        }
    

      常规的这种写法单线程没有问题,但是考虑到并发的存在,就会出现缓存渗透的问题,也就是不能保证其他9999个请求都是从redis中取。

    3.2、常规写法压测

    @GetMapping(value = "/test2")
        public String  test2(){
            ExecutorService executorService= Executors.newFixedThreadPool(20);
    
            for(int i=1 ; i<=10000;i++){
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        userService.getAllUserWithNoPage2();
                    }
                });
            }
    
            return "test over";
        }
    

    3.3、常规写法压测结果

    3.4、常规写法的改进,使用双重检测锁

    public List<UsersDO> getAllUserWithNoPage(){
    
    
            try{
    
                //序列化器,将key的值设置为字符串
                RedisSerializer redisSerializer=new StringRedisSerializer();
                redisTemplate.setKeySerializer(redisSerializer);
    
                //查缓存
                List<UsersDO> list=(List<UsersDO>)redisTemplate.opsForValue().get("allUsers");
    
                if(null==list){
                    //双重检测 锁
                    synchronized (this) {
    
                        List<UsersDO> list1 = (List<UsersDO>) redisTemplate.opsForValue().get("allUsers");
                        if (null == list1) {
    
                            UsersQuery query=new UsersQuery();
                            list=usersDOMapper.selectByExample(query);
                            redisTemplate.opsForValue().set("allUsers", list);
    
                            System.out.println("从数据库中取数据");
                        }
                        else{
                            System.out.println("从缓存中取数据");
                        }
                    }
                }
                else{
                    System.out.println("从缓存中取数据");
                }
                return list;
            }
            catch (Exception e) {
                logger.error("UserService.getAllUserWithNoPage error",e);
            }
            return null;
        }
    

    3.5、双重检测锁压测

    @GetMapping(value = "/test")
        public String  test(){
            ExecutorService executorService= Executors.newFixedThreadPool(20);
    
            for(int i=1 ; i<=10000;i++){
    
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        userService.getAllUserWithNoPage();
                    }
                });
            }
    
            return "test over";
        }
    

    3.6、双重检测锁压测结果

    压测结果符合要求。

    完整代码已上传Github :传送门

  • 相关阅读:
    hadoop再次集群搭建(3)-如何选择相应的hadoop版本
    48. Rotate Image
    352. Data Stream as Disjoint Interval
    163. Missing Ranges
    228. Summary Ranges
    147. Insertion Sort List
    324. Wiggle Sort II
    215. Kth Largest Element in an Array
    快速排序
    280. Wiggle Sort
  • 原文地址:https://www.cnblogs.com/geekdc/p/9256515.html
Copyright © 2011-2022 走看看