Redis基础
1.Redis 为什么这么快?4
- 1.Redis 基于内存,内存的访问速度是磁盘的上千倍;
- 2.Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用
- 3.Redis 内置了多种优化过后的数据类型/结构实现,性能非常高。
2.分布式缓存常见的技术选型方案有哪些?说一下 Redis 和 Memcached 的区别和共同点3
- 共同点:都是基于内存的数据库,一般都用来当做缓存使用。都有过期策略。两者的性能都非常高。
- 不同点:
- 1.Redis 支持更丰富的数据类型(支持更复杂的应用场景)
- 2.Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 把数据全部存在内存之中。
- 3.Redis 有灾难恢复机制。 因为可以把缓存中的数据持久化到磁盘上。
- 4.Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。
3.常见的缓存读写策略有哪些?3
- 1.Cache Aside Pattern(旁路缓存模式):是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景。
- 2.Read/Write Through Pattern(读写穿透):Read/Write Through Pattern 中服务端把 cache 视为主要数据存储,从中读取数据并将数据写入其中。cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。
- 3.Write Behind Pattern(异步缓存写入):Read/Write Through 是同步更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db。
4.什么是 Redis Module?有什么用?项目中使用过吗?3
Redis应用
5.Redis 除了做缓存,还能做什么?4
- 1.分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。
- 2.限流:一般是通过 Redis + Lua 脚本的方式来实现限流。如果不想自己写 Lua 脚本的话,也可以直接利用 Redisson 中的 RRateLimiter 来实现分布式限流,其底层实现就是基于 Lua 代码+令牌桶算法。
- 3.消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。
- 4.延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)。
- 5.分布式 Session :利用 String 或者 Hash 数据类型保存 Session 数据,所有的服务器都可以访问。
- 6.复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。
Redis数据结构
6.Redis 常用的数据类型有哪些?4
- 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
- 3 种特殊数据类型:HyperLogLog(基数统计)、Bitmap (位图)、Geospatial (地理位置)。
7.使用 HyperLogLog 统计页面 UV 怎么做?5
8.使用 Redis 实现一个排行榜怎么做?5
Redis 中有一个叫做 Sorted Set (有序集合)的数据类型经常被用在各种排行榜的场景,比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。相关的一些 Redis 命令: ZRANGE (从小到大排序)、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。
Redis线程模型👍
9.Redis单线程模型了解吗?那怎么监听大量的客户端连接呢?5
10.Redis6.0 之前为什么不使用多线程?3
- 单线程编程容易并且更容易维护;
- Redis 的性能瓶颈不在 CPU ,主要在内存和网络;
- 多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。
11.Redis6.0 之后为何引入了多线程?4
Redis6.0 引入多线程主要是为了提高
Redis持久化机制👍
12.Redis宕机了?如何避免数据丢失?5
依赖于持久化机制
13.什么是 RDB 持久化?5
快照(snapshotting,RDB):
Redis 可以通过创建快照来获得存储在内存里面的数据在 某个时间点 上的副本。Redis 创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用。
14.什么是 AOF 持久化?5
只追加文件(append-only file, AOF):
与快照持久化相比,AOF 持久化的实时性更好。默认情况下 Redis 没有开启 AOF(append only file)方式的持久化(Redis 6.0 之后已经默认是开启了),可以通过 appendonly 参数开启:
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到 AOF 缓冲区 server.aof_buf 中,然后再写入到 AOF 文件中(此时还在系统内核缓存区未同步到磁盘),最后再根据持久化方式( fsync策略)的配置来决定何时将系统内核缓存区的数据同步到硬盘中的。
15.Redis 4.0 对于持久化机制做了什么优化?4
由于 RDB 和 AOF 各有优势,于是,Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。
16.如何选择 RDB 和 AOF?
- Redis 保存的数据丢失一些也没什么影响的话,可以选择使用 RDB。
- 不建议单独使用 AOF,因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。
- 如果保存的数据要求安全性比较高的话,建议同时开启 RDB 和 AOF 持久化或者开启 RDB 和 AOF 混合持久化。
Redis内存管理
17.Redis 给缓存数据设置过期时间有啥用?4
因为内存是有限的,如果缓存中的所有数据都是一直保存的话,分分钟直接 Out of memory。
18.Redis 是如何判断数据是否过期的呢?4
Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。
19.过期的数据的删除策略了解么?4
- 1.惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
- 2.定期删除:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
- 定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是 定期删除+惰性/懒汉式删除 。
20.Redis 内存淘汰机制了解么?4
- 相关问题:MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?
- 1.volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
- 2.volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰。
- 3.volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
- 4.allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
- 5.allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
- 6.no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
Redis事务
21.什么是 Redis 事务?如何使用 Redis 事务?4
- 你可以将 Redis 中的事务理解为:Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。
- 如何使用?
- MULTI:MULTI命令后可以输入多个命令,Redis 不会立即执行这些命令,而是将它们放到队列,当调用了 EXEC 命令后,再执行所有的命令。
- 你也可以通过 DISCARD 命令取消一个事务,它会清空事务队列中保存的所有命令。
- 你可以通过WATCH命令监听指定的 Key,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的 Key 被 其他客户端/Session 修改的话,整个事务都不会被执行。
22.Redis 事务支持原子性吗?4
23.Redis事务还有什么缺陷?4
提示:除了不满足原子性之外,事务中的每条命令都会与Redis服务器进行网络交互,这是比较浪费资源的行为。明明一次批量执行多个命令就可以了,这种操作实在是看不懂。
24.如何解决 Redis 事务的缺陷?4
我们可以利用 Lua 脚本来批量执行多条 Redis 命令,这些 Redis 命令会被提交到 Redis 服务器一次性执行完成,大幅减小了网络开销。
另外,Redis 7.0 新增了 Redis functions 特性,你可以将 Redis functions 看作是比 Lua 更强大的脚本。
Redis性能优化👍
25.什么是 bigkey?有什么危害?3
简单来说,如果一个 key 对应的 value 所占用的内存比较大,那这个 key 就可以看作是 bigkey。
26.如何发现 bigkey?3
1.使用 Redis 自带的 –bigkeys 参数来查找。
2.借助开源工具分析 RDB 文件。
27.如何避免大量 key 集中过期?5
- 1.给 key 设置随机过期时间。
- 2.开启 lazy-free(惰性删除/延迟释放) 。lazy-free 特性是 Redis 4.0 开始引入的,指的是让 Redis 采用异步方式延迟释放 key 使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程。
28.什么是内存碎片?为什么会有 Redis 内存碎片?如何清理 Redis 内存碎片?4
- 你可以将内存碎片简单地理解为那些不可用的空闲内存。
- 为什么?
- 1.Redis 存储数据的时候向操作系统申请的内存空间可能会大于数据实际需要的存储空间。
- 2.频繁修改 Redis 中的数据也会产生内存碎片。
- 如何清理?
- 直接通过 config set 命令将 activedefrag 配置项设置为 yes 即可。
Redis生产问题👍
29.什么是缓存穿透?怎么解决?5
- 1.缓存无效key:如果缓存和数据库都查不到某个 key 的数据就写一个到 Redis 中去并设置过期时间,这种方式只可以解决请求的 key 变化不频繁的情况
- 2.布隆过滤器:由二进制向量(或者说位数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构。类似于hash表,可以非常方便地判断一个给定数据是否存在于海量数据中。
- 把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会走下面的流程。
30.什么是缓存击穿?怎么解决?5
举个例子:秒杀进行过程中,缓存中的某个秒杀商品的数据突然过期,这就导致瞬时大量对该商品的请求直接落到数据库上,对数据库造成了巨大的压力。
- 解决方法:
- 1.设置热点数据永不过期或者过期时间比较长。
- 2.针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。
- 3.请求数据库写数据到缓存之前,先获取互斥锁,保证只有一个请求会落到数据库上,减少数据库的压力。
31.什么是缓存雪崩?怎么解决?5
举个例子:数据库中的大量数据在同一时间过期,这个时候突然有大量的请求需要访问这些过期的数据。这就导致大量的请求直接落到数据库上,对数据库造成了巨大的压力。
- 解决办法:
- 针对 Redis 服务不可用的情况:
- 1.采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 2.限流,避免同时处理大量的请求。
- 3.多级缓存,例如本地缓存+Redis 缓存的组合,当 Redis 缓存出现问题时,还可以从本地缓存中获取到部分数据。
- 针对热点缓存失效的情况:
- 1.设置不同的失效时间比如随机设置缓存的失效时间。
- 2.缓存永不失效(不太推荐,实用性太差)。
- 3.缓存预热,也就是在程序启动后或运行过程中,主动将热点数据加载到缓存中。
- 缓存预热如何实现?
- 1.使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。
- 2.使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。
- 缓存雪崩和缓存击穿有什么区别?
- 缓存雪崩和缓存击穿比较像,但缓存雪崩导致的原因是缓存中的大量或者所有数据失效,缓存击穿导致的原因主要是某个热点数据不存在与缓存中(通常是因为缓存中的那份数据已经过期)。
32.三者有什么区别?
参考链接
33.缓存预热如何实现?5
- 1.使用定时任务,比如 xxl-job,来定时触发缓存预热的逻辑,将数据库中的热点数据查询出来并存入缓存中。
- 2.使用消息队列,比如 Kafka,来异步地进行缓存预热,将数据库中的热点数据的主键或者 ID 发送到消息队列中,然后由缓存服务消费消息队列中的数据,根据主键或者 ID 查询数据库并更新缓存。
Redis集群
34.什么是Sentinel(哨兵)?有什么用?如何实现故障转移?5
- Sentinel (哨兵)只是Redis的一种运行模式,不提供读写服务,默认运行在26379端口上,依赖于Redis 工作。Redis Sentinel的稳定版本是在 Redis 2.8之后发布的。
- 作用:监控Redis节点的运行状态并自动实现故障转移。
35.Sentinel如何检测节点是否下线?主观下线和客观下线的区别?
36.Sentinel如何选择出新的master(选举机制)?
37.如何从Sentinel集群中选择出Leader?
38.为什么需要 Redis Cluster?解决了什么问题?有什么优势?
简单来说,Redis 切片集群就是部署多台Redis主节点(master),这些节点之间平等,并没有主从之说,同时对外提供读/写服务。缓存的数据库相对均匀地分布在这些Redis实例上,客户端的请求通过路由规则转发到目标master 上。
Redis 切片集群对于横向扩展非常友好,只需要增加Redis节点到集群中即可。
39.Redis Cluster是如何分片的?
Redis Cluster中的数据是如何分布的?如何确定给定key应该分布到哪个哈希槽中?
Redis Cluster并没有使用一致性哈希,采用的是哈希槽
分区,每一个键值对都属于一个hash slot(哈希槽)。
Redis Cluster通常有16384个哈希槽,要计算给定 key应该分布到哪个哈希槽中,我们只需要先对每个key计算CRC-16 (XMODEM)校验码,然后再对这个校验码对16384(哈希槽的总数)取模
40.为什么 Redis Cluster 的哈希槽是 16384 (2的14次方)个?
41.如何确定给定 key 的应该分布到哪个哈希槽中?
42.Redis Cluster 支持重新分配哈希槽吗?
支持
43.Redis Cluster 扩容缩容期间可以提供服务吗?
44.Redis Cluster 中的节点是怎么进行通信的?