Redis基础及其分布式锁

Redis基础

redis是一个分布式的缓存技术,采用key-value对数据进行存储,它的数据类型主要分为5种:

  • String
  • Hash
  • List
  • Set
  • ZSet
    在日常开发中,redis是十分重要的,是一种面向NoSql的存储结构,也可用作快存快取的缓存场景。

Redis整合springBoot

配置

  • 引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 配置yml文件
spring:
  redis:
    host: 127.0.0.1
    port: 6379

应用

在Java中操作redis时一般采用的是RedisTemplate,这个类主要有以下几种方法:

  • redisTemplate.opsForValue();//操作字符串
  • redisTemplate.opsForHash();//操作hash
  • redisTemplate.opsForList();//操作list
  • redisTemplate.opsForSet();//操作set
  • redisTemplate.opsForZSet();//操作有序set

代码示例

 private String selectByRedis() {
        String s = redisTemplate.opsForValue().get("spuModel");
        if (StringUtils.isEmpty(s)) {
            //查询数据库
            //查询完后存入redis
            List<SpuEsModel> spuEsModels = selectByDb();
            s = JSON.toJSONString(spuEsModels);
            redisTemplate.opsForValue().set("spuModel", s);
            return s;
        }
        return s;
    }

缓存失效

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

  • 解决
    缓存空对象、布隆过滤器、mvc拦截器
缓存雪崩

缓存雪崩是指在我们设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。

  • 解决
    规避雪崩:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
    如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中。
    设置热点数据永远不过期。
    出现雪崩:降级 熔断
缓存击穿

缓存雪崩和缓存击穿不同的是:

  • 缓存击穿 指 并发查同一条数据。缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
  • 缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决

  • 设置热点数据永远不过期。
  • 加锁

分布式锁

如果redis中没有相应的key,就需要去查询DB, 但是在分布式场景下,多台机器发送请求同时去查询DB可能会造成负载飙高,所有就需要进行加入redis分布式锁进行处理。也就是不同的机器同时去竞争锁,先拿到锁的机器去查询数据库并设置缓存,这样就节省了很大的时间以及空间。

  • redis分布式锁:Set NX
    APISET key value [EX seconds] [PX milliseconds] [NX|XX]
  • 业务场景图:

在这里插入图片描述

  • 代码实例
 //redis分布式锁
    private String selectByRedisLock() throws InterruptedException {
        String uuid = UUID.randomUUID().toString();
        //給redis设置分布式锁并设置过期时间
        boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);
        if (lock) {
            //已经拿到锁了
            //利用LUA脚本删除锁
            String s = null;
            try {
                //设置redis缓存
                List<SpuEsModel> spuEsModels = selectByDb();
                s = JSON.toJSONString(spuEsModels);
            } finally {
                //无论成功与否,都要把锁删除,利用LUA脚本
                // get和delete原子操作
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                stringRedisTemplate.execute(
                        new DefaultRedisScript<Long>(script, Long.class), // 脚本和返回类型
                        Arrays.asList("lock"), // 参数
                        uuid); // 参数值,锁的值
            }
            return s;
        } else {
            //自旋锁。重试获取锁
            //先等待200毫秒再进行自旋
            Thread.sleep(200);
            selectByRedisLock();
        }
        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个在努力为老板实现梦想的搬砖工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值