Redis面试

烟雨 4年前 (2021-08-03) 阅读数 382 #面试
文章标签 Redis面试

一、Redis 有哪些类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

二、聊聊 Redis 使用场景

随着数据量的增长,数据库已经满足不了大型互联网类应用的需求。为了提高服务端接口的访问速度,尽可能将读频率高的热点数据存放在 Redis 中。这个是非常典型的以空间换时间的策略,使用更多的内存换取 CPU 资源,通过增加系统的内存消耗,来加快程序的运行速度。
场景包括缓存,会话缓存,时效性,访问频率,计数器,社交列表,记录用户判定信息,交集、并集和差集,热门列表与排行榜,最新动态等。

热点数据,缓存才有价值

对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。

对于热点数据,比如我们的某IM产品,生日祝福模块,当天的寿星列表,缓存以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。

频繁修改的数据,看情况考虑使用缓存

数据更新前至少读取两次,缓存才有意义。这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。

对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不高,读取通常非常高的场景。

那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到Redis缓存,减少数据库压力。

数据不一致性

一般会对缓存设置失效时间,一旦超过失效时间,就要从数据库重新加载,因此应用要容忍一定时间的数据不一致。还有一种是在数据更新时立即更新缓存,不过这也会更多系统开销和事务一致性问题。

缓存更新机制

使用缓存过程中,我们经常会遇到缓存数据的不一致性和与脏读现象,我们有什么解决策略呢?

一般情况下,我们采取缓存双淘汰机制,在更新数据库的时候淘汰缓存。此外,设定超时时间,例如30分钟。极限场景下,即使有脏数据入cache,这个脏数据也最多存在三十分钟。

缓存可用性

缓存是提高数据读取性能的,缓存数据丢失和缓存不可用不会影响应用程序的处理。因此,一般的操作手段是,如果Redis出现异常,我们手动捕获这个异常,记录日志,并且去数据库查询数据返回给用户。

缓存服务降级

服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。

缓存预热

在新启动的缓存系统中,如果没有任何数据,在重建缓存数据过程中,系统的性能和数据库复制都不太好,那么最好的缓存系统启动时就把热点数据加载好,例如对于缓存信息,在启动缓存加载数据库中全部数据进行预热。一般情况下,我们会开通一个同步数据的接口,进行缓存预热。

缓存穿透

如果因为不恰当的业务,或者恶意攻击持续地发请求某些不存在的数据,由于缓存没有保存该数据,所有的请求都会落到数据库上,会对数据库造成很大压力,甚至奔溃。一个简单的对策是将不存在的数据也缓存起来。

三、Redis 为何那么快?

1、完全基于内存。
2、数据结构简单。
3、采用单线程。
4、IO多路复用,非阻塞IO。
5、使用底层模型不同,Redis构建了自己VM机制。

四、Redis 持久化机制是什么?

1、RDB快照:将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。
2、AOF:将修改的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间fsync到磁盘)
3、混合持久化:在AOF在重写时,不再是单纯将内存数据转换为RESP命令并写入AOF文件。而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令(持久化开始到结束期间所产生的修改命令)存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。
于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的AOF 全量文件重放,因此重启效率大幅得到提升。

image.png

五、如何保证数据库缓存双写一致性?

更新缓存方案

1、先更新缓存,再更新数据库(不建议)。
2、先更新数据库,再更新缓存(不建议)。
上面的更新策略会有并发问题。
比如:同时有请求A和请求B更新操作。
理想的流程图如下:
1、线程A更新了数据库。
2、线程A更新了缓存。
3、线程B更新了数据库。
4、线程B更新了缓存。

image.png

非理想状态流程图如下:
1、线程A更新了数据库。
2、线程B更新了数据库。
3、线程B更新了缓存。
4、线程A更新了缓存。

image.png

这样就出现请求A更新缓存比请求B更早,更新缓存才对,但是由于网络等原因,B比A先完成更新缓存,导致A读取到了脏数据。

删除缓存方案

1、先删除缓存,再更新数据库(不建议)。
比如:两个请来,请求A更新操作,请求B查询操作。
请求A会先删除缓存,然后更新数据库。此时B请求看到缓存没有数据,进入数据库查询放入缓存。
但是请求A并没有提交事务,请求B去数据库查询到了旧值。

image.png

延时双删策略(建议使用)

    1、先淘汰缓存。
    2、再写数据库。
    3、休眠1秒,再淘汰缓存。
这样可以将1秒内所造成的缓存脏数据,再次删除。
这个休眠多少秒,可根据业务来定。
版权声明

非特殊说明,本文由Zender原创或收集发布,欢迎转载。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

作者文章
热门