什么是 Redis ?

什么是 Redis ?

Redis,全称 Remote Dictionary Server,是一个基于内存的高性能 Key-Value 数据库。html

另外,Redis 已经成为互联网公司在缓存组件选择的惟一,更多的关注点是,如何使用好 Redis 。java

Redis 有什么优势?

一、速度快node

由于数据存在内存中,相似于 HashMap ,HashMap 的优点就是查找和操做的时间复杂度都是O (1) 。git

Redis 本质上是一个 Key-Value 类型的内存数据库,很像Memcached ,整个数据库通通加载在内存当中进行操做,按期经过异步操做把数据库数据 flush 到硬盘上进行保存。github

由于是纯内存操做,Redis 的性能很是出色,每秒能够处理超过 10 万次读写操做,是已知性能最快的 Key-Value 数据库。面试

二、支持丰富数据类型redis

支持 String ,List,Set,Sorted Set,Hash 。算法

Redis 的出色之处不只仅是性能,Redis 最大的魅力是支持保存多种数据结构,此外单个 Value 的最大限制是1GB,不像 Memcached只能保存1MB的数据,所以Redis能够用来实现不少有用的功能。比方说:数据库

  • 用他的 List 来作 FIFO 双向链表,实现一个轻量级的高性能消息队列服务。
  • 用他的 Set 能够作高性能的 tag 系统等等。

三、丰富的特性缓存

  • 订阅发布 Pub / Sub 功能
  • Key 过时策略
  • 事务
  • 支持多个 DB
  • 计数

而且在 Redis 5.0 增长了 Stream 功能,一个新的强大的支持多播的可持久化的消息队列,提供相似 Kafka 的功能。

四、持久化存储

Redis 提供 RDB 和 AOF 两种数据的持久化存储方案,解决内存数据库最担忧的万一 Redis 挂掉,数据会消失掉。

Redis 有什么缺点?

  • 因为 Redis 是内存数据库,因此,单台机器,存储的数据量,跟机器自己的内存大小。虽然 Redis 自己有 Key 过时策略,可是仍是须要提早预估和节约内存。若是内存增加过快,须要按期删除数据。

    另外,可以使用 Redis Cluster、Codis 等方案,对 Redis 进行分区,从单机 Redis 变成集群 Redis 。

  • 若是进行完整重同步,因为须要生成 RDB 文件,并进行传输,会占用主机的 CPU ,并会消耗现网的带宽。不过 Redis2.8 版本,已经有部分重同步的功能,可是仍是有可能有完整重同步的。好比,新上线的备机。

  • 修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程当中,Redis 不能提供服务。

Redis 和 Memcached 的区别有哪些?

一、Redis 支持复杂的数据结构

  • Memcached 仅提供简单的字符串。
  • Redis 提供复杂的数据结构,丰富的数据操做。

也由于 Redis 支持复杂的数据结构,Redis 即便往于 Memcached 推出,却得到更多开发者的青睐。

Redis 相比 Memcached 来讲,拥有更多的数据结构,能支持更丰富的数据操做。若是须要缓存可以支持更复杂的结构和操做,Redis 会是不错的选择。

二、Redis 原生支持集群模式

  • 在 Redis3.x 版本中,官方便能支持 Cluster 模式。
  • Memcached 没有原生的集群模式,须要依靠客户端来实现往集群中分片写入数据。

三、性能对比

  • Redis 只使用单核,而 Memcached 可使用多核,因此平均每个核上 Redis在存储小数据时比 Memcached 性能更高。
  • 在 100k 以上的数据中,Memcached 性能要高于 Redis 。虽然 Redis 最近也在存储大数据的性能上进行优化,可是比起 Memcached,仍是稍有逊色。

更多关于性能的对比,能够看看 《Memcached 与 Redis 的关键性能指标比较》 。

四、内存使用效率对比

  • 简单的 Key-Value 存储的话,Memcached 的内存利用率更高,可使用相似内存池。
  • 若是 Redis 采用 hash 结构来作 key-value 存储,因为其组合式的压缩, 其内存利用率会高于 Memcached 。

  • Redis 和 Memcached 的内存管理方法不一样,Redis 采用的是包装的 malloc/free , 相较于 Memcached 的内存管理方法 tcmalloc / jmalloc 来讲,要简单不少 。

五、网络 IO 模型

  • Memcached 是多线程,非阻塞 IO 复用的网络模型,原型上接近 Nignx 。
  • Redis 使用单线程的 IO 复用模型,本身封装了一个简单的 AeEvent 事件处理框架,主要实现了 epoll, kqueue 和 select ,更接近 Apache 早期的模式。

TODO 有点看不懂,找亚普表弟确认中。

六、持久化存储

  • Memcached 不支持持久化存储,重启时,数据被清空。
  • Redis 支持持久化存储,重启时,能够恢复已持久化的数据。

也推荐阅读下 《脚踏两只船的困惑 - Memcached 与 Redis》 。

请说说 Redis 的线程模型?

艿艿:这个是我从网络上找的资料,讲的灰常不错。

redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,因此 redis 才叫作单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,根据 socket 上的事件来选择对应的事件处理器进行处理。

文件事件处理器的结构包含 4 个部分:

  • 多个 socket
  • IO 多路复用程序
  • 文件事件分派器
  • 事件处理器(链接应答处理器、命令请求处理器、命令回复处理器)

多个 socket 可能会并发产生不一样的操做,每一个操做对应不一样的文件事件,可是 IO 多路复用程序会监听多个 socket,会将 socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

来看客户端与 redis 的一次通讯过程:

redis-single-thread-model

  • 客户端 socket01 向 redis 的 server socket 请求创建链接,此时 server socket 会产生一个 AE_READABLE 事件,IO 多路复用程序监听到 server socket 产生的事件后,将该事件压入队列中。文件事件分派器从队列中获取该事件,交给链接应答处理器。链接应答处理器会建立一个能与客户端通讯的 socket01,并将该 socket01 的 AE_READABLE事件与命令请求处理器关联。
  • 假设此时客户端发送了一个 set key value 请求,此时 redis 中的 socket01 会产生 AE_READABLE 事件,IO 多路复用程序将事件压入队列,此时事件分派器从队列中获取到该事件,因为前面 socket01 的 AE_READABLE 事件已经与命令请求处理器关联,所以事件分派器将事件交给命令请求处理器来处理。命令请求处理器读取 socket01 的 key value 并在本身内存中完成 key value 的设置。操做完成后,它会将 socket01 的 AE_WRITABLE 事件与令回复处理器关联。
  • 若是此时客户端准备好接收返回结果了,那么 redis 中的 socket01 会产生一个 AE_WRITABLE 事件,一样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 socket01 输入本次操做的一个结果,好比 ok,以后解除 socket01 的 AE_WRITABLE 事件与命令回复处理器的关联。

这样便完成了一次通讯。😈 耐心理解一下,灰常重要。若是仍是不能理解,能够在网络上搜一些资料,在理解理解。

为何 Redis 单线程模型也能效率这么高?

  • 一、纯内存操做。

    Redis 为了达到最快的读写速度,将数据都读到内存中,并经过异步的方式将数据写入磁盘。因此 Redis 具备快速和数据持久化的特征。

    若是不将数据放在内存中,磁盘 I/O 速度为严重影响 Redis 的性能。

  • 二、核心是基于非阻塞的 IO 多路复用机制。

  • 三、单线程反而避免了多线程的频繁上下文切换问题。

    Redis 利用队列技术,将并发访问变为串行访问,消除了传统数据库串行控制的开销

  • 四、Redis 全程使用 hash 结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。

Redis 有几种持久化方式?

持久化方式

Redis 提供了两种方式,实现数据的持久化到硬盘。

  • 【全量】RDB 持久化,是指在指定的时间间隔内将内存中的数据集快照写入磁盘。实际操做过程是,fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。
  • 【增量】AOF持久化,以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,能够打开文件看到详细的操做记录。

两者的区别

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

img

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

img

两者优缺点

RDB存在哪些优点呢?

  • 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是很是完美的。好比,你可能打算每一个小时归档一次最近24小时的数据,同时还要天天归档一次最近30天的数据。经过这样的备份策略,一旦系统出现灾难性故障,咱们能够很是容易的进行恢复。
  • 对于灾难恢复而言,RDB是很是不错的选择。由于咱们能够很是轻松的将一个单独的文件压缩后再转移到其它存储介质上。
  • 性能最大化。对于Redis的服务进程而言,在开始持久化时,它惟一须要作的只是fork出子进程,以后再由子进程完成这些持久化的工做,这样就能够极大的避免服务进程执行IO操做了。
  • 相比于AOF机制,若是数据集很大,RDB的启动效率会更高。

RDB又存在哪些劣势呢?

  • .若是你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。由于系统一旦在定时持久化以前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
  • 因为RDB是经过fork子进程来协助完成数据持久化工做的,所以,若是当数据集较大时,可能会致使整个服务器中止服务几百毫秒,甚至是1秒钟。

AOF的优点有哪些呢?

  • 该机制能够带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不一样步。事实上,每秒同步也是异步完成的,其效率也是很是高的,所差的是一旦系统出现宕机现象,那么这一秒钟以内修改的数据将会丢失。而每修改同步,咱们能够将其视为同步持久化,即每次发生的数据变化都会被当即记录到磁盘中。能够预见,这种方式在效率上是最低的。至于无同步,无需多言,我想你们都能正确的理解它。
  • 因为该机制对日志文件的写入操做采用的是append模式,所以在写入过程当中即便出现宕机现象,也不会破坏日志文件中已经存在的内容。然而若是咱们本次操做只是写入了一半数据就出现了系统崩溃问题,不用担忧,在Redis下一次启动以前,咱们能够经过redis-check-aof工具来帮助咱们解决数据一致性的问题。
  • 若是日志过大,Redis能够自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会建立一个新的文件用于记录此期间有哪些修改命令被执行。所以在进行rewrite切换时能够更好的保证数据安全性。
  • AOF包含一个格式清晰、易于理解的日志文件用于记录全部的修改操做。事实上,咱们也能够经过该文件完成数据的重建。

AOF的劣势有哪些呢?

  • 对于相同数量的数据集而言,AOF文件一般要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
  • 根据同步策略的不一样,AOF在运行效率上每每会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB同样高效。

两者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),仍是愿意写操做频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再作备份(rdb)。rdb这个就更有些 eventually consistent 的意思了。

经常使用配置

RDB持久化配置

Redis会将数据集的快照dump到dump.rdb文件中。此外,咱们也能够经过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件以后,咱们搜索save,能够看到下面的配置信息:

1
2
3
save 900 1         # 在900秒(15分钟)以后,若是至少有1个key发生变化,则dump内存快照。
save 300 10        # 在300秒(5分钟)以后,若是至少有10个key发生变化,则dump内存快照。
save 60 10000      # 在60秒(1分钟)以后,若是至少有10000个key发生变化,则dump内存快照。

AOF持久化配置

在Redis的配置文件中存在三种同步方式,它们分别是:

1
2
3
appendfsync always     # 每次有数据修改发生时都会写入AOF文件。
appendfsync everysec   # 每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no         # 从不一样步。高效可是数据不会被持久化。

如何选择

  • 不要仅仅使用 RDB,由于那样会致使你丢失不少数据

  • 也不要仅仅使用 AOF,由于那样有两个问题,第一,你经过 AOF 作冷备,没有 RDB 作冷备,来的恢复速度更快; 第二,RDB 每次简单粗暴生成数据快照,更加健壮,能够避免 AOF 这种复杂的备份和恢复机制的 bug 。

  • Redis 支持同时开启开启两种持久化方式,咱们能够综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,做为数据恢复的第一选择; 用 RDB 来作不一样程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可使用 RDB 来进行快速的数据恢复。

    • 若是同时使用 RDB 和 AOF 两种持久化机制,那么在 Redis 重启的时候,会使用 AOF 来从新构建数据,由于 AOF 中的数据更加完整

      通常来讲, 若是想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。若是你很是关心你的数据, 但仍然能够承受数分钟之内的数据丢失,那么你能够只使用 RDB 持久化。

      有不少用户都只使用 AOF 持久化,但并不推荐这种方式:由于定时生成 RDB 快照(snapshot)很是便于进行数据库备份, 而且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此以外,使用 RDB 还能够避免以前提到的 AOF 程序的 bug。

在 Redis4.0 版本开始,容许你使用 RDB-AOF 混合持久化方式,详细可见 《Redis4.0 之 RDB-AOF 混合持久化》 。也所以,RDB 和 AOF 同时使用,是但愿达到安全的持久化的推荐方式。

自动化触发 RDB 持久化的方式

  • 根据 redis.conf 配置中 SAVE m n 定时触发(使用的BGSAVE)
  • 主从复制时,主节点自动触发
  • 执行 Debug Reload
  • 执行 Shutdown 且没有开启 AOF 持久化

BGSAVE 原理:

timg

重要知识:

  • bgsave 作镜像全量持久化,AOF 作增量持久化。由于 bgsave 会耗费较长时间,不够实时,在停机的时候会致使大量丢失数据,因此须要 AOF 来配合使用。在 Redis 实例重启时,会使用 bgsave 持久化文件从新构建内存,再使用 AOF 重放近期的操做指令来实现完整恢复重启以前的状态。
  • 对方追问那若是忽然机器掉电会怎样?取决于 AOF 日志 sync 属性的配置,若是不要求性能,在每条写指令时都 sync 一下磁盘,就不会丢失数据。可是在高性能的要求下每次都 sync 是不现实的,通常都使用定时 sync ,好比 1 秒 1 次,这个时候最多就会丢失 1 秒的数据。
  • 对方追问 bgsave 的原理是什么?你给出两个词汇就能够了,fork 和 cow 。fork 是指 Redis 经过建立子进程来进行 bgsave 操做。cow 指的是 copy on write ,子进程建立后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

Redis 有几种数据“过时”策略?

Redis 的过时策略,就是指当 Redis 中缓存的 key 过时了,Redis 如何处理。

Redis 提供了 3 种数据过时策略:

  • 被动删除:当读/写一个已通过期的 key 时,会触发惰性删除策略,直接删除掉这个过时 key 。
  • 主动删除:因为惰性删除策略没法保证冷数据被及时删掉,因此 Redis 会按期主动淘汰一批已过时的 key 。
  • 主动删除:当前已用内存超过 maxmemory 限定时,触发主动清理策略,即 「数据“淘汰”策略」 。

在 Redis 中,同时使用了上述 3 种策略,即它们非互斥的。

想要进一步了解,能够看看 《关于 Redis 数据过时策略》 文章。

Redis 有哪几种数据“淘汰”策略?

Redis 内存数据集大小上升到必定大小的时候,就会进行数据淘汰策略。

Redis 提供了 6 种数据淘汰策略:

  1. volatile-lru
  2. volatile-ttl
  3. volatile-random
  4. allkeys-lru
  5. allkeys-random
  6. no-enviction

具体的 每种数据淘汰策略的定义,和 如何选择讨论策略,可见 《Redis实战(二) 内存淘汰机制》 。

Redis LRU 算法

另外,Redis 的 LRU 算法,并非一个严格的 LRU 实现。这意味着 Redis 不能选择最佳候选键来回收,也就是最久未被访问的那些键。相反,Redis 会尝试执行一个近似的 LRU 算法,经过采样一小部分键,而后在采样键中回收最适合(拥有最久未被访问时间)的那个。

艿艿:这个是从网络上找到的一个神奇的问题,而且看了答案以后,以为有点莫名的对不上。

因此,感受这个问题的目的是,如何保证热点数据不要被淘汰。

在 「Redis 有哪几种数据“淘汰”策略?」 问题中,咱们已经看到,“Redis 内存数据集大小上升到必定大小的时候,就会进行数据淘汰策略。” 。

那么,若是咱们此时要保证热点数据不被淘汰,那么须要选择 volatile-lru 或 allkeys-lru 这两个基于 LRU 算法的淘汰策略。

相比较来讲,最终会选择 allkeys-lru 淘汰策略。缘由是,若是咱们的应用对缓存的访问符合幂律分布,也就是存在相对热点数据,或者咱们不太清楚咱们应用的缓存访问分布情况,咱们能够选择 allkeys-lru 策略。

Redis 回收进程如何工做的?

理解回收进程如何工做是很是重要的:

  • 一个客户端运行了新的命令,添加了新的数据
  • Redis 检查内存使用状况,若是大于 maxmemory 的限制, 则根据设定好的策略进行回收。
  • Redis 执行新命令……

因此咱们不断地穿越内存限制的边界,经过不断达到边界而后不断地回收回到边界如下(跌宕起伏)。

若是有大量的 key 须要设置同一时间过时,通常须要注意什么?

若是大量的 key 过时时间设置的过于集中,到过时的那个时间点,Redis可能会出现短暂的卡顿现象。

通常须要在时间上加一个随机值,使得过时时间分散一些。

Redis 有哪些数据结构?

若是你是 Redis 普通玩家,可能你的回答是以下五种数据结构:

  • 字符串 String
  • 字典Hash
  • 列表List
  • 集合Set
  • 有序集合 SortedSet

若是你是 Redis 中级玩家,还须要加上下面几种数据结构:

  • HyperLogLog
  • Geo
  • Pub / Sub

若是你是 Redis 高端玩家,你可能玩过 Redis Module ,能够再加上下面几种数据结构:

  • BloomFilter
  • RedisSearch
  • Redis-ML
  • JSON

另外,在 Redis 5.0 增长了 Stream 功能,一个新的强大的支持多播的可持久化的消息队列,提供相似 Kafka 的功能。😈 默默跟面试官在装一波。

聊聊 Redis 使用场景

Redis 可用的场景很是之多:

  • 数据缓存
  • 会话缓存
  • 时效性数据
  • 访问频率
  • 计数器
  • 社交列表
  • 记录用户断定信息
  • 交集、并集和差集
  • 热门列表与排行榜
  • 最新动态
  • 消息队列
  • 分布式锁

详细的介绍,能够看看以下文章:

请用 Redis 和任意语言实现一段恶意登陆保护的代码,限制 1 小时内每用户 Id 最多只能登陆 5 次。

用列表实现,列表中每一个元素表明登录时间,只要最后的第 5 次登录时间和如今时间差不超过 1 小时就禁止登录。

具体的代码实现,能够看看 《一道 Redis 面试题》 。

Redis 支持的 Java 客户端都有哪些?

使用比较普遍的有三个 Java 客户端:

  • Redisson

    Redisson ,是一个高级的分布式协调 Redis 客服端,能帮助用户在分布式环境中轻松实现一些 Java 的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

  • Jedis

    Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支持。

    Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,Jedis 功能较为简单,不支持字符串操做,不支持排序、事务、管道、分区等 Redis 特性。

    Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者可以将精力更集中地放在处理业务逻辑上。

  • Lettuce

    Lettuce 是一个可伸缩线程安全的 Redis 客户端。多个线程能够共享同一个 RedisConnection 。它利用优秀 Netty NIO 框架来高效地管理多个链接。

Redis 官方推荐使用 Redisson 或 Jedis 。

Spring Boot 2.x 内置使用 Lettuce 。

如何使用 Redis 实现分布式锁?

方案一:set 指令

先拿 setnx 来争抢锁,抢到以后,再用 expire 给锁加一个过时时间防止锁忘记了释放。

  • 这时候对方会告诉你说你回答得不错,而后接着问若是在 setnx 以后执行 expire 以前进程意外 crash 或者要重启维护了,那会怎么样?
  • 这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你须要抓一抓本身得脑壳,故做思考片刻,好像接下来的结果是你主动思考出来的,而后回答:我记得 set 指令有很是复杂的参数,这个应该是能够同时把 setnx 和 expire 合成一条指令来用的!对方这时会显露笑容,内心开始默念:摁,这小子还不错。

因此,咱们可使用 set 指令,实现分布式锁。指令以下:

1
SET key value [EX seconds] [PX milliseconds] [NX|XX]

方案二:redlock

set 指令的方案,适合用于在单机 Redis 节点的场景下,在多 Redis 节点的场景下,会存在分布式锁丢失的问题。因此,Redis 做者 Antirez 基于分布式环境下提出了一种更高级的分布式锁的实现方式:Redlock 。

具体的方案,胖友能够看看老友飞哥的两篇博客:

对比 Zookeeper 分布式锁

  • 从可靠性上来讲,Zookeeper 分布式锁好于 Redis 分布式锁。
  • 从性能上来讲,Redis 分布式锁好于 Zookeeper 分布式锁。

因此,没有绝对的好坏,能够根据本身的业务来具体选择。

如何使用 Redis 实现消息队列?

通常使用 list 结构做为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。

  • 若是对方追问可不能够不用 sleep 呢?list 还有个指令叫 blpop ,在没有消息的时候,它会阻塞住直到消息到来。
  • 若是对方追问能不能生产一次消费屡次呢?使用 pub / sub 主题订阅者模式,能够实现 1:N 的消息队列。
  • 若是对方追问 pub / sub 有什么缺点?在消费者下线的状况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。
  • 若是对方追问 redis 如何实现延时队列?我估计如今你很想把面试官一棒打死若是你手上有一根棒球棍的话,怎么问的这么详细。可是你很克制,而后神态自若的回答道:使用 sortedset ,拿时间戳做为 score ,消息内容做为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒以前的数据轮询进行处理。

到这里,面试官暗地里已经对你竖起了大拇指。可是他不知道的是此刻你却竖起了中指,在椅子背后。

固然,实际上 Redis 真的真的真的不推荐做为消息队列使用,它最多只是消息队列的存储层,上层的逻辑,还须要作大量的封装和支持。

另外,在 Redis 5.0 增长了 Stream 功能,一个新的强大的支持多播的可持久化的消息队列,提供相似 Kafka 的功能。

什么是 Redis Pipelining ?

一次请求/响应服务器能实现处理新的请求即便旧的请求还未被响应。这样就能够将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。

这就是管道(pipelining),是一种几十年来普遍使用的技术。例如许多 POP3 协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。

Redis 很早就支持管道(pipelining)技术,所以不管你运行的是什么版本,你均可以使用管道(pipelining)操做 Redis。

Redis 如何作大量数据插入?

Redis2.6 开始,Redis-cli 支持一种新的被称之为 pipe mode 的新模式用于执行大量数据插入工做。

具体可见 《Redis 大量数据插入》 文章。

什么是 Redis 事务?

和众多其它数据库同样,Redis 做为 NoSQL 数据库也一样提供了事务机制。在Redis中,MULTI / EXEC / DISCARD / WATCH 这四个命令是咱们实现事务的基石。相信对有关系型数据库开发经验的开发者而言这一律念并不陌生,即使如此,咱们仍是会简要的列出 Redis 中事务的实现特征:

  • 一、在事务中的全部命令都将会被串行化的顺序执行,事务执行期间,Redis 不会再为其它客户端的请求提供任何服务,从而保证了事物中的全部命令被原子的执行。

  • 二、和关系型数据库中的事务相比,在 Redis 事务中若是有某一条命令执行失败,其后的命令仍然会被继续执行。

  • 三、咱们能够经过 MULTI 命令开启一个事务,有关系型数据库开发经验的人能够将其理解为 "BEGIN TRANSACTION"语句。在该语句以后执行的命令都,将被视为事务以内的操做,最后咱们能够经过执行 EXEC / DISCARD 命令来提交 / 回滚该事务内的全部操做。这两个 Redis 命令,可被视为等同于关系型数据库中的 COMMIT / ROLLBACK 语句。

  • 四、在事务开启以前,若是客户端与服务器之间出现通信故障并致使网络断开,其后全部待执行的语句都将不会被服务器执行。然而若是网络中断事件是发生在客户端执行 EXEC 命令以后,那么该事务中的全部命令都会被服务器执行。

  • 五、当使用 Append-Only 模式时,Redis 会经过调用系统函数 write 将该事务内的全部写操做在本次调用中所有写入磁盘。然而若是在写入的过程当中出现系统崩溃,如电源故障致使的宕机,那么此时也许只有部分数据被写入到磁盘,而另一部分数据却已经丢失。

    Redis 服务器会在从新启动时执行一系列必要的一致性检测,一旦发现相似问题,就会当即退出并给出相应的错误提示。此时,咱们就要充分利用 Redis 工具包中提供的 redis-check-aof 工具,该工具能够帮助咱们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复以后咱们就能够再次从新启动Redis服务器了。

如何实现 Redis CAS 操做?

在 Redis 的事务中,WATCH 命令可用于提供CAS(check-and-set)功能。

假设咱们经过 WATCH 命令在事务执行以前监控了多个 keys ,假若在 WATCH 以后有任何 Key 的值发生了变化,EXEC 命令执行的事务都将被放弃,同时返回 nil 应答以通知调用者事务执行失败。

具体的示例,能够看看 《Redis 事务锁 CAS 实现以及深刻误区》 。

Redis 集群都有哪些方案?

Redis 集群方案以下:

  • 一、Redis Sentinel
  • 二、Redis Cluster
  • 三、Twemproxy
  • 四、Codis
  • 五、客户端分片

关于前四种,能够看看 《Redis 实战(四)集群机制》 这篇文章。

关于最后一种,客户端分片,在 Redis Cluster 出现以前使用较多,目前已经使用比较少了。实现方式以下:

在业务代码层实现,起几个毫无关联的 Redis 实例,在代码层,对 Key 进行 hash 计算,而后去对应的 Redis 实例操做数据。

这种方式对 hash 层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。

选择

目前通常在选型上来讲:

  • 体量较小时,选择 Redis Sentinel ,单主 Redis 足以支撑业务。
  • 体量较大时,选择 Redis Cluster ,经过分片,使用更多内存。

    Redis 集群如何扩容?

这个问题,艿艿了解的也不是不少,建议在搜索有什么方案。

  • 若是 Redis 被当作缓存使用,使用一致性哈希实现动态扩容缩容。
  • 若是 Redis 被当作一个持久化存储使用,必须使用固定的 keys-to-nodes 映射关系,节点的数量一旦肯定不能变化。不然的话(即Redis 节点须要动态变化的状况),必须使用能够在运行时进行数据再平衡的一套系统,而当前只有 Redis Cluster、Codis 能够作到这样。

什么是 Redis 主从同步?

Redis 主从同步

Redis 的主从同步(replication)机制,容许 Slave 从 Master 那里,经过网络传输拷贝到完整的数据备份,从而达到主从机制。

  • 主数据库能够进行读写操做,当发生写操做的时候自动将数据同步到从数据库,而从数据库通常是只读的,并接收主数据库同步过来的数据。
  • 一个主数据库能够有多个从数据库,而一个从数据库只能有一个主数据库。
  • 第一次同步时,主节点作一次 bgsave 操做,并同时将后续修改操做记录到内存 buffer ,待完成后将 RDB 文件全量同步到复制节点,复制节点接受完成后将 RDB 镜像加载到内存。加载完成后,再通知主节点将期间修改的操做记录同步到复制节点进行重放就完成了同步过程。

好处

经过 Redis 的复制功,能能够很好的实现数据库的读写分离,提升服务器的负载能力。主数据库主要进行写操做,而从数据库负责读操做。

Redis 主从同步,是不少 Redis 集群方案的基础,例如 Redis Sentinel、Redis Cluster 等等。

更多详细,能够看看 《Redis 主从架构》 。

如何使用 Redis Sentinel 实现高可用?

能够看看 《Redis 哨兵集群实现高可用》 。

若是使用 Redis Cluster 实现高可用?

能够看看

说说 Redis 哈希槽的概念?

Redis Cluster 没有使用一致性 hash ,而是引入了哈希槽的概念。

Redis 集群有 16384 个哈希槽,每一个 key 经过 CRC16 校验后对 16384 取模来决定放置哪一个槽,集群的每一个节点负责一部分 hash 槽。

由于最大是 16384 个哈希槽,因此考虑 Redis 集群中的每一个节点都能分配到一个哈希槽,因此最多支持 16384 个 Redis 节点。

Redis Cluster 的主从复制模型是怎样的?

为了使在部分节点失败或者大部分节点没法通讯的状况下集群仍然可用,因此集群使用了主从复制模型,每一个节点都会有 N-1 个复制节点。

因此,Redis Cluster 能够说是 Redis Sentinel 带分片的增强版。也能够说:

  • Redis Sentinel 着眼于高可用,在 master 宕机时会自动将 slave 提高为 master ,继续提供服务。
  • Redis Cluster 着眼于扩展性,在单个 Redis 内存不足时,使用Cluster 进行分片存储。

Redis Cluster 方案什么状况下会致使整个集群不可用?

有 A,B,C 三个节点的集群,在没有复制模型的状况下,若是节点 B 宕机了,那么整个集群就会觉得缺乏 5501-11000 这个范围的槽而不可用。

Redis Cluster 会有写操做丢失吗?为何?

Redis 并不能保证数据的强一致性,而是【异步复制】,这意味这在实际中集群在特定的条件下可能会丢失写操做。

Redis 集群如何选择数据库?

Redis 集群目前没法作数据库选择,默认在 0 数据库。

请说说生产环境中的 Redis 是怎么部署的?

重点问题,仔细理解。

  • Redis Cluster,10 台机器,5 台机器部署了 redis 主实例,另外 5 台机器部署了 redis 的从实例,每一个主实例挂了一个从实例,5 个节点对外提供读写服务,每一个节点的读写高峰 qps 可能能够达到每秒 5 万,5 台机器最可能是 25 万读写请求每秒。
  • 机器是什么配置?32G 内存 + 8 核 CPU + 1T 磁盘,可是分配给 Redis 进程的是 10g 内存,通常线上生产环境,Redis 的内存尽可能不要超过 10g,超过 10g 可能会有问题。那么,5 台机器对外提供读写,一共有 50g 内存。
  • 由于每一个主实例都挂了一个从实例,因此是高可用的,任何一个主实例宕机,都会自动故障迁移,Redis 从实例会自动变成主实例继续提供读写服务。
  • 你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb 。100 条数据是 1mb ,10 万条数据是 1g 。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的请求量。
  • 其实大型的公司,会有基础架构的 team 负责缓存集群的运维。

什么是 Redis 分区?

这个问题,和 「Redis 集群都有哪些方案?」 是同类问题。

关于以下四个问题,直接看 《Redis 分区》 文章。

  • Redis 分区是什么?
  • 分区的优点?
  • 分区的不足?
  • 分区类型?

可能有胖友会懵逼,又是 Redis 主从复制,又是 Redis 分区,又是 Redis 集群。傻傻分不清啊!

  • Redis 分区是一种模式,将数据分区到不一样的 Redis 节点上,而 Redis 集群的 Redis Cluster、Twemproxy、Codis、客户端分片( 不包括 Redis Sentinel ) 这四种方案,是 Redis 分区的具体实现。
  • Redis 每一个分区,若是想要实现高可用,须要使用到 Redis 主从复制。

你知道有哪些 Redis 分区实现方案

Redis 分区方案,主要分红两种类型:

  • 客户端分区,就是在客户端就已经决定数据会被存储到哪一个 Redis 节点或者从哪一个 Redis 节点读取。大多数客户端已经实现了客户端分区。
    • 案例:Redis Cluster 和客户端分区。
  • 代理分区,意味着客户端将请求发送给代理,而后代理决定去哪一个节点写数据或者读数据。代理根据分区规则决定请求哪些 Redis 实例,而后根据 Redis 的响应结果返回给客户端。
    • 案例:Twemproxy 和 Codis 。

查询路由(Query routing)的意思,是客户端随机地请求任意一个 Redis 实例,而后由 Redis 将请求转发给正确的 Redis 节点。Redis Cluster 实现了一种混合形式的查询路由,但并非直接将请求从一个Redis 节点转发到另外一个 Redis 节点,而是在客户端的帮助下直接 redirect 到正确的 Redis 节点。

分布式 Redis 是前期作仍是后期规模上来了再作好?为何??

以下是网络上的一个大答案:

既然 Redis 是如此的轻量(单实例只使用1M内存),为防止之后的扩容,最好的办法就是一开始就启动较多实例。即使你只有一台服务器,你也能够一开始就让 Redis 以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。

一开始就多设置几个 Redis 实例,例如 32 或者 64 个实例,对大多数用户来讲这操做起来可能比较麻烦,可是从长久来看作这点牺牲是值得的。

这样的话,当你的数据不断增加,须要更多的 Redis 服务器时,你须要作的就是仅仅将 Redis 实例从一台服务迁移到另一台服务器而已(而不用考虑从新分区的问题)。一旦你添加了另外一台服务器,你须要将你一半的 Redis 实例从第一台机器迁移到第二台机器。

  • 和飞哥沟通了下,这个操做不是很合理。
  • 不管怎么说,建议,须要搭建下 Redis Sentinel 高可用,至于拓展性,根据本身的状况,是否使用 Redis Cluster 集群

Redis 有哪些重要的健康指标?

推荐阅读 《Redis 几个重要的健康指标》

  • 存活状况
  • 链接数
  • 阻塞客户端数量
  • 使用内存峰值
  • 内存碎片率
  • 缓存命中率
  • OPS
  • 持久化
  • 失效KEY
  • 慢日志

如何提升 Redis 命中率?

推荐阅读 《如何提升缓存命中率(Redis)》 。

怎么优化 Redis 的内存占用

推荐阅读 《Redis 的内存优化》

  • redisObject 对象
  • 缩减键值对象
  • 共享对象池
  • 字符串优化
  • 编码优化
  • 控制 key 的数量

    一个 Redis 实例最多能存放多少的 keys?List、Set、Sorted Set 他们最多能存放多少元素?

一个 Redis 实例,最多能存放多少的 keys ,List、Set、Sorted Set 他们最多能存放多少元素。

理论上,Redis 能够处理多达 2^32 的 keys ,而且在实际中进行了测试,每一个实例至少存放了 2 亿 5 千万的 keys。

任何 list、set、和 sorted set 均可以放 2^32 个元素。

假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,若是将它们所有找出来?

使用 keys 指令能够扫出指定模式的 key 列表。

  • 对方接着追问:若是这个 Redis 正在给线上的业务提供服务,那使用keys指令会有什么问题?
  • 这个时候你要回答 Redis 关键的一个特性:Redis 的单线程的。keys 指令会致使线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可使用 scan 指令,scan 指令能够无阻塞的提取出指定模式的 key 列表,可是会有必定的重复几率,在客户端作一次去重就能够了,可是总体所花费的时间会比直接用 keys 指令长。

Redis 常见的性能问题都有哪些?如何解决?

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

  • Master 写内存快照,save 命令调度 rdbSave 函数,会阻塞主线程的工做,当快照比较大时对性能影响是很是大的,会间断性暂停服务,因此 Master 最好不要写内存快照。
  • Master AOF 持久化,若是不重写 AOF 文件,这个持久化方式对性能的影响是最小的,可是 AOF 文件会不断增大,AOF 文件过大会影响 Master 重启的恢复速度。
  • 因此,Master 最好不要作任何持久化工做,包括内存快照和 AOF 日志文件,特别是不要启用内存快照作持久化。若是数据比较关键,某个 Slave 开启AOF备份数据,策略为每秒同步一次

二、Master 调用 BGREWRITEAOF 重写 AOF 文件,AOF 在重写的时候会占大量的 CPU 和内存资源,致使服务 load 太高,出现短暂服务暂停现象。

三、尽可能避免在压力很大的主库上增长从库。

四、主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3... 。

  • 这样的结构,也方便解决单点故障问题,实现 Slave 对 Master 的替换。若是 Master挂了,能够马上启用 Slave1 作 Master ,其余不变。

五、Redis 主从复制的性能问题,为了主从复制的速度和链接的稳定性,Slave 和 Master 最好在同一个局域网内。


和飞哥沟经过后,他们主节点开启 AOF ,从节点开启 AOF + RDB 。

和晓峰沟通后,他们主节点开启 AOF ,从节点开启 RDB 居多,也有开启 AOF + RDB 的。

修改配置不重启 Redis 会实时生效吗?

针对运行实例,有许多配置选项能够经过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。

从 Redis 2.2 开始,能够从 AOF 切换到 RDB 的快照持久性或其余方式而不须要重启 Redis。检索 CONFIG GET * 命令获取更多信息。

但偶尔从新启动是必须的,如为升级 Redis 程序到新的版本,或者当你须要修改某些目前 CONFIG 命令还不支持的配置参数的时候。

其余问题

有些比较凶残的面试官,可能会问咱们一些 Redis 数据结构的问题,例如:

  • Skiplist 插入和查询原理?

  • 压缩列表的原理?

  • Redis 底层为何使用跳跃表而不是红黑树?

    跳跃表在范围查找的时候性能比较高。

参考连接

相关文章
相关标签/搜索