redis-2-常见问题

1、缓存穿透、击穿、雪崩

1.1、缓存穿透

是指缓存和数据库中都没有的数据,而用户不断发起请求
如发起为id为“-1”的数据或id为特别大(不存在的数据)。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

解决:

  • 接口层增加校验,如用户鉴权校验,id做基础校验,比如 id<=0的直接拦截;

  • 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

  • 另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。

1.2、缓存击穿

是指缓存中没有但数据库中有的数据

当一个key非常热点(类似于爆款),在不停的扛着大并发,大并发集中对这一个点进行访问;
当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

解决:

  • 设置热点数据永远不过期。
  • 加互斥锁。
  • 读到某key时重置(延长)它的过期时间(缓存续命)

1.3、缓存雪崩

是指缓存中数据大批量到过期时间,大批量数据同一时间过期,导致请求量全部请求到数据库,造成数据库宕机。

解决:

  • 给缓存失效时间,加上一个随机值,避免大量缓存集体失效。
  • 双缓存:缓存A和B,比如A的失效时间是20分钟,B不失效。比如从A中没读到,就去B中读,然后异步起一个线程同步到A。

2、Memcache与Redis的区别

  • 1、memecache不支持持久化 宕机断电无法恢复

  • 2、memecache只有简单的字符串类型,虽然也可以缓存图片;Redis有很多种类型。

  • 3、memcache可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS,适用于最大程度扛量,100k以上的文件memcache较快。

  • 4、memcached一个value最大只支持1MB,Redis最大支持512MB


redis6.0引入了多线程

开启多线程后,是否会存在线程并发安全问题?
不会:
1)Redis多线程部分仅用于处理网络IO和协议解析
2)Redis执行命令仍然是单线程的


3、Redis 常见性能问题和解决方案

  • (1) Master主节点最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件。
    (因为RDB生成快照是很耗性能的,这样会阻塞master,会造成master假死)

  • (2) 如果数据比较重要,某个 Slave从节点开启 AOF 备份数据,策略设置为每秒同步一次
    (这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度,所以要合理设置AOF重写机制)

  • (3) Master 和 Slave 最好在同一个局域网内(主从复制的速度快和连接的稳定性强 )

  • (4) 读写分离,把请求压力分散到各个服务。


4、Redis分布式锁

关键点:SETNX命令。

Redis中提供SETNX命令可以实现分布式锁。
redisson也可以实现(redisson是在Redis是封装的一个jar,简单灵活),配合lua进行加锁和解锁。

将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作。(轮询)

1
2
3
RLock rLock = redissonClient.getLock(lockKey);
Boolean flag = rLock.tryLock(20, 10, TimeUnit.SECONDS);
rLock.unlock();

5、Redis的并发竞争问题如何解决?

出现这个问题的原因:多个子系统去set一个key-value,并发情况下,可能会导致数据一致性问题。

  • 上面第10点说的分布式锁是一种方案,利用SETNX命令。确保同一个时间,只有一个线程拿到了锁,其他则在等待。

  • 还有一种方案就是时间戳。假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

  • 利用队列,将set方法变成串行访问 等..


6、redis事务

Redis也自带事务,但是和MySQL的不同,又有点类似。

Redis事务和MySQL一样,通过 begin;commit;rollback去开启和提交/回滚事务,只不过命令不一样。

具体参考:https://www.cnblogs.com/DeepInThought/p/10720132.html


7、双一致性问题

简单的说就是先写Redis还是先写数据库的问题。

举例:A先改数据库 但B改缓存的操作比A先响应
A改数据库 → B改数据库 → B改缓存 → A改缓存 那就会有数据脏读问题。

详细说明、解决方案见:https://www.cnblogs.com/rjzheng/p/9041659.html

简略说明:

  • 先改库 再改缓存 普遍反对 上述例子说明脏读问题

  • 先删缓存 再改库 也有问题 (用延迟双删策略)

  • 先改库 再删缓存 也有问题