redis,缓存 bilibili

在这里插入图片描述
这个锁必须是分布式锁,,防止各个微服务并发,并且可以使不同的key对应不同的锁,,单纯用sychrnized并发不行

在这里插入图片描述
Wath Dog的自动延期机制
如果拿到分布式锁的节点宕机,且这个锁正好处于锁住的状态时,会出现锁死的状态,为了避免这种情况的发生,锁都会设置一个过期时间。这样也存在一个问题,加入一个线程拿到了锁设置了30s超时,在30s后这个线程还没有执行完毕,锁超时释放了,就会导致问题,Redisson给出了自己的答案,就是 watch dog 自动延期机制。
Redisson提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期,也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁超时时间,锁不会因为超时而被释放。
默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。另外Redisson 还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。
3.源码解读
其实要想对一个框架深刻的了解,主要还是多看源码,目前的Redisson的源码版本基于:3.16.4,同时需要注意的是:

watchDog 只有在未显示指定加锁时间(leaseTime)时才会生效。(这点很重要)
在这里插入图片描述
watchDog并不是全部lock都生效,而是lock没设置过期时间的那些锁才会开启watchDog续期,没设置过期时间的话默认采取的是watchDog的30s过期时间。如果调用lock(time,unit)是不会开启watchDog线程续期的,是有可能造成线程不安全的。
续期是段lua脚本。
续期线程会在续期时间超过三分之一的时候执行。

冷热数据分离

在这里插入图片描述
读一个数据,并同时给他续命,这样热点数据就可以活久点
在这里插入图片描述
为了防止缓存穿透,黑客攻击,对库中取不到的缓存个空值。

突然冷门数据火起来了
突发性热点数据导致的缓存重建,而缓存中没有数据,导致大量请求涌入数据库,此时可以加锁(分布式锁,不同key用不同锁),只让第一个请求能成功,并采用double-check,进入锁里先查一次缓存,再去数据查
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

redis的LRU算法如何实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Redis 脑裂
如果当前主库突然出现暂时性 “失联”,而并不是真的发生了故障,此时监听的哨兵会自动启动主从切换机制。当这个原始的主库从假故障中恢复后,又开始处理请求,但是哨兵已经选出了新的主库,这样一来,旧的主库和新主库就会同时存在,这就是脑裂现象。
当主从切换后,从库升级为新主库,原主库和新主库会重新进行数据的全量同步,在这个过程中会发生数据的丢失
在这里插入图片描述
redis CPU飙升
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
优化
在这里插入图片描述
在这里插入图片描述
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

批量操作在发送 EXEC 命令前被放入队列缓存。
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行会经历以下三个阶段:

开始事务。
命令入队。
执行事务。
一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令。
在这里插入图片描述
1.如果在我们执行事务的时候,出现了语法错误,那么整个事务都不会被执行了。
2.执行事务时,出现运行错误我们让一个字符串自增,也就是执行 INCR 命令,这样肯定会出现错误,但是事务的其他语句还是正常执行了 。

利用redis做分布式锁

String productKey = "pro:detail:" + id;
    String productLockKey = "pro:detail:lock:" + id;
    //从缓存中获取数据
    String resultStr = redisUtil.get(productKey, String.class);
    //缓存中没有拿到数据,去数据库中拿取数据
    if (StringUtils.isEmpty(resultStr)) {

        /*存在问题:
            1、锁没有设置过期时间,那么当程序宕机时,将永远不会释放
            2、可能会删除别人的锁*/
        //进数据库获取数据
        String value = UUID.randomUUID().toString();
        try {
            //尝试加锁
            //boolean ifAbsent = redisUtil.setIfAbsent(key, null);
            boolean ifAbsent = redisUtil.setIfAbsent(
            productLockKey, value, 1000, TimeUnit.SECONDS);
            if (ifAbsent) {
                System.out.println("从数据库中获取数据......");
                resultStr = "商品详情:查询数据库";
                //拿到数据后去将该数据放入缓存中
                redisUtil.set(productKey, resultStr + "存入缓存中!");
            } else {
                Thread.sleep(5000);
                //开启自旋
                this.redisLock(id);
            }
        } finally {
            if (value.equals(redisUtil.get(productLockKey))) {
                //释放锁
                redisUtil.del(productLockKey);
            }

        }
    } else {
        resultStr = "商品详情:查询缓存";
    }
    return resultStr;
}

Redission实现分布式锁

//缓存中没有拿到数据,去数据库中拿取数据
if (StringUtils.isEmpty(resultStr)) {
    RLock lock = redisson.getLock(productLockKey);
    try {
        if (lock.tryLock(0, 5, TimeUnit.SECONDS)) {

            System.out.println("从数据库中获取数据......");
            resultStr = "商品详情:查询数据库";
            //拿到数据后去将该数据放入缓存中
            redisUtil.set(productKey, resultStr + "存入缓存中!");
        } else {
            Thread.sleep(5000);
            this.redissionLock(id);
        }
    } finally {
        //判断该lock是否已经锁
        if (lock.isLocked()) {
            //判断锁是否是自己的
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
} else {
    resultStr = "商品详情:查询缓存";
}

redission首先获取锁(get lock()),然后尝试加锁,加锁成功后可以执行下面的业务逻辑,执行完毕之后,会释放该分布式锁。
redission解决了redis实现分布式锁中出现的锁过期问题,还有释放他人的锁:它的内部机制是默认锁过期时间是30s,然后会有一个定时任务在每10s去扫描一下该锁是否被释放,如果没有释放那么就延长至30s,这个机制就是看门狗机制。
如果请求没有获取到锁,那么它将while循环获取继续尝试加锁。
redission实际还存在一个问题,就是当redis是主从架构时,线程A刚刚成功的加锁在了master节点,还没有同步到slave节点,此时master节点给挂了,然后线程B这时过来是可以加锁的,但是实际上它已经加锁过了,这就是所出现的问题,这个问题涉及了高一致性 ,也就是C原则了;redission是无法解决高一致性问题的。
如果想要解决高一致性可以使用红锁,或者zk锁;他们保证了高一致性,但是不建议使用,因为为了保证高一致性,它丢失了高可用性,对用户体验感不好,且出现上述问题出现几率不大,不能因为这种很小的问题出现几率而舍弃其高可用性。

Jedis与Redisson对比
Jedis技术特点
比较全面支持redis命令
支持Redis cluster
支持sentinel哨兵模式
使用阻塞的I/O,同步调用(即当前jedis与redis数据库获取连接后,只有当释放连接后才能允许下一次的连接,所以需要通过连接池来使用Jedis)
不支持异步
不是线程安全的
Jedis仅支持基本的数据类型如:String、Hash、List、Set、Sorted Set。

jedis.set("key", "value");
List<String> values = jedis.mget("key", "key2", "key3");

Redisson
实现了分布式和可扩展的java数据结构,支持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, Lock, AtomicLong, CountDownLatch。并且是线程安全的,底层使用Netty4实现网络通信。和jedis相比,功能比较简单,不支持排序,事务,管道,分区等redis特性

基于Redission实现分布式锁

Jedis的基本使用

1Jedis对象常用API
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值