Redis面试题汇总
1 请说出你对Redis的认识,Redis有哪些优缺点?
Redis是一个使用C语言编写,开源的高性能非关系型数据库。
Redis有5种数据存储类型,健的类型只能是字符串,值的类型可以是:字符串、列表、集合、散列表、有序集合。
Redis的数据存储在内存之中,所以读写速度非常快,每秒可以处理超过10万次数据读写操作。
优点
- 读写性能优异,读速度可达110000次/秒,写速度可达到81000次/秒;
- 支持数据持久化,支持AOF和RDB两种数据持久化;
- 支持事务,Redis所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性操作;
- 数据结构丰富,除了支持string外,还支持hash、set、zset、list等数据结构;
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
缺点
- 易受物理内存限制,不能作为海量数据的高性能读写,因此适应场景主要局限在较小数据量的高性能操作和运算上;
- 不具备容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或手动切换前端IP才能恢复;
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引发数据不一致问题,降低可用性;
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这会对资源造成很大的浪费;
2 Redis为什么会这么快?
- 完全基于内存,绝大部分请求也是纯粹的内存操作,所以非常快速。数据在内存中,类似于HashMap,时间复杂度是O(1)
- 数据结构简单,所以数据操作也简单,这些数据结构是专门设计的。
- 采用单线程,这就避免了不必要的上下文切换和竞争条件,也不存在多进程或多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而出现的性能损耗;
- 使用多路I/O复用模型,非阻塞型IO;
- 使用底层模型不同,他们之间底层实现方式以及客户端之间通讯的应用协议不一样,Redis直接构建了自己的VM机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
3 Redis有哪些数据类型,分别应用在什么场景?
string
可以存储字符串、整数、浮点数,适用于简单的健值对存储。
应用场景:
- 分布式锁
- 计数
- 序列化对象
hash
键值对集合,适用于存储结构化数据,例如对象。
list
列表,可以从两端插入和弹出,按照插入顺序排序。适用于存储消息队列,有序数据。
set
string无序集合,通过hash表实现。可执行交、并、差的操作,适用于例如粉丝列表等。
zset
有序集合。可去重,可排序。
4 Redis有哪些持久化方式?优缺点分别是什么?
持久化是将内存数据写到磁盘中去,防止宕机数据丢失。
Rds提供了两种持久化方式,RDB和AOF
RDB
快早持久化,默认持久化方式。Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本,Redis创建快照后,可以对快照进行备份,可以将快照复制到其它服务器从而创建具有相同数据的服务器副本,还可以将快照留在原地以便重启服务器的时候使用。
redis.conf配置
save 900 10
在300秒之后,如果至少有10个KEY发生变化,REDIS就会自动触发BGSAVE命令创建快照。
AOF
AOF持久化实时性更好,是目前主流的持久化方案,开启AOF命令:
appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入磁盘的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过DIR参数设置的,默认的文件名appendonly.aof
AOF可以配置三种不同的持久化方式
appednfsync always
每次有数据修改发生时都会写入AOF文件,这种方式会严重降低Redis的速度appendfsync everysec
每秒钟同步一次,显式地将多个写命令同步到硬盘appendfsync no
让操作系统决定何时进行同步
为了兼顾数据和写入性能,用户可以考虑appendfsync everysec玄子昂,让redis美妙同步一次AOF文件,Redis性能几乎没有收到任何影响。而且这样即使出现系统奔溃,用户最多只会丢失疫苗之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的的最大写入速度。
混合持久化
Redis4.0开始支持,AOF重写的时候就直接把RDB的内容写到AOF文件开头。这样做综合了RDB和AOF的有点,快速加载同时避免丢失过多的数据。缺点是,AOF里面的RDB部分是压缩格式不再是AOF格式,可读性差。
5 什么是缓存雪崩和缓存穿透,如何解决?
缓存雪崩
缓存同意时间大面积失效,后续请求落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决办法:
- 保证redis集群的高可用性,发现有机器宕机就尽快补上,选择合适的内存淘汰策略;
- 系统上线前,对缓存进行预热;
- 让缓存的过期时间合理均匀分布;
- 加排斥锁;
- 缓存过期标记+异步刷新
缓存穿透
黑客故意请求缓存中不存在的数据,导致所有请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决办法:
- 最简单的办法就是将空结果进行缓存,但是不要太长时间;
- 复杂一点的办法就是使用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,不存在的数据肯定会被bitmap兰及诶啊哦。
6 如何解决Redis并发竞争Key问题?
多个系统同时对一个KEY进行操作,但是最后执行的顺序和我们期望的殊勋不同,这样就导致了结果的不同。
解决办法:
使用分布式锁。
基于zookeeper临时有序节点可以实现分布式锁,大致思想为:每个客户端对某个方法加锁时,在zookeeper上的域该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否货物所的方式很简单,值需要判断有序节点中序号最小的一个。当锁释放的时候,只需要将这个瞬时节点删除即可。同时,其可以表面服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。
7 Redis如何实现分布式锁?
加锁
NX操作,写入随机值,设置鬼泣时间,避免死锁。解锁
解锁必须确保操作的原子性,所以需要借助LUA先判断随机值是否相等再解锁
8 详述Redis过期策略和内存淘汰机制?
定时删除
- 设置键的过期时间时,创建一个Timer, 当过期时间到临时,立刻删除键;
- 内存友好型策略,一旦键过期,就会被删除,并释放所占用的内存,CPU不友好,当一批数量比较多的键过期时,正好遇上CPU紧张的时段,这时候需要的事CPU处理能力,而不是内存。显然CPU时间用在删除过期键上,会对服务器的响应时间和吞吐量造成影响。另外当前Redis时间事件无法搞笑处理大量时间事件,所以定时删除并不是一种号的定时删除策略。
Redis默认每个100ms检查,随机抽取KEY进行检查,如果过期则删除,这种操作十分消耗CPU资源。
惰性删除
不管过期的键,在这种策略下,当键在空间中被取出时,首先检查取出的键是否过期,若过期删除该键,否则,返回该键;
定期删除
即内存淘汰策略:
- noeviction : 当内存不足以容纳新写入数据时,新写入操作会报错;
- allkeys-lru :当内存不足以容纳新写入数据时,在键空间红,移除最近最少使用的KEY;
- allkeys-random : 当内存布椅子容纳新写入数据时,在键空间中,随机移除某个KEY;
- volatile-lru : 当内存不足以容纳写入数据时,在这是了过期时间的键空间中,移除最近最少使用的KEY。 这种情况一般是把Redis即当缓存,又做持久化存储的时候采用。
- volatile-random: 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的KEY优先移除。
9 如何保证缓存与数据库双写时的数据一致性?
数据库和缓存双鞋,就必然会存在不一致的问题。有强一致性的场景,就不能做缓存。
做缓存则代表取最终一致性:
- 采取正确的更新策略,先更新数据库,再删除缓存
- 如果存在删除缓存失败,提供补偿措施,例如利用消息队列
10 Redis适合那些场景?
- Sesion共享(单点登录)
- 页面缓存
- 消息队列
- 分布式锁
- 排行榜/计数器
- 发布订阅
发表回复