一、问题
我看你在很多项目中都使用了redis,请问你在最近项目的哪些场景使用了redis?
比如我开发的电商项目,用到了redis缓存,用于用户高频访问的不经常的修改的热点数据,目的是加快访问速度,同时减轻数据库压力。
二、常见Redis出现的问题以及解决方案
1.缓存穿透
当用户访问的数据既不在缓存也不在数据库中时,就会导致每个用户查询都
会“穿透”缓存“直抵”数据库。这种情况就称为缓存穿透。当高度发的访问请求
到达时,缓存穿透不仅增加了响应时间,而且还会引发对DBMS的高并发查
询,这种高并发查询很可能会导致DBMS的崩溃。
缓存穿透产生的主要原因有两个:一是在数据库中没有相应的查询结果,二是
查询结果为空时,不对查询结果进行缓存。所以,针对以上两点,解决方案也
有两个。
1.对非法请求进行限制
布隆过滤器:布隆过滤器中存在,就继续查询redis,如果不存在直接拦截。缓存预热时,预热布隆过滤器,热点数据在添加缓存的同时添加到布隆过滤器。
原理:
bitmap:只能存储二进制数0或1,bit数组。
hash存储,对一个数据进行多次hash求值,对求出的位置进行赋值。
hash查询,使用相同的hash函数进行求值,如果对应求出的值所在的数组位置的值都相同,则表示查询到。
布隆过滤器作用:布隆过滤器可以用于每次检索一个元素是否在一个集合中。
缺点:可能存在误判,hash用可能重复。解决:数据大小决定了误判率,数据大小又决定内存。
Reddision Guava 添加redis可以设置误判率 5%以内。
2.对结果为空的查询给出默认值
优点:简单 缺点:消耗内存,可能会发生不一致问题。
2.缓存击穿
1.在缓存设计的key过期的同时,有大量高并发请求,穿过缓存,直接访问数据库,引起数据库崩溃,叫做缓存击穿。
解决方案两种:
1.互斥锁(分布式锁)
当缓存是失效时,不立刻去load db,先使用如redis的sexnx设置一个互斥锁,当操作成功返回时再进行Load db操作并设置缓存,否则重试get缓存。
优缺点:数据的强一致性,性能不高,可能产生死锁问题。
2.逻辑过期,设置key逻辑过期
在设置key时候,设置一个时间字段一块存入缓存中,不设置key过期时间。
当查询时候,从redis中取出数据查看是否过期,如果过期再开一个先后才能进行数据同步,当前线程正常返回数据,当然返回的数据不是最新的。
如果选择key的逻辑删除,优先考虑高可用性,性能较高,但同步性不强。
3.缓存雪崩,当redis中有大量key在同一时间过期时,Redis缓存失效,会导致请求直接访问数据库,或者redis服务宕机当请求足够多就会导致数据库崩溃。
解决策略:
1.设置随机过期时间,在设置过期时间时加一个随机数,间隔一段时间设置key过期。
2.宕机解决策略可以是高可用集群,提高集群服务可用性。设置限流规则,添加降级策略,sentinel. 给业务添加多级缓存。
以上三种缓存问题都可以用限流规则避免。
3.mysql数据如何与redis进行同步。
1.当修改数据库的数据同时要更新缓存的数据,缓存和数据的数据保持一致。
读操作:访问缓存,有直接返回,没有访问数据库,设置缓存。
写操作:延迟双删
删除缓存 修改数据库
先删除缓存 还是修改数据库 都有可能产生脏数据
所以采用延时删除 延时数据不好确认删除时间 所以有脏数据风险 只能控制
2.双写一致 读多写少
共享锁 排他锁
读写锁
读业务获取读锁,读读互斥,读写不互斥。写业务获取写锁,不允许其他业务读写,以此保证了数据的强一致性。
3.延迟实现数据一致方案
MQ异步通知
Canal 允许短暂延时可以考虑cannal 阿里的 主要是基于mysql主从同步,不嵌入代码。监听myql binlog