1、Redis 是什么?它的主要用途是什么?
答案: Redis 是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息代理。它支持多种数据结构,例如字符串、列表、哈希表、集合和有序集合。Redis 的主要用途包括缓存、会话存储、排行榜、计数器和发布/订阅模式等。
2、Redis 的优点是什么?
答案: Redis 的优点包括高性能、可扩展性、数据持久性、丰富的数据类型、支持事务和 Lua 脚本、以及灵活的配置选项。此外,Redis 支持多种编程语言,例如 Python、Java 和 Ruby,可以轻松地与应用程序集成。
3、Redis 如何实现数据持久性?
答案:
Redis 可以通过将数据保存到磁盘上的文件来实现数据持久性。
Redis 提供了多种持久化方式,包括 RDB 和 AOF。
RDB 将 Redis 数据保存到磁盘上的快照文件中,而 AOF 则记录 Redis 的写操作,并将其保存到磁盘上的日志文件中。在服务器启动时,Redis 可以从快照文件或日志文件中恢复数据。
4、Redis 如何处理并发访问?
答案: Redis 是单线程的,但它使用了异步 I/O 和多路复用技术,可以同时处理多个客户端请求。此外,Redis 使用了乐观锁机制来避免并发访问问题。如果两个客户端同时尝试修改同一个键的值,Redis 会根据操作的类型(例如 SET、INCRBY)执行不同的操作。
5、Redis 的数据结构有哪些?
答案: Redis 支持多种数据结构,包括字符串、列表、哈希表、集合和有序集合。字符串是最简单的数据结构,用于存储文本或二进制数据。列表是一个有序的字符串列表,可以用于实现队列、栈和发布/订阅模式等。哈希表用于存储键值对,类似于关联数组。集合是一个无序的字符串集合,可以用于实现交集、并集和差集等。有序集合是一个有序的字符串集合,每个字符串都有一个分数与之关联,可以用于实现排行榜和计数器等。
6、Redis的主从复制是什么?
答案: Redis的主从复制是指将一个Redis服务器的数据复制到其他的Redis服务器,使得每个服务器都能独立提供读操作服务。主从复制可以分为以下几个过程:
-
主服务器持久化操作:主服务器将写命令记录到AOF或RDB文件中。
-
从服务器同步操作:从服务器与主服务器建立连接,接收并执行主服务器的写命令。
-
从服务器在线复制:主服务器与从服务器断开连接,从服务器成为一个独立的Redis数据库,可以接受读操作请求。
7、Redis的过期策略是什么?
答: Redis通过过期时间来实现过期策略,主要有两种过期策略:
-
定期删除:Redis每隔一段时间就会遍历整个数据集,删除过期的键值对。
-
惰性删除:Redis在读写键值对时,会检查过期时间,如果过期则立即删除。
8、Redis和Memcached的区别是什么?
答:Redis和Memcached都是基于内存的缓存系统,但Redis比Memcached支持更多的数据结构,比如哈希、列表、集合、有序集合等,也可以持久化数据到磁盘上。此外,Redis还提供了更多的功能,比如发布订阅、Lua脚本、事务等。
9、Redis的架构设计是什么样的?
答:Redis的架构设计采用了单线程的方式,即所有的请求都由一个线程来处理。这种设计可以避免多线程的竞争问题,提高了性能和稳定性。同时,Redis也支持多个客户端的并发访问。
10、Redis支持哪些高级功能?
答:Redis支持多种高级功能,比如发布订阅、Lua脚本、事务等。发布订阅是一种消息传递模式,用于将消息广播给多个客户端。Lua脚本是一种嵌入式脚本语言,可以在Redis中执行。事务是一组命令的集合,可以保证这些命令的原子性。
11、Redis 有哪几种数据淘汰策略?
- noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部
分的写入指令,但 DEL 和几个例外) - allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有
空间存放。 - allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数
据有空间存放。
12、Redis 集群方案应该怎么做?都有哪些方案?
- twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通 redis 无任何区别,设
置好它下属的多个 redis 实例后,使用时在本需要连接 redis 的地方改为连接 twemproxy,它
会以一个代理的身份接收请求并使用一致性 hash 算法,将请求转接到具体 redis,将结果再
返回 twemproxy。使用方式简便(相对 redis 只需修改连接端口),对旧项目扩展的首选。 问
题:twemproxy 自身单端口实例的压力,使用一致性 hash 后,对 redis 节点数量改变时候的
计算值的改变,数据无法自动移动到新的节点。 - codis,目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在 节点数量
改变情况下,旧节点数据可恢复到新 hash 节点。 - redis cluster3.0 自带的集群,特点在于他的分布式算法不是一致性 hash,而是 hash 槽的概
念,以及自身支持节点设置从节点。具体看官方文档介绍。 - 在业务代码层实现,起几个毫无关联的 redis 实例,在代码层,对 key 进行 hash 计算,然
后去对应的 redis 实例操作数据。 这种方式对 hash 层代码要求比较高,考虑部分包括,节
点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。
13、谈一谈缓存穿透、缓存击穿和缓存雪崩,以及解决办法?
-
缓存穿透
问题:大量并发查询不存在的 KEY,在缓存和数据库中都不存在,同时给缓存和数据库带来压力。
原因:一般而言,缓存穿透有 2 种可能性:业务数据被误删,导致缓存和数据库中都没有数据。恶意进行 ddos 攻击。
分析:为什么会多次透传呢?不存在 一直为空,需要注意让缓存能够区分KEY不存在和查询到一个空值。
解决办法:缓存空值的 KEY,这样第一次不存在也会被加载会记录,下次拿到有这个略(异步线程负责维护缓存的数据,定期或根据条件触发更新),这样就不会触发更新。 -
缓存击穿
问题:某个 KEY 失效的时候,正好有大量并发请求访问这个KEY。
分析:跟穿透其实很像,属于比较偶然的。
解决办法:KEY 的更新操作添加全局互斥锁。完全以缓存为准,使用延迟异步加载的策将流量压力传导到数据库上,导致数据库压力过大甚至宕机。 -
缓存雪崩
问题:当某一时刻发生大规模的缓存失效的情况,导致大量的请求无法获取数据,从而KEY。Bloom 过滤或 RoaingBitmap 判断 KEY 是否存在,如果布隆过滤器中没有查到这个数据,就不去数据库中查。在处理请求前增加恶意请求检查,如果检测到是恶意攻击,则拒绝进行服务。完全以缓存为准,使用延迟异步加载的策略(异步线程负责维护缓存的数据,定期或根据条件触发更新),这样就不会触发更新。
原因:一般而言,缓存雪崩有 2 种可能性:大量的数据同一个时间失效:比如业务关系强相关的数据要求同时失效 Redis 宕机
分析:一般来说,由于更新策略、或者数据热点、缓存服务宕机等原因,可能会导致缓存数据同一个时间点大规模不可用,或者都更新。所以,需要我们的更新策略要在时间上合适,数据要均匀分享,缓存服务器要多台高可用。
解决办法:更新策略在时间上做到比较平均。如果数据需要同一时间失效,可以给这批数据加上一些随机值,使得这批数据不要在同一个时间过期,降低数据库的压力。使用的热数据尽量分散到不同的机器上。多台机器做主从复制或者多副本,实现高可用。做好主从的部署,当主节点挂掉后,能快速的使用从结点顶上。实现熔断限流机制,对系统进行负载能力控制。对于非核心功能的业务,拒绝其请求,只允许核心功能业务访问数据库获取数据。服务降价:提供默认返回值,或简单的提示信息。
14、Redis 数据结构 压缩列表和跳跃表的区别
- 压缩列表(ziplist)本质上就是一个字节数组,是 Redis 为了节约内存而设计的一种线性数据结构,可以包含多个元素,每个元素可以是一个字节数组或一个整数。
- 跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均 O(logN)、最坏O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。
15、一个字符串类型的值能存储最大容量是多少?
答:512M
16、Redis 常见的几种数据结构说一下?各自的使用场景?
- string
介绍:string 数据结构是简单的 key-value 类型。
使用场景: 一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等等。 - list
介绍:list 即是 链表
使用场景:发布与订阅或者说消息队列、慢查询。 - hash
介绍:hash 类似于 JDK1.8 前的 HashMap,内部实现也差不多(数组+ 链表)。
使用场景:系统中对象数据的存储。 - set
介绍:set 类似于 Java 中的 HashSet 。Redis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序。
当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口,这个也是list 所不能提供的。
可以基于 set 轻易实现交集、并集、差集的操作
使用场景: 需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景。 - sorted set
介绍:和 set 相比,sorted set 增加了一个权重参数 score,使得集合中的元素能够按score 进行有序排列,还可以通过 score 的范围来获取元素的列表。有点像是Java中HashMap 和 TreeSet 的结合体。
使用场景:需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。 - bitmap
介绍:bitmap 存储的是连续的二进制数字(0 和 1),通过bitmap, 只需要一个bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道8 个bit 可以组成一个byte,所以 bitmap 本身会极大的节省储存空间。。
使用场景:适合需要保存状态信息(比如是否签到、是否登录…)并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
17、Redis 常见性能问题和解决方案:
- Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务
- 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次
- 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网
- 尽量避免在压力很大的主库上增加从库
- 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1<-Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现Slave 对Master 的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其 他不变。
18、为什么 Redis 需要把所有数据放到内存中?
答:Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。
所以 redis 具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响 redis 的性能。在内存越来越便宜的今 天,redis 将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录 数达到内存限值后不能继续插入新值。
19、Redis 的同步机制了解么?
答:Redis 可以使用主从同步,从从同步。
第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全 量同步到复制节点,复制节点接受完成后将 rdb 镜像加载到内存。
加载完成 后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
20、Pipeline 有什么好处,为什么要用 pipeline?
答:可以将多次 IO 往返的时间缩减为一次,前提是 pipeline 执行的指令之间没有因果相关性。使用 redis-benchmark 进行压测的时候可以发现影响 redis 的QPS 峰值的一个重要因素是pipeline 批次指令的数目。
21、是否使用过 Redis 集群,集群的原理是什么?
- Redis Sentinal 着眼于高可用,在 master 宕机时会自动将slave 提升为master,继续提供服务。
- Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用Cluster 进行分片存储。
22、Redis 支持的 Java 客户端都有哪些?官方推荐用哪个?
答:Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
23、Jedis 与 Redisson 对比有什么优缺点?
答:Jedis 是 Redis 的 Java 实现的客户端,其 API 提供了比较全面的 Redis 命令的支持;
Redisson 实现了分布式和可扩展的 Java 数据结构,和 Jedis 相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、 分区等 Redis 特性。
Redisson 的宗旨是促进使用者对 Redis 的关注分离,从而让使用者能够将精 力更集中地放在处理业务逻辑上。
24、Redis 如何设置密码及验证密码?
设置密码:config set requirepass 123456
授权密码:auth 123456
25、说说 Redis 哈希槽的概念?
答:Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群 有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置 哪个槽,集群的每个节点负责一部分 hash 槽。
26、Redis 集群的主从复制模型是怎样的?
答:为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用, 所以集群使用了主从复制模型,每个节点都会有 N-1 个复制品。
27、Redis 集群会有写操作丢失吗?为什么?
答:Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件 下可能会丢失写操作。
28、Redis 集群之间是如何复制的?
答:异步复制
29、Redis 集群最大节点个数是多少?
答:16384 个。
30、Redis 集群如何选择数据库?
答:Redis 集群目前无法做数据库选择,默认在 0 数据库。
31、Redis 事务相关的命令有哪几个?
答:MULTI、EXEC、DISCARD、WATCH
32、Redis key 的过期时间和永久有效分别怎么设置?
答:EXPIRE 和 PERSIST 命令。
33、使用过 Redis 分布式锁么,它是什么回事
答:先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。当 setnx 之后执行expire之前进程意外 crash 或者要重启维护了,使用 set 指令有非常复杂的参数,可以同时把 setnx 和 expire 合成一条指令来用的!
34、Redis 最适合的场景?
-
会话缓存(Session Cache)
最常用的一种使用 Redis 的情景是会话缓存(session cache)。
用Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分 人都会不高兴的,现在,他们还会这样吗? 幸运的是,随着 Redis 这些年的 改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的 商业平台 Magento 也提供 Redis 的插件。 -
全页缓存(FPC)
除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。再次以 Magento 为 例,Magento 提供一个插件来使用Redis 作为全页缓存后端。 此外,对 WordPress 的用户来说,Pantheon 有一个非常好的插件 wp-redis,这个插件 能帮助你以最快速度加载你曾浏览过的页面。 -
队列
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis 能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作, 就类似于本地程序语言(如Python)对 list 的 push/pop 操作。 如果你快 速的在 Google 中搜索“Redis queues”,你马上就能找到大量的开源项目, 这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需 求。例如,Celery 有一个后台就是使用 Redis 作为broker,你可以从这里去查看。 -
排行榜/计数器
Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠 前的10 个用户–我们称之为“user_scores”,我们只需要像下面一样执行即 可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户 及用户的分数,你需要这样执行:ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一个很好的例子,用Ruby实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到。 -
发布/订阅
最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis 的发布/订阅功能来建立聊天系统!