Redis常见面试题解析(二)

你。 提交于 2019-12-21 03:21:59

文章目录

一、Redis 集群结构以及设计理念

1. Redis 集群架构模式有哪几种?

  1. Redis 单节点单机器部署
  2. Redis 主从节点部署
  3. Redis Sentinel(哨兵)模式部署
  4. Redis 集群模式

2. Redis 集群最大节点个数是多少?

16384 个

3. Redis 集群的主从复制模型是怎样的?

Redis 中的主从复制,也就是 Master-Slave 模型,多个 Redis 实例间的数据同步以及 Redis 集群中数据同步会使用主从复制。

主从复制主要是数据同步, 数据同步分为全量同步增量同步


全量同步:

全量同步一般发生在 Slave 机器初始化阶段, 这时候 Slave 需要将 Master 上的所有数据都进行同步复制。

大概步骤如下所示:

  1. 从服务器发送 SYNC 命令,链接主服务器
  2. 主服务器收到 SYNC 命令后,进行存盘的操作,并继续收集后续的写命令,存储缓冲区
  3. 存盘结束后,将对应的数据文件发送到 Slave 中,完成一次全量同步
  4. 主服务数据发送完毕后,将进行增量的缓冲区数据同步
  5. Slave 加载数据文件和缓冲区数据,开始接受命令请求,提供操作

增量更新:

Slave 节点初始化完成之后,开始正常工作,Master 节点进行的写操作都会同步到 Slave 节点上面。Master 节点每执行一个写命令都会向从服务器发送相同的写命令,从服务器接收到命令,并执行。

4. 请介绍一下 Redis 集群实现方案

  1. Redis Cluster 集群方案(服务端 Sharding 技术)

    Redis Cluster 是 3.0 版本开始正式提供的服务器 Sharding 技术。引入 slot(槽)的概念,整个集群共有 16384 个槽。根据 key 进行散列(CRC16 后 16384 取模),分配到其中一个槽当中。

  2. Redis Sharding 集群(客户端 Sharding 技术)

    Redis Sharding 出现先与 Redis Cluster 方案,他是多 Redis 实例集群方案。

    客户端 Sharding 方式,该向哪个 Redis 节点操作数据,由客户端来进行控制。服务端 Redis 还是一个个相对独立的 Redis 实例节点,没有做任何变动。节点选择可采用的方法:一致性 hash 算法或者虚拟节点算法。

  3. Twemproxy 中间件实现

    Twemproxy 就是一种中间件 Sharding 分片的技术,处于客户端和服务器的中间,将客户端发来的请求,进行一定的处理后(如 Sharding),再转发给后端真正的 Redis 服务器。

    也就是说,客户端不直接访问 Redis 服务器,而是通过 Twemproxy 代理中间件间接访问。

5. Redis 集群会有写操作丢失吗?为什么?

Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。

6. Redis 慢查询是什么?通过什么配置?

所谓慢查询就是指,系统执行命令之后,计算统计每条指令执行的时间,如果执行时间超过设置的阈值,就说明该命令为慢指令。

Redis 慢查询配置参数为:

  1. slowlog-log-slower-than:设置慢查询定义阈值,超过这个阈值就是慢查询。单位为微妙,默认为 10000。
  2. slowlog-max-len:慢查询的日志列表的最大长度,当慢查询日志列表处于最大长度的时候,最早插入的一个命令将从列表中移除。

7. Redis 的慢查询修复经验有哪些?怎么修复的?

  1. 将一些效率比较低或者算法复杂度比较高的命令,禁用或者替换为效率较高的指令。 例如禁用:sort、keys 命令
  2. 拆分大对象数据,防止一次命令操作过多的数据

8. 如何优化 Redis 服务的性能?

  1. Master 节点禁止持久化工作
  2. 持久化策略要有正确的选择,关键数据可以采用 slave 节点 AOF 备份
  3. 主从节点部署在同一个局域网内,保证复制速度与稳定性
  4. 设置或者增加从库需要考虑主库现有的压力
  5. 主从复制一定要单向结构,避免使用图状结构

9. Redis 的主从复制模式有什么优缺点?

优点:可靠性相对于单个节点部署模式有所提高,实现读写分离提高读写效率
缺点:写数据依赖于主节点,主节点空间有限,而且主节点存在单点的风险

10. Redis sentinel(哨兵)模式优缺点有哪些?

优点:保证高可用,各个节点自动故障转移
缺点:主从模式,依旧存在主节点单点风险,主从切换有丢失数据的问题

11. 如何设置 Redis 的最大连接数?查看 Redis 的最大连接数?查看 Redis 的当前连接数?

  • 设置 Redis 的最大连接数使用命令:redis-server -maxclients 50000
  • 查看 Redis 最大连接数使用命令:config get maxclients
  • 查看 Redis 连接数:使用 info 命令;在 redis-cli 端输入 info 命令即可查看

12. 介绍一些 Redis 常用的安全设置?

  1. 网络安全

    除了信任的客户端发出的请求以外,其他所有请求都拒绝。对于暴露到外网的服务,使用防火墙阻止外部访问 Redis 端口。

  2. 身份验证

    Redis 提供了简单的身份验证功能,在 redis.conf 文件中进行配置生效。客户端可以通过发送(AUTH 密码)命令进行身份认证。

  3. 禁用特定的命令集

    Redis 可以选择禁止使用某些命令,这样即使是正常的客户端也无法使用这些命令集合。

二、Redis 缓存管理与持久化机制

1. Redis 持久化机制有哪些?

Redis 提供两种方式进行持久化。

  1. RDB 持久化:原理是将 Reids 在内存中的数据库记录定时 dump 到磁盘上的 RDB 持久化。
  2. AOF(append only file)持久化:原理是将 Redis 的操作日志以追加的方式写入文件。

2. Redis 持久化机制 AOF 和 RDB 有哪些不同之处?

两者的区别

  • RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。

  • AOF 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

3. 请介绍一下 RDB 持久化机制的优缺点

优点

  • RDB 是紧凑的二进制文件,比较适合备份,全量复制等场景
  • RDB 恢复数据远快于 AOF

缺点

  • RDB 无法实现实时或者秒级持久化;
  • 新老版本无法兼容 RDB 格式。

4. 请介绍一下 AOF 持久化机制的优缺点

优点

  1. 可以更好地保护数据不丢失;
  2. appen-only 模式写入性能比较高;
  3. 适合做灾难性的误删除紧急恢复。

缺点:

  1. 对于同一份文件,AOF 文件要比 RDB 快照大;
  2. AOF 开启后,会对写的 QPS 有所影响,相对于 RDB 来说 写 QPS 要下降;
  3. 数据库恢复比较慢, 不合适做冷备。

5. 如果 AOF 文件的数据出现异常, Redis 服务怎么处理?

如果 AOF 文件出现异常, Redis 在重启的时候将会拒绝加载 AOF 文件,从而保证数据的一致性。

这时候,可以试着对 AOF 文件进行修复:redis-check-aof -fix。

6. 常见的淘汰算法有哪些?

  1. FIFO:First In First Out

    先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。

  2. LRU:Least Recently Used

    最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。

  3. LFU:Least Frequently Used

    最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。

7. Redis 淘汰策略有哪些?

Redis 可以看作是一个内存数据库,通过 Maxmemory 指令配置 Redis 的数据集使用指定量的内存。设置 Maxmemory 为 0,则表示无限制。

当内存使用达到 Maxmemory 极限时,需要使用某种淘汰算法来决定清理掉哪些数据,以保证新数据的存入。

Redis 的缓存淘汰策略有:

  1. noeviction:当内存使用达到上限,所有需要申请内存的命令都会异常报错。
  2. allkeys-lru:先试图移除一部分最近未使用的 key。
  3. volatile-lru:淘汰一部分最近使用较少的(LRC),但只限于过期设置键。
  4. allkeys-random:随机淘汰某一个键。
  5. volatile-random:淘汰任意键,但只限于有过期设置的驱逐键。
  6. volatile-ttl:优先移除具有更早失效时间的 key。

8. Redis 缓存失效策略有哪些?

策略有:

  1. 定时删除策略
  2. 惰性删除策略
  3. 定期删除策略。

定时删除策略

在设置 key 的过期时间的同时,为该 key 创建一个定时器,让定时器在 key 的过期时间来临时,对 key 进行删除。

  • 优点:保证内存尽快释放。
  • 缺点:若 key 过多,删除这些 key 会占用很多 CPU 时间, 而且每个 key 创建一个定时器,性能影响严重。

惰性删除策略

key 过期的时候不删除,每次从数据库获取 key 的时候去检查是否过期,若过期,则删除,返回 null。

  • 优点:CPU 时间占用比较少。
  • 缺点:若 key 很长时间没有被获取, 将不会被删除,可能造成内存泄露。

定期删除策略

每隔一段时间执行一次删除(在 redis.conf 配置文件设置 hz,1s 刷新的频率)过期 key 操作。

  • 优点:可以控制删除操作的时长和频率,来减少 CPU 时间占用,可以避免惰性删除时候内存泄漏的问题。
  • 缺点:对内存友好方面,不如定时策略;对 CPU 友好方面,不如惰性策略
    Redis 一般采用:惰性策略 + 定期策略两个相结合。

9. Redis 如何做内存优化?

  • Redis 的所有数据都进行 redisObject 来封装
  • 缩减键、值对象的长度,简化键名,提高内存使用效率
  • 尽量使用 hash 数据结构,减少 key 的数量
  • 共享对象池,并设置空间极限值

10. 什么是 bigkey? 有什么影响?

bigkey 是指存储 value 占用内存空间非常大的 key。例如一个 String 类型的 value 占用了 100MB 空间。

bigkey 的影响主要体现在:

  1. 造成内存空间不平衡:如果 bigkey 存储量比较大,同一个 key 在同一个节点或者服务器中存储,造成一定的影响
  2. 超时阻塞:由于占用空间比较大,那么操作起来效率肯定比较低,也就表示出现阻塞可能性增加
  3. 网络阻塞:获取 bigkey 的时候,自然传输的数据量比较大,导致宽带的压力。

11. 怎么发现 bigkey?

redis-cli-bigkeys 命令可以统计 bigkey 的分布。

生产环境下执行 debug object key 查看 serializedlength 属性,表示 key 对应的 value 序列化之后的字节数。

12. Redis 的内存消耗分类有哪些?

Redis的内存消耗分为:

  1. 对象内存:这是占用最大的一块,存储用户的所有数据。可以理解为:所有 key 的大小 + 所有 value 的大小
  2. 缓冲内存:客户端缓冲、复制积压缓冲、AOF 缓冲
  3. 内存碎片:更新操作、过期数据都可能造成内存碎片

13. 简单介绍一下 Redis 的内存管理方式有哪些?

Redis 内存管理方式主要方向上有两个:

  1. 控制内存上限
  2. 优化回收策略,进行内存回收

14. 如何设置 Redis 的内存上限?有什么作用?

Maxmemory 参数可以限制最大可用内存。

15. Redis 报内存不足怎么处理?

  1. 修改配置文件,增加 Redis 的内存空间 maxmemory
  2. 设置缓存淘汰策略, 具体的淘汰策略如(Redis 缓存管理与持久化机制)题 7 所示
  3. 使用 Redis 集群模式来存储

三、Redis 应用场景设计

1. Redis 适用场景有哪些?

适用场景:

  1. 数据(热点)高并发的读写
  2. 海量数据的读写
  3. 对扩展性要求高的数据

不适场景:

  1. 需要事务支持(非关系型数据库)
  2. 基于 SQL 结构化查询储存,关系复杂

2. Redis 常用的业务场景有哪些?

  1. 热点数据缓存:由于 Redis 访问速度块、支持的数据类型比较丰富,所以 Redis 很适合用来存储热点数据
  2. 限时业务实现:expire 命令设置 key 的生存时间,到时间后自动删除 key。收集验证码、优惠活动等业务场景。
  3. 计数器实现:incrby 命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成。比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
  4. 排行榜实现:借助 SortedSet 进行热点数据的排序。例如:下单量最多的用户排行榜,最热门的帖子(回复最多)等。
  5. 分布式锁实现:利用 Redis 的 setnx 命令进行。后面会有详细的实现介绍。
  6. 队列机制实现:Redis 有 list push 和 list pop 这样的命令,所以能够很方便的执行队列操作。

3. Redis 支持的 Java 客户端有哪些? 简单说明一下特点。

官方推荐的有三种:Jedis、Redisson 和 lettuce。

Jedis:

  1. 轻量,简洁,便于集成和改造
  2. 支持连接池
  3. 支持 pipelining、事务、LUA Scripting、Redis Sentinel、Redis Cluster
  4. 不支持读写分离,需要自己实现

Redisson:

  1. 基于 Netty 实现,采用非阻塞 IO,性能高
  2. 支持异步请求
  3. 支持连接池
  4. 支持 pipelining、LUA Scripting、Redis Sentinel、Redis Cluster
  5. 不支持事务
  6. 支持读写分离,支持读负载均衡,在主从复制和 Redis Cluster 架构下都可以使用
  7. 内建 Tomcat Session Manager,为 Tomcat 6/7/8 提供了会话共享功能
  8. 可以与 Spring Session 集成,实现基于 Redis 的会话共享
  9. 文档较丰富,有中文文档

lettuce:

  1. 可伸缩的线程安全的 Redis 客户端
  2. 支持同步、异步和响应式模式。
  3. 多个线程可以共享一个连接实例,而不必担心多线程并发问题。
  4. 它基于优秀 Netty NIO 框架构建
  5. 支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型。

4. 请简单描述一下 Jedis 的基本使用方法?

Jedis jedis = new Jedis("127.0.0.1", 6379,500,500);
jedis.set("hello", "world”);
String value = jedis.get("hello”);

上面代码就是一个简单的 Redis 数据存储操作。

初始化 Jedis 需要四个参数:

Jedis(final String host, final int port, final int connectionTimeout, final int soTimeout)
  • Host:Redis 节点的服务 IP
  • Port:Redis 服务的端口
  • connectionTimeout:客户端连接超时时间
  • soTimeout:客户端读写超时时间

5. Jedis 连接池链接方法有什么优点?

上一个题目介绍了 Jedis 的直连方式, 每次操作 Redis 都会创建一个新的 TCP 连接,使用完之后就会断开。很明显消耗了不必要的资源。

为了减少这方面的消耗, Jedis 提供了连接池的链接方式:JedisPool。每次连接 Redis 只需要池子中拿,用完了归还就可以了。

  1. 无需每次连接都要生成一个 Jedis 对象
  2. 使用连接池保护和控制资源的使用

6. 什么是分布式锁?有什么作用?

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。 在单机或者单进程环境下,多线程并发的情况下,使用锁来保证一个代码块在同一时间内只能由一个线程执行。比如 Java 的 Synchronized 关键字和 Reentrantlock 类。

多进程或者分布式集群环境下,如何保证不同节点的线程同步执行呢? 这就是分布式锁。

7. 分布式锁可以通过什么来实现?

  1. Memcached 分布式锁

Memcached 提供了原子性操作命令 add,才能 add 成功,线程获取到锁。key 已存在的情况下,则 add 失败,获取锁也失败。

  1. Redis 分布式锁

Redis 的 setnx 命令为原子性操作命令。只有在 key 不存在的情况下,才能 set 成功。和 Memcached 的 add 方法比较类似。

  1. ZooKeeper 分布式锁

利用 ZooKeeper 的顺序临时节点,来实现分布式锁和等待队列。

  1. Chubby 实现分布式锁

Chubby 底层利用了 Paxos 一致性算法,实现粗粒度分布式锁服务。

8. 介绍一下分布式锁实现需要注意的事项?

分布式锁实现要保证几个基本点。

  1. 互斥性:任意时刻,只有一个资源能够获取到锁。
  2. 容灾性:在未成功释放锁的的情况下,一定时限内能够恢复锁的正常功能。
  3. 统一性:加锁和解锁保证同一资源来进行操作。

9. Redis 怎么实现分布式锁?

简单方案:

简单的方法是使用 setnx 命令。释放锁的最简单方式是执行 del 指令。

存在的问题:

锁超时:如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来。

优化方案:

  • setnx 没办法设置超时时间,如果利用 expire 来设置超时时间,那么这两步操作不是原子性操作。

  • 利用 set 指令增加了可选参数方式来替代 setnx。set 指令可以设置超时时间。

10. 缓存命中率表示什么?

  • 缓存命中: 可以同缓存中获取到需要的数据
  • 缓存不命中:缓存中无法获取所需数据,需要再次查询数据库或者其他数据存储载体。

缓存命中率 = 缓存中获取数据次数/获取数据总次数

通常来说,缓存命中率越高,缓存的收益越高,应用的性能也就越好。

11. 怎么提高缓存命中率?

  1. 缓存预加载
  2. 增加缓存存储量
  3. 调整缓存存储数据类型
  4. 提升缓存更新频次

12. 请介绍一下 Spring 注解缓存

Spring 3.1 版本之后,加入了注解缓存操作技术,对缓存使用进行了具体的定义操作,添加了部分自定义的 annotation,能够非常便捷的获取缓存对象以及释放缓存对象。

常用的注解:

  1. @Cacheable:针对方法配置,根据方法的请求参数对其结果进行缓存
  2. @CachePut:针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
  3. @CacheEvict:主要针对方法配置,能够根据一定的条件对缓存进行清空

13. 设计一下在交易网站首页展示当天最热门售卖商品的前五十名商品列表?

这个题目很明显可以看出来,考察 Redis 的实际技术选型。 从题目中我们可以看到几个信息:

  1. 首页:代表访问量非常大
  2. 当天: 热门选择的时间跨度为当天的 24 小时
  3. 热门售卖商品:售卖的越多越热门,售卖个数

那我们可以就可以使用 Redis 来存储这个热门商品的榜单列表, 使用 Redis 的 zset 来进行存储。

  • Key:为商品 ID
  • value:商品当天售卖次数

然后就可以获取有序的产品售卖排行榜。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!