使用jedis连接redis-cluster模拟缓存击穿,穿透,雪崩场景

上一篇演示了通过redis实现ID生成器,本篇模拟缓存击穿,穿透,雪崩的场景。

package com.coderman.jedis.clusterdemo.hack;

import com.coderman.jedis.clusterdemo.ClusterTest;
import org.junit.Test;

/**
 * @Author fanchunshuai
 * @Date 2020/1/31 15
 * @Description:
 *  * 缓存穿透:
 *  参考 https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247486705&idx=2&sn=33f90d9606ad32384d351a2cc170ba2d&chksm=fb3f150acc489c1c967f2bb250d14c3e44d4f4f2dff6991f8315043ca247819b3bfd973650ef&mpshare=1&scene=1&srcid=&sharer_sharetime=1579147583247&sharer_shareid=9c9dad852994f99c77b36e07bf5e0634&key=e10552fbfdccf7e3c22c51843df41144e9c3289850973823df906830ec355cb3e209383648ee671a95a76047a8153bff8ebc315cdcb6a94cb28e546b334ff71bab7a01ea25dc2a703afcccd1ddd6d5fe&ascene=1&uin=MjYzNzcyMTYyNw%3D%3D&devicetype=Windows+10&version=6208006f&lang=zh_CN&exportkey=AQFkC39NhSkTnb6SD70SAfY%3D&pass_ticket=iG9ywRBijCrb47ifDs6%2B%2Fgz8gQXaPnoVEkBXC0Kvb1%2BAmKJ3ZR3f48KpJcp2%2BWKI
 *
 *  参考 https://blog.csdn.net/kongtiao5/article/details/82771694
 */
public class RedisHackTest extends ClusterTest {
    private static final String STAFF_PREFIX = "sso:staff:";
    /**
     * 缓存穿透测试
     *        缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,
     *        如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
     */
    @Test
    public void cacheThroughTest(){
        //假设缓存中就只有1000个key
        for (int i  = 1 ;i<1000;i++){
            String staffId = STAFF_PREFIX + i;
            cluster.set(staffId,"樊春帅"+i,"NX","EX",30);
        }

        Thread [] threads = new Thread[1000];
        //使用1000个线程访问一个不存在的key
        for (int i  = 0 ;i<1000;i++){
            Thread pop = new Thread(()->{
                for (int k = 0;k < 10000;k++){
                    //访问一个不存在的key
                    String notExitKey = STAFF_PREFIX +  1001;
                    String x = cluster.get(notExitKey);
                    System.out.println("x = "+x);
                    if(x == null  || "".equals(x)){
                        //db.get();
                    }
                }
            },"pop-"+i);
            threads[i] = pop;
        }

        for (int i  = 0 ;i<1000;i++){
            threads[i].start();
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 缓存击穿测试
     *       缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),
     *       这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
     * 我这边理解的具体场景有两种
     * 1.在高并发下某个key被突然访问,但是缓存中数据还没有建立起来,而数据库中可能有,此时会有大量请求走到DB
     * 2.在高并发下某个key失效后被突然访问,但是缓存中数据还没有建立起来,而数据库可能有,此时会有大量请求走到DB
     *
     * 突然成为热点key存在缓存击穿情况
     */
    @Test
    public void cacheBreakDownTest(){
        for (int i  = 1 ;i < 1000;i++){
            String staffId = STAFF_PREFIX + i;
            cluster.set(staffId,"樊春帅"+i,"NX","EX",30);
        }

        String key = STAFF_PREFIX + 1000;

        //设计1000个线程,突然在某一刻访问第1000个key,之前缓存中一直没有也没有建立起来,这里来演示这种情况
        Thread [] threads = new Thread[1000];
        for (int i  = 0 ;i<1000;i++){
            Thread pop = new Thread(()->{
                for (int k = 0;k < 10000;k++){
                    //访问一个缓存中不存在的key
                    String x = cluster.get(key);
                    System.out.println("x = "+x);
                    if(x == null  || "".equals(x)){
                        //很多请求查询db
                        //db.get();
                        //这里是数据库里有,所以会很快重建缓存
                        cluster.set(key,"冲冲冲","NX","EX",30);
                        //这里涉及到缓存失效后如何重建缓存,后面大家可以自行百度
                    }
                }
            },"pop-"+i);
            threads[i] = pop;
        }

        for (int i  = 0 ;i<1000;i++){
            threads[i].start();
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 缓存雪崩
     * 参考 https://www.jianshu.com/p/b880570a1545
     */
    @Test
    public void CacheAvalancheTest(){
        for (int i  = 1 ;i < 1000;i++){
            String staffId = STAFF_PREFIX + i;
            cluster.set(staffId,"樊春帅"+i,"NX","EX",30);
        }

        try {
            //休息30秒,让缓存过期
            Thread.sleep(30 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //所有缓存key都很快失效
        Thread [] threads = new Thread[1000];
        for (int i  = 0 ;i<1000;i++){
            Thread pop = new Thread(()->{
                for (int k = 1;k < 1000;k++){
                    String staffId = STAFF_PREFIX + k;
                    String x = cluster.get(staffId);
                    System.out.println("x = "+x);
                    if(x == null  || "".equals(x)){
                        //很多请求查询db
                        //db.get();
                    }
                }
            },"pop-"+i);
            threads[i] = pop;
        }

        for (int i  = 0 ;i<1000;i++){
            threads[i].start();
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值