大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey

CSDN 2024-08-29 14:07:02 阅读 57

点一下关注吧!!!非常感谢!!持续更新!!!

目前已经更新到了:

Hadoop(已更完)HDFS(已更完)MapReduce(已更完)Hive(已更完)Flume(已更完)Sqoop(已更完)Zookeeper(已更完)HBase(已更完)Redis (正在更新…)

章节内容

上节我们完成了:

Redis 通信协议Redis 响应模式:串行模式、双工模式Redis 数据格式处理流程、处理机制、文件事件Reactor 多路复用等基础概念

在这里插入图片描述

缓存穿透

问题描述

一般的缓存系统,都是按照Key去缓存查询,如果不存在对应的Value,就会去后端中查询。

在高并发情况下,过量查找不存在的Key就会出现缓存穿透的问题,数据库会因为量过大而宕机。

解决方案

对查询结果为空的情况也进行缓存,缓存时间(TTL)设置的短一点,或者Key对应的数据 INSERT 操作后清理缓存。使用布隆过滤器,在缓存之前加一层。在查询前先到布隆过滤器中查找,不存在则直接返回,不需要到DB查找。

在这里插入图片描述

布隆过滤器

布隆过滤器(BloomFilter)是1970年提出的,它实际上一个很长的二进制向量和一系列随机的Hash。

布隆过滤器的原理是:当一个元素被加入到集合中,通过 k 个Hash函数将这个元素映射成一个数组中的 k 个点,把它设置为1。

检索时:查询这些点是否为1即可,如果这些点存在任何一个0,那这个元素一定不存在。但是如果都是1,则这个元素是可能存在的。

在这里插入图片描述

缓存雪崩

问题描述

当缓存服务器重启或者压力过大宕机时,会有大量的访问到达DB,导致数据库奔溃。

解决方案

key 的失效期分散开,不同的key是指不同的过期时间设置二级缓存高可用

缓存击穿

问题描述

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发的访问,是一种非常热的数据。这个时候,可能会存在被击穿的问题。

缓存在某个时间点过期的时候,恰好有很多key的访问过来,这些请求都发现缓存中没有值,从而都到达DB。

解决方案

分布式锁控制线程的访问不设置超时时间 但会造成读写一致问题

数据不一致

问题描述

缓存和DB中的数据不一致。

解决方案

强一致是非常难的,但是可以追求最终一致,采用 延时双删:

先更新数据库的同时删除缓存,等读的时候就会填充缓存2秒后再删除一次缓存设置过期时间将缓存删除失败记录到日志中,利用脚本再次删除

更高级的方案:

通过 binglog 日志来删除缓存

并发竞争

问题描述

多个客户端并发写一个 key,比如写请求:1、2、3、4,最后本来是4,但是由于到达时间顺序问题,成了 2、1、4、3。

解决方案: 分布式锁 + 时间戳

实现原理

准备一个分布式锁,让大家抢锁,抢到再做 SET 操作。

目的是为了让原来的并行操作变成串行操作。

在这里插入图片描述

Redis分布式锁

通过 setnx() 函数实现,但是要注意要有时间:

系统A key 1: { A: 10:00}

系统B key 1: { B: 10:01}

如果是B先抢到锁执行后,在A抢到锁后,发现时间已经过了,那就不做SET操作了。保证数据的顺序。

解决方案:消息队列

在并发量过高的情况下,消息队列排队串行化。

再从消息队列中取出一个一个执行。

HotKey

问题描述

当有大量的请求访问某个Redis中的Key,由于流量集中达到网络的上限。

当有大量的请求(几十万)访问Redis中某个Key时,导致Redis的服务宕机了。接下来就导致流量会进入到DB中。

在这里插入图片描述

如何发现

预估热key,比如秒杀、火爆新闻客户端进行统计Redis自带命令:monitor、hotkeys,但是执行慢利用大数据技术:Storm、Spark、Flink等,发现后写入到ZK中

在这里插入图片描述

解决方案

变分布式缓存为本地缓存,发现hotkey后,加载本地的缓存(数据一致性可能会低)在每个主节点上备份呢热key数据,到时候随机选节点读取即可热点数据进行限流熔断

Big Key

问题描述

大Key指存储的值非常大:

热门话题下的讨论大V的粉丝列表序列化后的图片没有及时处理的垃圾数据

大Key带来的问题:

大key会占用大量的内存,集群中无法均衡Redis性能下降,主从复制异常删除时操作时间过长导致阻塞

如何发现

使用 --bigkeys 命令 但key较多时会很慢获取 RDB 文件,进行分析

如何处理

string类型的bigkey不要存入Redis,可用MongoDB或者CDNstring类型bigkey如果非要存Redis,则单独存储,比如一台Redis单独存。将Key拆分成多个 key-value,平摊到多次获取的压力上大Key不要del,del会阻塞,而删除时间很长会导致阻塞使用 lazy delelet (unlink指令)



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。