春招之-Redis篇(1)

文章介绍了基于session和Redis的登录机制,强调了使用Redis存储验证码和token的优缺点,讨论了缓存问题如穿透、雪崩和击穿的解决方案,以及如何使用全局唯一ID生成算法RedisIdWorker进行高效并发测试。
摘要由CSDN通过智能技术生成

1、基于session登录,不需要返回用户凭证,因为session有sessionID,全局唯一,前端的JSESSIONID就是凭证。缺点:如果换了tomcat服务器,会消失凭证,解决方法:使用Redis,达到全局唯一

2、基于Redis存储验证码,key:value对应手机号(不推荐):验证码,分别有String用JSON保存,和Hash结构:field:value

3、最佳实践,用token作为key,value存储用户信息,前端每次请求携带token,从token返回用户数据,

4、写操作:先操作数据库,再删除缓存

缓存穿透:

解决方案:

1、缓存空对象

2、布隆过滤器:先于redis,如果key不存在,直接拒绝

缓存雪崩:

解决方案:

1、设置随机TTL

2、多级缓存

缓存击穿:

部分key(热点且恢复复杂)过期,缓存重建应该只由第一个访问的线程进行重建(通过加锁进行互斥),并把key设置为逻辑过期

1、解决方案:

线程一访问数据,发现逻辑过期,获取锁,读取旧数据后,新建线程二,让线程二进行缓存重建,其他线程发现逻辑过期,并且获取锁失败,则读取旧数据

全局唯一ID:

1、主键不采用自增长,因为容易被猜测

2、用64个bit位,即Long型,存储:符号位(1),时间戳(31)和序列号(32)

RedisIdWorker类

   /**
     * 开始的时间戳,2024-2-5
     */
    private final static long BEGIN_TIMESTAMP = 1707091200L;

    /**
     * 序列号位数
     */
    private final static int COUNT_BITS=32;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    public long nextId(String keyPrefix){
        //生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond-BEGIN_TIMESTAMP;

        //生成序列号
        //获取当天日期
        String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
        //拼接并返回
        return timestamp<<COUNT_BITS | count;
    }

测试:

    @Autowired
    RedisIdWorker redisIdWorker;

    private ExecutorService es = Executors.newFixedThreadPool(500);

    @Test
    void test3() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(300);
        Runnable task = ()->{
            for (int i = 0; i < 100; i++) {
                long id = redisIdWorker.nextId("order");
                System.out.println("id="+id);
            }
            latch.countDown();
            //每次减一
        };
        long begin = System.currentTimeMillis();
        for (int i = 0; i < 300; i++) {
            es.submit(task);
        }
        latch.await(); //等300减完再唤醒线程
        long end = System.currentTimeMillis();
        System.out.println("time="+(end-begin));
    }

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值