FAQ:Redis
关于
关于 Redis 的常见问题、面试问题。
概念
什么是Redis?
Redis 全称为:Remote Dictionary Server(远程数据服务),是一个基于内存且支持持久化的高性能 key-value 数据库。具备一下三个基本特征:
- 多数据类型
- 持久化机制
- 主从同步
Redis 有什么优点和缺点?
优点:
- 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
- 支持数据持久化,支持AOF和RDB两种持久化方式。
- 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
- 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点:
- 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis 适合的场景主要局限在较小数据量的高性能操作和运算上。
- Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。【???】
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
- Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
Redis 和 Memcached 的区别有哪些?
从以下8个方面来讲:
- Redis 和 Memcache 都是将数据存放在内存中,都是内存数据库。不过 Memcache 还可用于缓存其他东西,例如图片、视频等等。
- Memcache 仅支持key-value结构的数据类型,Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,hash等数据结构的存储。
- 虚拟内存– Redis 当物理内存用完时,可以将一些很久没用到的value 交换到磁盘分布式–设定 Memcache 集群,利用 magent 做一主多从; Redis 可以做一主多从。都可以一主一从
- 存储数据安全– Memcache 挂掉后,数据没了; Redis 可以定期保存到磁盘(持久化)
- Memcache 的单个value最大 1m,Redis 的单个value最大 512m。
- 灾难恢复– Memcache 挂掉后,数据不可恢复; Redis 数据丢失后可以通过 aof 恢复
- Redis 原生就支持集群模式, Redis3.0 版本中,官方便能支持Cluster模式了, Memcached 没有原生的集群模式,需要依赖客户端来实现,然后往集群中分片写入数据。
- Memcached 网络IO模型是多线程,非阻塞IO复用的网络模型,原型上接近于 nignx。而 Redis使用单线程的IO复用模型,自己封装了一个简单的 AeEvent 事件处理框架,主要实现类epoll,kqueue 和 select,更接近于Apache早期的模式。
数据类型
Redis 的数据类型有哪些?
一般文章都是以Redis只有 5 种数据类型,还有 Bitmaps、HyperLogLogs、Streams 等。
中文官网上的解释:
一个字符串类型的值能存储最大容量是多少?
单线程
Redis 是单线程的吗?
Redis 为什么设计成单线程的?
请说说 Redis 的线程模型?
为什么 Redis 单线程模型也能效率这么高?
可以从下面5个方面来回答:
- C语言实现,效率高
- 纯内存操作
- 基于非阻塞的IO复用模型机制
- 单线程的话就能避免多线程的频繁上下文切换问题
- 丰富的数据结构(全程采用hash结构,读取速度非常快,对数据存储进行了一些优化,比如亚索表,跳表等)【???】
Redis 是单线程的,如何提高多核 CPU 的利用率?
在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用。
在某些时候,无论如何一个服务器是不够的,所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。
事务
什么是 Redis 事务?
可以一次性执行多条命令,本质上是一组命令的集合。一个事务中的所有命令都会序列化,然后按顺序地串行化执行,而不会被插入其他命令。
Redis 事务的注意点有哪些?
- 不支持回滚,如果事务中有错误的操作,无法回滚到处理前的状态,需要开发者处理。
- 在执行完当前事务内所有指令前,不会同时执行其他客户端的请求。
为什么Redis 事务不支持回滚?
Redis 事务不支持回滚,如果遇到问题,会继续执行余下的命令。 这一点和关系型数据库不太一致。这样处理的原因有:
- 只有语法错误,Redis 才会执行失败,例如错误类型的赋值, 这就是说从程序层面完全可以捕获以及解决这些问题
- 支持回滚需要增加很多工作,不支持的情况下,Redis 可以保持简单、速度快的特性
持久化
Redis 有几种持久化方式?
说说 RDB 的优缺点
优点:
- 灵活设置备份频率和周期。你可能打算每个小时归档一次最近 24 小时的数据,同时还要每天归档一次最近 30 天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
- 非常适合冷备份,对于灾难恢复而言,RDB 是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。推荐,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说 Amazon 的 S3 云服务上去,在国内可以是阿里云的 OSS 分布式存储上。
- 性能最大化。对于 Redis 的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行 IO 操作了。也就是说,RDB 对 Redis 对外提供的读写服务,影响非常小,可以让 Redis 保持高性能。
- 恢复更快。相比于 AOF 机制,RDB 的恢复速度更更快,更适合恢复数据,特别是在数据集非常大的情况。
缺点:
- 不能避免数据丢失。如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么 RDB 将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
- 所以,RDB 实际场景下,需要和 AOF 一起使用。
- 大数据量时,对服务器影响大。由于 RDB 是通过 fork 子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是 1 秒钟。所以,RDB 建议在业务低估,例如在半夜执行。
说说 AOF 的优缺点
优点:
- 该机制可以带来更高的数据安全性(即数据持久性)。
- Redis 中提供了 3 种同步策略:
- “每秒同步”:事实上也是异步完成的,其效率也是非常高的。所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。
- “每次修改同步”:可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率最低。
- “不同步”。
- 由于该机制对日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。
- 因为以 append-only 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高。
- 另外,如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在 Redis 下一次启动之前,我们可以通过 redis-check-aof 工具来帮助我们解决数据一致性的问题。
- 如果 AOF 日志过大,Redis 可以自动启用 rewrite 机制。即使出现后台重写操作,也不会影响客户端的读写。因为在 rewrite log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。
- AOF 包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
缺点:
- 文件较大。对于相同数量的数据集而言,AOF 文件通常要大于 RDB 文件。
- 恢复较慢。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
- 执行效率较低。根据同步策略的不同,AOF 在运行效率上往往会慢于 RDB,总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和 RDB 一样高效。
- 恢复数据可能与原数据不一致。以前 AOF 发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似 AOF 这种较为复杂的基于命令日志/merge/回放的方式,比基于 RDB 每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有 bug。不过 AOF 就是为了避免 rewrite 过程导致的 bug,因此每次 rewrite 并不是基于旧的指令日志进行 merge 的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。
两种持久化方式该如何选择?
bgsave 做镜像全量持久化,AOF 做增量持久化。
- 因为 bgsave 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要 AOF 来配合使用。在 Redis 实例重启时,会使用 bgsave 持久化文件重新构建内存,再使用 AOF 重放近期的操作指令来实现完整恢复重启之前的状态。
- 一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
- 如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失,那么你可以只使用 RDB 持久化。
有很多用户都只使用 AOF 持久化,但并不推荐这种方式:因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快,除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的问题。
面试官追问那如果突然机器掉电会怎样?
- 如果仅使用“RDB”,则可能丢失数分钟的数据。
- 如果使用“RDB+AOF”或“AOF”,则:取决于 AOF 日志 sync 属性的配置:
- “每次修改”:如果不要求性能,在每条写指令时都 sync 一下磁盘,就不会丢失数据。
- “每秒”:但是在高性能的要求下每次都 sync 是不现实的,一般都使用定时 sync,比如 1 秒 1 次,这个时候最多就会丢失 1 秒的数据。
- 实际上,极端情况下,最多丢失 2 秒的数据。
- 因为 AOF 线程,负责每秒执行一次 fsync 操作,操作完成后,记录最后同步时间。主线程,负责对比上次同步时间,如果超过 2 秒,阻塞等待成功。
面试官追问 bgsave 的原理是什么?
fork 和 cow:
- fork:是指 Redis 通过创建子进程来进行 bgsave 操作。
- cow:指的是“copy on write”,子进程创建后,父子进程共享数据段;父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
bgsave 操作后,会产生 RDB 快照文件。
什么是 Redis Pipelining?
pipeline 就是把一组命令进行打包,然后一次性通过网络发送到 Redis,同时将执行的结果批量的返回回来。通过管道技术能够减少的I/O的调用次数。
内存回收与key失效机制
Redis 有几种数据“过期”策略?
【key失效机制】
Redis 有哪几种数据“淘汰”策略?
【内存回收策略】
集群
什么是 Redis 主从同步?
如何使用 Redis Sentinel 实现高可用?
如果使用 Redis Cluster 实现高可用?
Redis 的同步机制了解是什么?【!!!】
Redis可以使用“主从同步”,“从从同步”:
- 第一次同步时,主节点做一次 bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制节点,复制节点接受完成后将 rdb 镜像加载到内存。
- 加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。