1,商品首页和商品详情做缓存
1.1 为什么做缓存
当系统用户量增大,访问量随着增发,但是MySQL处理数据量是有限的,无法满足大批量的请求
这时就需要把数据库中的数据放入内存中先做缓存。如果不做缓存就可能把数据库搞崩掉
缓存的好处:
1.减轻数据库访问压力
2.更快的响应速度
1.2 什么是做缓存
把磁盘数据放入内存中
1.3 怎么做缓存
1.3.1采用redis做缓存
1.3.1.1 redis定义
redis是一个运行在内存中采用key-value存储的nosql数据库
sql数据库: 关系型数据库(MySQL,Oracle)
Nosql数据库(Not only sql 非关系型数据库)
redis中的数据全部运行在内存中,该特点是可以做缓存的重要原因
(redis单机理论处理速度50000请求/s)
2,用redis做缓存就会有下面三个问题
2.4、缓存穿透
指客户端请求的数据在缓存数据库中都没有,这样缓存永远不会生效,这些请求都会打到数据库
解决方案:
1:缓存空对象给过期时间,优点,实现简单,缺点额外内存消耗
2:布隆过滤器 有点内存占用少,实现复杂,存在误判情况
2.5、缓存雪崩
指同一时间段内大量的缓存key失效,或者redis宕机,导致大量的请求到达数据库
解决方案:
1:给不同key添加不同过期时间
2:利用redis集群提高服务可有性
3:给业务添加多级缓存
2.6、缓存击穿
指热点key 问题,就是一个高并发访问的key突然失效,无数的请求访问都会瞬间给数据库带来巨大压力
解决方案:
1:查询缓存未命中时,去查数据库的代码前加互斥锁(可以用redis分布式锁),从数据库查到数据并且写入缓存完毕后在释放锁
分布式锁的作用: * 在集群部署下/分布式部署下,jdk锁不住非原子性代码,只能用分布式锁 * 用redis实现分布式锁: * 通过redis中的setnx指令,在放数据之前,会判断key是否存在,key在返回0,key不在则把数据放入并返回1
用redis锁实现分布式锁的问题:
1.锁的时间不好指定(对于锁的时间不能去明确合适的时间) * 解决办法:加锁后,开启一个子线程(检测主线程是否走完,如果没有,则再给锁的时间续期) * 2.删除锁的代码不是原子性代码(会有bug) * 解决办法 :可以使用lua脚本删除锁 * * 解决上述所有问题还可以用redis框架redisson实现分布式锁
三,数据一致性问题(数据库数据和redis数据不一样)
在什么情况下会出现?
对缓存对应数据库数据,出现新增,修改,删除
3.1:先删除缓存,在操作数据库
一个线程删除缓存,在操作数据库时比如(update set age = 20 原值等于10)另外一个线程进来
查缓存没有(被第一个线程删了)查数据库放入缓存放的还是10,这时候线程一修改数据库完成。结果导致缓存为10,数据库为 20,数据不一致性问题。
3.2:先操作数据库,在删除缓存
缓存数据突然失效,线程一查询没有缓存,去查数据库(age = 10)然后写入缓存中时,线程2执行修改数据库操作(set age = 20)
删除缓存,这是线程一开始写缓存(age = 10)造成了数据不一致问题
3.3:延迟双删(选中方案)
1,删除缓存。2,动数据库。3,延迟200ms。4, 在删除缓存
延迟的作用:等查询方法走完。