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 属性全部失效,例如自己配置的过期时间 ,因为你自己指定了配置!!
解决方案
- 解决缓存穿透
- 同时修改多种缓存操作
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机制缺陷
【redis|Redis做分布式锁,redission,rediscache,redis面试等.....】锁可以无线续命,但是 假如 程序发生了异常, 锁就一直得不到释放,那么该怎么办呢?
解决:如果程序释放锁操作时因为异常没有被执行,那么锁无法被释放,所以释放锁操作一定要放到 finally {} 中;
推荐阅读
- zookeeper|zookeeper-常用命令,集成springboot,分布式锁实现和原理 ,dock集群zookeeper搭建,
- 轻小说|图书馆后记。
- 面试|秋招已至,抓紧备一波蚂蚁金服、字节跳动、阿里等大厂面试,冲刺金九银十!!
- java|Java开发四年遇瓶颈,决心跳槽入字节,四面后成功斩获45万offer!!
- java|(Java岗面试)耗时1月最新整理了20个技术栈的大厂面试题+解析+面经!
- 区块链探索|[论文分享]基于区块链技术的服务端资源权限控制系统设计与实现
- Java|项目总结--3(@Cacheable的使用方法和使用技巧)
- java面试|简单理解Redis缓存中的三大问题
- 面试复习|敖丙思维导图-Redis