Redis做分布式锁,redission,rediscache,redis面试等.....

redisson中文官方文档
一张图搞懂分布式锁

redis面试

        1. 做数据缓存

        2.缓存穿透(空值被查询):布隆过滤器,保存空值

        3.缓存雪崩(大面积同时失效): 存储的数据同时失效 (设置过期时间随机),造集群

        4.缓存击穿(单个热点key失效):(集群万能csdn搜redis集群),加锁(只让一个去查热点key,然后放入缓存 ,其余直接就可以查缓存了) 

redis做分布式锁

加锁方式:

(1)本地锁

    synchronized (this):(不适合分布式,一个服务对应一个线程):当前对象进行加锁,springboot对象默认单例,可以用此方法,也可以换为ReentrantLock。synchronized是同步阻塞,使用的是悲观并发策略,lock是同步非阻塞,采用的是乐观并发策略(说白了消耗性能更低)。 注意:避免在程序在写入数据进入redis的时候,对redis进行了盘空操作,会对数据库进行两次查询。 故,查询完毕数据库 并 写入redis是一个类似于原子操作 !!
(2)分布式锁:
                         加锁:

                                1.相较于本地锁,更慢,分布式锁吃性能,适合金融业务和秒杀。

                                2.加锁记得设置超时时间(会造成两个问题) , 免得 程序异常一直没有释放锁 。

                                         设置锁的过期时间和设置一把锁应该是原子操作!!不然可能锁设置了,服务器宕机了,分布式另一个程序一直得不到锁。                       

实现:stringRedisTemplate.opsForValue().setIfAbsent(key,value,time,time Unit)

                     删锁:1.业务超时 ,删锁删除的是别人的锁。所以占用锁的时候设置一个uuid,每个人的uuid都不一样,自己删除自己的锁。



                            2.即是设置了uuid 但是,还是会删除别人的锁

所以获取值验证是不是自己的锁+删除锁 是一个组合的原子操作

❤ 引出lua脚本(保证解锁的原子的原子性)
3.自动续期 ,防止任务还没有做完 ,锁就被释放掉了
4.redission.getLock(“lock”,time,timeUnit):

(1)自动锁的时间续期 (2)TTL:time to live,自动设置过期时间 ,但是一旦自己设置了超时时间,会造成锁的时间不会自动续期,从而导致 当业务时间大于 锁的时间的时候,自己的锁被释放了,但是 业务还没有执行完毕,导致 其他线程占用锁而删除,可当第一个线程业务执行完毕时候删除锁的时候,删除的是第二个锁。因为分布式锁事务里面的锁一般都是一把锁 。
最佳:直接设置30秒锁的超时时间 ,自动到期释放锁,业务时长一般不会超过30秒,超过30秒业务肯定会出现问题,手动解锁

5. 锁的种类:读锁必须等到写锁释放。
                   读锁:相当于无锁

                   不能同时写,可以同时读,写的时候不能读

                   

                闭锁:相当于等前面的所有锁释放,自己才能释放



            信号量:获得信号量和释放信号量
6.和数据库的一致性问题
    (1)双写模式:先改数据库 ,再改缓存        

漏洞:当1线程在 写入往redis写缓存之前卡住了,2号线程过来直接完成了双写模式,再切换1线程对缓存进行写,则2号线程是后发生的,但是缓存写进去的确是1号线程。

导致数据库保存的是后发生二号线程写的数据,redis缓存是缓存的一号线程的数据

解决:1.加锁,双写模式是一套操作

        2.加超时时间,但是要允许一定时间的数据库的不一致,例如菜单业务。

              (2) 失效模式:改完数据库,删了redis缓存,下次查询请求会先先查数据库再写入redis。

漏洞(不过发生概率较低):1.当缓存中没有数据,线程二更新数据(更新数据的时间是比较长的)

         线程三读取数据(读取数据时间是比较短的)

     线程二写完数据,删除缓存(删除空缓存),线程三卡住,等待二号线程缓存删除完毕,更新缓存,此时缓存是就的数据库中的数据,造成了不一致性的问题。(此时即使写与)

.

解决:经常性修改的数据不需要放入缓存 ,免得造成不一致问题。

总结:加过期时间可以解决大部分读写不一致的问题,也可以加读写锁保证不发生数据不一致性的问题。

遇到一致性要求高的 ,去数据库查数据。遇到一致性要求不高的,直接缓存。或者canal技术(就是一个消息中间键),mysql更新 ,便通知redis更新

springchache集成redis(性质和redis一模一样,就是简化了操作而已)

第一步

启动方法上加@EnableCache

配置的结果

注解操作

@cacheevict:更新数据库删除 redis缓存,缓存失效模式

1.默认永不过期 。需要指定过期时间(ttl)

2.将存缓数据转化为json数据

springcache默认不能将缓存数据转化为json,所以需要自己放置一个CacheRedisconfigration来重新配置springcache缓存机制
自己配置了rediscacheconfigration 则 会造成 yml文件配置的springcache 属性全部失效,例如自己配置的过期时间 ,因为你自己指定了配置!!

解决方案

  1. 解决缓存穿透

  2. 同时修改多种缓存操作

所以同一类型的数据指定同一分区,而且分区名作为前缀

springcahce -redis :不足

 1.缓存穿透:查询永不存在 



2.缓存击穿:同时查询一个正常过时的数据

解决 1.(加本地锁)所有的服务加上锁,查询即使是个服务 查询十次数据库也不是很慢对吧?

( 分布式锁太浪费性能。又要网络IO。万一碰上阻塞全完蛋了。)

3.缓存雪崩:大量同时过期(不建议加随机过期时间 , 你大量key加进去就是不同时间的)

4.写模式 (数据一致性):加读写锁(太慢了)

                                          引入canal

                                          读多写多的直接走数据库

总结:常规数据直接springcache(度多写少,一致性要求不高,及时性)记得设置过期时间就行

       特殊数据特殊设计

redission

redis集群三主三从扩容缩容等…

https://blog.csdn.net/weixin_45699541/article/details/126208427?spm=1001.2014.3001.5501
![在这里插入图片描述](https://img-blog.csdnimg.cn/d8c8f6003dcb48c899fd068363663171.png

集群配置读写分离

在这里插入图片描述
(未完待续…)

附赠 redis的20种用法

redis20种用法

redisson

ps:为什么 redisson作为分布式锁比 使用 redistemplate (unset)好 ,因为redisson 有wactdog机制
原生redis 存在问题,
假如你使用原生redis 作为分布式锁 ,在你服务器宕机的时候 ,程序执行到一半还没有释放锁,锁会得不到释放。其余线程得不到锁,会阻塞。
使用redisson: 内部有watchdog机制 ,每隔几秒给锁加时,假如你服务器宕机了 。锁会超时自动释放,不仅不会死锁 而且也免费给锁续命 。

watchdog机制缺陷

锁可以无线续命,但是 假如 程序发生了异常, 锁就一直得不到释放,那么该怎么办呢?
解决:如果程序释放锁操作时因为异常没有被执行,那么锁无法被释放,所以释放锁操作一定要放到 finally {} 中;

redis 做分布式锁和 zoopkeeper的对比

在这里插入图片描述
划红线的是redis的不同,zk的临时节点不需要续期,reids有单点故障的的发生可能,但是可以用一些算法补救,但是很复杂。
其实也没有什么是一定的 ,说不定下一个算法就能补救一些缺憾

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值