原创

Redis面试20题

Redis 面试 20 题

redis 作为高性能 kv 数据库,受到了广大用户的喜爱和使用,本文整理常见的 20 个知识点,覆盖 redis 的方方面面。

1.Redis 是什么?

是一个基于内存的高性能 key-value 数据库。

2.Redis 相比 memcached 有哪些优势:

  • memcached 所有的值均是简单的字符串,
  • redis 作为其替代者,支持更为丰富的数据类型,
  • redis 的速度比 memcached 快很多,
  • redis 可以持久化其数据。

3.Reids 常用 5 种数据类型

string,list,set,sorted set,hash

4.Reids6 种淘汰策略:

noeviction : 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外。

allkeys-lru :所有 key 通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。

volatile-lru :只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。

allkeys-random :所有 key 通用; 随机删除一部分 key。

volatile-random : 只限于设置了 expire 的部分; 随机删除一部分 key。

volatile-ttl : 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的 key。

5.为什么 Redis 是单线程的?

Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。

单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

6.Redis 是单线程的,但 Redis 为什么这么快?

完全基于内存 绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1);

数据结构简单 对数据操作也简单,Redis 中的数据结构是专门进行设计的;

采用单线程 避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

使用多路 I/O 复用模型 非阻塞 IO;这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程

使用底层模型不同 它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

7.Redis 内存模型

used_memory :Redis 分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即 swap);Redis 分配器后面会介绍。used_memory_human 只是显示更友好。

used_memory_rss :Redis 进程占据操作系统的内存(单位是字节),与 top 及 ps 命令看到的值是一致的;除了分配器分配的内存之外,used_memory_rss 还包括进程运行本身需要的内存、内存碎片等,但是不包括虚拟内存。

mem_fragmentation_ratio :内存碎片比率,该值是 used_memory_rss / used_memory 的比值。

mem_allocator :Redis 使用的内存分配器,在编译时指定;可以是 libc 、jemalloc 或者 tcmalloc,默认是 jemalloc;截图中使用的便是默认的 jemalloc。

8.Redis 内存划分

数据 作为数据库,数据是最主要的部分;这部分占用的内存会统计在 used_memory 中。 进程本身运行需要的内存 Redis 主进程本身运行肯定需要占用内存,如代码、常量池等等;这部分内存大约几兆,在大多数生产环境中与 Redis 数据占用的内存相比可以忽略。这部分内存不是由 jemalloc 分配,因此不会统计在 used_memory 中。

缓冲内存 缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF 缓冲区等;其中,客户端缓冲存储客户端连接的输入输出缓冲;复制积压缓冲用于部分复制功能;AOF 缓冲区用于在进行 AOF 重写时,保存最近的写入命令。在了解相应功能之前,不需要知道这些缓冲的细节;这部分内存由 jemalloc 分配,因此会统计在 used_memory 中。

内存碎片 内存碎片是 Redis 在分配、回收物理内存过程中产生的。例如,如果对数据的更改频繁,而且数据之间的大小相差很大,可能导致 redis 释放的空间在物理内存中并没有释放,但 redis 又无法有效利用,这就形成了内存碎片。内存碎片不会统计在 used_memory 中。

9.Redis 持久化方案:

RDB 和 AOF

10.AOF 常用配置总结

下面是 AOF 常用的配置项,以及默认值

appendonly no:可以配置为yes
appendfilename "appendonly.aof":AOF文件名
dir ./:RDB文件和AOF文件所在目录
appendfsync everysec:fsync持久化策略
no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡
auto-aof-rewrite-percentage 100:文件重写触发条件之一
auto-aof-rewrite-min-size 64mb:文件重写触发提交之一
aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

11.RDB 和 AOF 的优缺点

优点: RDB 文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比 AOF 快很多。当然,与 AOF 相比,RDB 最重要的优点之一是对性能的影响相对较小。

缺点: RDB 文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此 AOF 持久化成为主流。此外,RDB 文件需要满足特定格式,兼容性差(如老版本的 Redis 不兼容新版本的 RDB 文件

AOF 持久化与 RDB 持久化相对应,AOF 的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。

12.持久化策略选择

  • 如果 Redis 中的数据完全丢弃也没有关系(如 Redis 完全用作 DB 层数据的 cache),那么无论是单机,还是主从架构,都可以不进行任何持久化。

  • 在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择 RDB 对 Redis 的性能更加有利;如果只能接受秒级别的数据丢失,应该选择 AOF

  • 但在多数情况下,我们都会配置主从环境,slave 的存在既可以实现数据的热备,也可以进行读写分离分担 Redis 读请求,以及在 master 宕掉后继续提供服务。

13.Redis 常用管理命令

dbsize 返回当前数据库 key 的数量。
info 返回当前 redis 服务器状态和一些统计信息。
monitor 实时监听并返回redis服务器接收到的所有请求信息。
shutdown 把数据同步保存到磁盘上,并关闭redis服务。
config get parameter 获取一个 redis 配置参数信息。(个别参数可能无法获取)
config set parameter value 设置一个 redis 配置参数信息。(个别参数可能无法获取)
config resetstat 重置 info 命令的统计信息。(重置包括:keyspace 命中数、
keyspace 错误数、 处理命令数,接收连接数、过期 key 数)
debug object key 获取一个 key 的调试信息。
debug segfault 制造一次服务器当机。
flushdb 删除当前数据库中所有 key,此方法不会失败。小心慎用
flushall 删除全部数据库中所有 key,此方法不会失败。小心慎用

14.Reids 工具命令

#redis-server:Redis 服务器的 daemon 启动程序
#redis-cli:Redis 命令行操作工具。当然,你也可以用 telnet 根据其纯文本协议来操作
#redis-benchmark:Redis 性能测试工具,测试 Redis 在你的系统及你的配置下的读写性能
#redis-benchmark -n 100000 –c 50
#模拟同时由 50 个客户端发送 100000 个 SETs/GETs 查询
#redis-check-aof:更新日志检查
#redis-check-dump:本地数据库检查

15. redis 常见性能问题和解决方案:

Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件。

如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次。

为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网内。

尽量避免在压力很大的主库上增加从库。

16.redis 通讯协议

RESP 是 redis 客户端和服务端之前使用的一种通讯协议;

RESP 的特点:实现简单、快速解析、可读性好

17.Redis 分布式锁实现

先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。如果在 setnx 之后执行 expire 之前进程意外 crash 或者要重启维护了,那会怎么样?set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和 expire 合成一条指令来用的!

18.Redis 中海量数据的正确操作方式

利用 SCAN 系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成数据迭代。

19.SCAN 系列命令注意事项

  • SCAN 的参数没有 key,因为其迭代对象是 DB 内数据;
  • 返回值都是数组,第一个值都是下一次迭代游标;
  • 时间复杂度:每次请求都是 O(1),完成所有迭代需要 O(N),N 是元素数量;
  • 可用版本:version >= 2.8.0;

20.Reids 三种不同删除策略

定时删除

在设置键的过期时间的同时,创建一个定时任务,当键达到过期时间时,立即执行对键的删除操作

优点: 对内存友好,定时删除策略可以保证过期键会尽可能快地被删除,并释放国期间所占用的内存

缺点: 对 cpu 时间不友好,在过期键比较多时,删除任务会占用很大一部分 cpu 时间,在内存不紧张但 cpu 时间紧张的情况下,将 cpu 时间用在删除和当前任务无关的过期键上,影响服务器的响应时间和吞吐量

定期删除

每隔一点时间,程序就对数据库进行一次检查,删除里面的过期键,至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

优点: 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响定时删除策略有效地减少了因为过期键带来的内存浪费。

惰性删除

放任键过期不管,但在每次从键空间获取键时,都检查取得的键是否过期,如果过期的话,就删除该键,如果没有过期,

优点: 对 cpu 时间友好,在每次从键空间获取键时进行过期键检查并是否删除,删除目标也仅限当前处理的键,这个策略不会在其他无关的删除任务上花费任何 cpu 时间

缺点: 对内存不友好,过期键过期也可能不会被删除,导致所占的内存也不会释放。甚至可能会出现内存泄露的现象,当存在很多过期键,而这些过期键又没有被访问到,这会可能导致它们会一直保存在内存中,造成内存泄露。

正文到此结束