面试必问 Redis基本数据类型及缓存击穿、缓存穿透、缓存雪崩

科技   2024-10-04 08:01   河北  


缓存雪崩:是指缓存在同一时间大规模失效,导致后续的所有数据请求都涌向数据库,从而引起数据库的崩溃。

解决方案:

1) 将缓存数据的过期时间设置为随机值
2) 进行缓存预热
3) 使用互斥锁机制(使查询请求按顺序处理)


缓存穿透:是指当缓存和数据库中都不存在某些数据时,这些数据的请求都会直接落到数据库上,进而导致数据库的压力过大甚至崩溃(这种情况通常与恶意攻击有关)。

解决方案

1)在接口层增加基础的数据校验机制
2)当缓存中无法获取数据时,若数据库中也不存在,则将该数据的key与null值关联并设置较短的缓存时间。
3)采用布隆过滤器,将所有可能存在的数据通过哈希函数映射到一个足够大的位图中,这样对于确定不存在的数据请求可以进行拦截,但需要注意的是,由于哈希冲突的存在,布隆过滤器可能会产生“误判”现象。


缓存击穿:是指缓存中不存在,但数据库中却有的数据(通常是由于缓存的有效期到期所致),在大量并发用户同时请求这些数据时,会导致数据库在短时间内承受巨大的访问压力,进而可能引发数据库的崩溃。

解决方案:

1)为热点数据设置永久有效的缓存,避免其过期
2)引入互斥锁机制来协调并发请求


什么是Redis?它主要用来什么的?

Redis,其英文全称为Remote Dictionary Server(远程字典服务),是一个采用ANSI C语言编写的开源项目,它支持网络访问,既可以基于内存操作也可以实现数据的持久化存储。作为一个日志型的Key-Value数据库,Redis提供了多种编程语言的API接口。

与MySQL数据库相比,Redis的一个显著特点是其数据存储在内存中,这使得Redis的读写速度极为迅速,每秒能够轻松处理超过10万次的读写操作。因此,Redis被广泛地用作缓存系统。此外,Redis还常被用于实现分布式锁的功能。除了这些应用,Redis还支持事务处理、数据持久化、LUA脚本执行、基于LRU算法的事件驱动以及多种集群部署方案。


Redis五种基本数据类型

1)String(字符串)

string 类型在 Redis 中是二进制安全的,意味着 Redis 的 string 可以包含任意类型的数据,例如 jpg 图片或者序列化后的对象。

其值的最大存储容量为512MB。

简单使用示例包括:使用 set key value 来存储数据,使用 get key 来检索数据。

incr key 命令可以将对应 key 的 value 值自增 1,如果该 key 不存在,Redis 会自动创建它并将其值初始化为 1。

decr key 命令则可以将对应 key 的 value 值自减 1。

应用场景:共享session分布式锁,计数器、限流

2)Hash(哈希)

简单使用示例:使用 hset key field value 来设置哈希类型的数据,使用 hget key field 来获取哈希类型中指定字段的值。

内部编码方面,Redis 根据哈希类型的数据量和值的大小来选择编码方式。当哈希类型的元素个数少于 512 个且所有值的大小小于 64 字节时,Redis 会使用 ziplist(压缩列表)编码;否则,Redis 会使用 hashtable(哈希表)编码。

应用场景上,哈希类型非常适合用于缓存用户信息等场景。

在使用时需要注意,如果开发者使用 hgetall 命令来获取大量的哈希元素,可能会导致 Redis 服务器阻塞。为了避免这种情况,可以使用 hscan 命令进行逐步扫描。另外,如果只需要获取哈希中的部分字段,建议使用 hmget 命令来提高效率。

3)List(列表)

Redis 列表是一个简单的字符串集合,用于存储多个有序的字符串元素,这些元素会根据插入的顺序进行排序。你可以选择在列表的头部(左侧)或尾部(右侧)添加新的元素。值得注意的是,一个 Redis 列表最多能够存储 2^32-1 个元素,即大约 4294967295 个元素(超过40亿)。

在实际应用中,你可以通过 lpush key value [value …] 命令向列表的左侧添加元素,使用 lrange key start end 命令来获取列表中指定范围内的元素。

在内部实现上,Redis 会根据列表的大小和元素的值来选择编码方式。具体来说,如果列表中的元素数量少于 512 个,并且每个元素的值都小于 64 字节(这是默认值),Redis 会采用 ziplist(压缩列表)编码;否则,Redis 会使用 linkedlist(链表)编码。

Redis 列表的应用场景非常广泛,例如可以用作消息队列来传递信息,或者作为文章列表来展示一系列有序的内容。

4)set(无序集合)

Redis 的 Set 是一个由 string 类型元素组成的无序集合,它不允许元素重复。Set 集合是通过哈希表来实现的,因此添加、删除和查找操作的复杂度都是 O(1)。

在实际使用中,sadd key element [element …] 命令可以用来将一个或多个 string 元素添加到 key 对应的 Set 集合中。如果添加的元素已经存在于集合中,则返回 0;如果成功添加了新元素,则返回 1。

内部编码方面,Redis 会根据 Set 集合中元素的特点来选择编码方式。如果集合中的元素都是整数,并且元素个数少于 512 个,那么 Redis 会使用 intset(整数集合)编码;否则,Redis 会使用 hashtable(哈希表)编码。

需要注意的是,smembers 命令与 lrangehgetall 命令一样,都属于可能会产生较重负载的命令。当集合中的元素数量非常多时,使用这些命令可能会导致 Redis 服务器阻塞。为了避免这种情况,可以使用 sscan 命令来逐步扫描并获取集合中的元素。

5)zset(sorted set:有序集合)

有序集合zset:这是一个已经排序的字符串集合,其中的元素具有唯一性,不允许重复。

与 Redis 的 set 集合类似,zset 集合也是由 string 类型的元素组成,并且不允许成员重复。然而,zset 与 set 的不同之处在于,zset 为每个元素都关联了一个 double 类型的分数。Redis 根据这些分数来对集合中的成员进行从小到大的排序。需要注意的是,虽然 zset 的成员是唯一的,但与之关联的分数(score)却可以是重复的。

在实际使用中,可以通过 zadd key score member [score member …] 命令来向 zset 集合中添加元素,并同时指定每个元素的分数。


底层内部编码方面,Redis 有序集合 zset 可以选择使用 ziplist(压缩列表)或 skiplist(跳跃表)来进行实现。具体的选择依据是:当有序集合中的元素个数少于 128 个,并且每个元素的值都小于 64 字节时,Redis 会采用 ziplist 编码;否则,Redis 会选择使用 skiplist 编码。

在应用场景上,Redis 有序集合 zset 非常适用于实现排行榜功能,以及满足一些社交需求,比如用户点赞等场景。


Java技术前沿
专注分享Java技术,包括但不限于 SpringBoot,SpringCloud,Docker,消息中间件等。
 最新文章