java-redis⾯试题
⼀、Redis基础概述
1、什么是Redis,有哪些优缺点?
Redis 是⼀个使⽤ C 语⾔编写的,开源的⾼性能⾮关系型(NoSQL)的键值对数据库。
Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值⽀持五种数据类型:字符串、列表、集合、散列表、有序集合。
Redis 的数据是存在内存中的,所以读写速度⾮常快,因此 redis 被⼴泛应⽤于缓存⽅向,每秒可以处理超过 10万次读写操作
Redis ⽀持事务、持久化、LUA脚本、LRU驱动事件、多种集⽅案。
整体的回答流程就是概念+基本数据类型+特点+可以做什么
(1)优点
读写速度快、⽀持持久化、数据结构丰富、⽀持主从复制。
(2)缺点
受物理内存的限制、不具备⾃动容错和恢复功能、较难⽀持在线扩容
2、Redis为什么这么快
(1)完全基于内存,绝⼤部分请求是纯粹的内存操作,⾮常快速。
(2)数据结构简单,操作也简单,Redis 中的数据结构是专门进⾏设计的;
(3)采⽤单线程,避免了不必要的上下⽂切换和竞争条件,也不存在多进程或者多线程导致的切换⽽消耗 CPU,不⽤去考虑各种锁的问题
(4)使⽤多路 I/O 复⽤模型,⾮阻塞 IO;
(5)使⽤底层模型不同,它们之间底层实现⽅式以及与客户端之间通信的应⽤协议不⼀样,Redis 直接⾃⼰构建了 VM 机制,因为⼀般的系统调⽤系统函数的话,会浪费⼀定的时间去移动和请求;
3、为什么要⽤ Redis ⽽不⽤ map/guava 做缓存?
缓存分为本地缓存和分布式缓存。以 Java 为例,使⽤⾃带的 map 或者 guava 实现的是本地缓存,最
主要的特点是轻量以及快速,⽣命周期随着 jvm 的销毁⽽结束,并且在多实例的情况下,每个实例都需要各⾃保存⼀份缓存,缓存不具有⼀致性。
使⽤ redis 或 memcached 之类的称为分布式缓存,在多实例的情况下,各实例共⽤⼀份缓存数据,缓存具有⼀致性。
redis支持的五种数据类型
4、Redis与Memcached的区别
区别很多,有⼀张表,我觉得记不住,⼤概下⾯三种就可以:
(1) memcached所有的值均是简单的字符串,redis作为其替代者,⽀持更为丰富的数据类型
(2) redis的速度⽐memcached快很多
(3) redis可以持久化其数据
5、Redis常见性能问题和解决⽅案?
(1)Master最好不要做任何持久化⼯作,包括内存快照和AOF⽇志⽂件,特别是不要启⽤内存快照做持久化。
(2)如果数据⽐较关键,某个Slave开启AOF备份数据,策略为每秒同步⼀次。
(3)为了主从复制的速度和连接的稳定性,Slave和Master最好在同⼀个局域⽹内。
(4)尽量避免在压⼒较⼤的主库上增加从库
(5)Master调⽤BGREWRITEAOF重写AOF⽂件,AOF在重写的时候会占⼤量的CPU和内存资源,导致服务load过⾼,出现短暂服务暂停现象。
(6)为了Master的稳定性,主从复制不要⽤图状结构,⽤单向链表结构更稳定,即主从关系为:Master<–Slave1<–Slave2<–Slave3…,这样的结构也⽅便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以⽴马启⽤Slave1做Master,其他不变。
⼆、数据类型
1、Redis有哪些数据类型,都在哪些场景中使⽤过?
Redis主要有5种数据类型,包括String,List,Set,Zset,Hash,满⾜⼤部分的使⽤要求。
(1)string:适合最简单的k-v存储,类似于memcached的存储结构,短信验证码,配置信息等,就⽤这种类型来存储。
(2)hash:⼀般key为ID或者唯⼀标⽰,value对应的就是详情了。如商品详情,个⼈信息详情,新闻详情等。
(3)list:因为list是有序的,⽐较适合存储⼀些有序且数据相对固定的数据。如省市区表、字典表等。因为list是有序的,适合根据写⼊的时间来排序,如:最新的排名。
(4)set:可以简单的理解为ID-List的模式,如微博中⼀个⼈有哪些好友,set最⽜的地⽅在于,可以对两个set提供交集、并集、差集操作。例如:查两个⼈共同的好友等。
(5)Sorted Set:是set的增强版本,增加了⼀个score参数,⾃动会根据score的值进⾏排序。⽐较适合类似于top 10等不根据插⼊的时间来排序的数据。
三、持久化技术(重点)
1、Redis 的持久化机制是什么?各⾃的优缺点?
Redis 提供两种持久化机制 RDB(默认)和 AOF 机制:
(1)RDB是Redis默认的持久化⽅式。按照⼀定的时间将内存的数据以快照的形式保存到硬盘中,对应产⽣的数据⽂件为dump.rdb。通过配置⽂件中的save参数来定义快照的周期。
优点:
1、只有⼀个⽂件 dump.rdb,⽅便持久化。
2、容灾性好,⼀个⽂件可以保存到安全的磁盘。
3、性能最⼤化,fork ⼦进程来完成写操作,让主进程继续处理命令,所以是 IO 最⼤化。使⽤单独⼦进程来进⾏持久化,主进程不会进⾏任何 IO 操作,保证了 redis 的⾼性能
4.相对于数据集⼤时,⽐ AOF 的启动效率更⾼。
缺点:数据安全性低。RDB 是间隔⼀段时间进⾏持久化,如果持久化之间 redis 发⽣故障,会发⽣数据丢失。所以这种⽅式更适合数据要求不严谨的时候)
(2)AOF持久化(即Append Only File持久化),则是将Redis执⾏的每次写命令记录到单独的⽇志⽂件中,当重启Redis会重新将持久化的⽇志中⽂件恢复数据。
优点:数据安全、可以解决数据⼀致性问题。
缺点:AOF ⽂件⽐ RDB ⽂件⼤,且恢复速度慢、⽐ rdb 启动效率低。
2、如何选择合适的持久化⽅式
(1)应该同时使⽤两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载⼊AOF⽂件来恢复原始的数据,因为在通常情况下AOF ⽂件保存的数据集要⽐RDB⽂件保存的数据集要完整。
(2)如果允许部分数据丢失,可以使⽤RDB⽅式,并且 RDB 恢复数据集的速度也要⽐AOF恢复的速度要快,除此之外,使⽤RDB还可以避免AOF程序的bug。
(3)如果你只希望你的数据在服务器运⾏的时候存在,你也可以不使⽤任何持久化⽅式。
3、Redis怎么扩容?
(1)如果Redis被当做缓存使⽤时,使⽤⼀致性哈希实现动态扩容缩容。
(2)如果Redis被当做⼀个持久化存储使⽤,使⽤Redis集进⾏扩容。
4、Redis如何做⼤量数据插⼊?
Redis2.6开始redis-cli⽀持⼀种新的被称之为pipe mode的新模式⽤于执⾏⼤量数据插⼊⼯作。
5、假如Redis⾥⾯有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部
出来?
使⽤keys指令可以扫出指定模式的key列表。
对⽅接着追问:如果这个redis正在给线上的业务提供服务,那使⽤keys指令会有什么问题?
这个时候你要回答redis关键的⼀个特性:redis的单线程的。keys指令会导致线程阻塞⼀段时间,线上服务会停顿,直到指令执⾏完毕,服务才能恢复。这个时候可以使⽤scan指令,scan指令可以⽆阻塞的提取出指定模式的key列表,但是会有⼀定的重复概率,在客户端做⼀次去重就可以了,但是整体所花费的时间会⽐直接⽤keys指令长。
6、使⽤Redis做过异步队列吗,是如何实现的
使⽤list类型保存数据信息,rpush⽣产消息,lpop消费消息,当lpop没有消息时,可以sleep⼀段时间,然后再检查有没有信息,如果不想sleep的话,可以使⽤blpop, 在没有信息的时候,会⼀直阻塞,直到信息的到来。redis可以通过pub/sub主题订阅模式实现⼀个⽣产者,多个消费者,当然也存在⼀定的缺点,当消费者下线时,⽣产的消息会丢失。
7、Redis如何实现延时队列
使⽤sortedset,使⽤时间戳做score, 消息内容作为key,调⽤zadd来⽣产消息,消费者使⽤zrangbyscore获取n秒之前的数据做轮询处理。
四、过期删除策略(重点)
1、Redis的过期键的删除策略
过期策略通常有以下三种:
(1)定时过期:每个设置过期时间的key都需要创建⼀个定时器,到过期时间就会⽴即清除。该策略可以⽴即清除过期的数据,对内存很友好;但是会占⽤⼤量的CPU资源去处理过期的数据,从⽽影响缓存的响应时间和吞吐量。
(2)惰性过期:只有当访问⼀个key时,才会判断该key是否已过期,过期则清除。该策略可以最⼤化地节省CPU资源,却对内存⾮常不友好。极端情况可能出现⼤量的过期key没有再次被访问,从⽽不会被清除,占⽤⼤量内存。
(3)定期过期:每隔⼀定的时间,会扫描⼀定数量的数据库的expires字典中⼀定数量的key,并清除其中已过期的key。该策略是前两者的⼀个折中⽅案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
Redis中同时使⽤了惰性过期和定期过期两种过期策略。
2、设置过期时间和永久有效的命令是什么?
EXPIRE和PERSIST命令
3、Redis的内存淘汰策略有哪些?
全局的键空间选择性移除
(1)noeviction:当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错。
(2)allkeys-lru:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最近最少使⽤的key。(这个是最常⽤的)
(3)allkeys-random:当内存不⾜以容纳新写⼊数据时,在键空间中,随机移除某个key。
设置过期时间的键空间选择性移除
(1)volatile-lru:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,移除最近最少使⽤的key。
(2)volatile-random:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,随机移除某个key。
(3)volatile-ttl:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
在2.8.13的版本⾥,默认是noeviction,在3.2.3版本⾥默认是volatile-lru。
4、Redis如何做内存优化?
尽可能使⽤散列表(hashes),散列表(是说散列表⾥⾯存储的数少)使⽤的内存⾮常⼩,所以你应该尽可能的将你的数据模型抽象到⼀个散列表⾥⾯。⽐如你的web系统中有⼀个⽤户对象,不要为这个⽤户的名称,姓⽒,邮箱,密码设置单独的key,⽽是应该把这个⽤户的所有信息存储到⼀张散列表⾥⾯。
五、Redis事务
1、Redis事务的概念?
Redis 事务的本质是通过MULTI、EXEC、WATCH等⼀组命令的集合。事务⽀持⼀次执⾏多个命令,
⼀个事务中所有命令都会被序列化。在事务执⾏过程,会按照顺序串⾏化执⾏队列中的命令,其他客户端提交的命令请求不会插⼊到事务执⾏命令序列中。
总结说:redis事务就是⼀次性、顺序性、排他性的执⾏⼀个队列中的⼀系列命令。
2、Redis事务的三个阶段
事务开始 MULTI、命令⼊队、事务执⾏ EXEC
3、Redis事务⽀持隔离性吗?
Redis 是单进程程序,并且它保证在执⾏事务时,不会对事务进⾏中断,事务可以运⾏直到执⾏完所有事务队列中的命令为⽌。因
此,Redis 的事务是总是带有隔离性的。
4、Redis事务保证原⼦性吗,⽀持回滚吗?
Redis中,单条命令是原⼦性执⾏的,但事务不保证原⼦性,且没有回滚。事务中任意命令执⾏失败,其余的命令仍会被执⾏。
1. 如果在⼀个事务中的命令出现错误,那么所有的命令都不会执⾏;
2. 如果在⼀个事务中出现运⾏错误,那么正确的命令会被执⾏。
六、Redis集
1、什么是哨兵
哨兵的介绍
sentinel,中⽂名是哨兵。哨兵是 redis 集机构中⾮常重要的⼀个组件,主要有以下功能:
(1)集监控:负责监控 redis master 和 slave 进程是否正常⼯作。
(2)消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
(3)故障转移:如果 master node 挂掉了,会⾃动转移到 slave node 上。
(4)配置中⼼:如果故障转移发⽣了,通知 client 客户端新的 master 地址。
哨兵⽤于实现 redis 集的⾼可⽤,本⾝也是分布式的,作为⼀个哨兵集去运⾏,互相协同⼯作。
哨兵的核⼼知识
(1)哨兵⾄少需要 3 个实例,来保证⾃⼰的健壮性。
(2)哨兵 + redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集的⾼可⽤性。
(3)对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和⽣产环境,都进⾏充⾜的测试和演练。
2、redis 集模式的⼯作原理能说⼀下么?
Redis Cluster是⼀种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有使⽤⼀致性hash,⽽是采⽤slot(槽)的概念,⼀共分成16384个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执⾏。
3、分布式寻址都有哪些算法?
(1)hash 算法(⼤量缓存重建)
(2)⼀致性 hash 算法(⾃动缓存迁移)+ 虚拟节点(⾃动负载均衡)
(3)redis cluster 的 hash slot 算法
4、节点间如何通信?
集元数据的维护有两种⽅式:集中式、Gossip 协议。redis cluster 节点间采⽤ gossip 协议进⾏通信。
5、Redis Sharding如何实现的?
Redis Sharding是Redis Cluster出来之前,业界普遍使⽤的多Redis实例集⽅法。其主要思想是采⽤哈希算法将Redis数据的key进⾏散列,通过hash函数,特定的key会映射到特定的Redis节点上。Java redis客户端驱动jedis,⽀持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool
6、Redis 主从架构原理
单机的 redis,能够承载的 QPS ⼤概就在上万到⼏万不等。对于缓存来说,⼀般都是⽤来⽀撑读⾼并发的。因此架构做成主从(master-slave)架构,⼀主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部⾛从节点。这样也可以很轻松实现⽔平扩容,⽀撑读⾼并发。
过程原理
(1)当从库和主库建⽴MS关系后,会向主数据库发送SYNC命令
(2)主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程),并将期间接收到的写命令缓存起来
(3)当快照完成后,主Redis会将快照⽂件和所有缓存的写命令发送给从Redis
(4)从Redis接收到后,会载⼊快照⽂件并且执⾏收到的缓存的命令
(5)之后,主Redis每当接收到写命令时就会将命令发送从Redis,从⽽保证数据的⼀致
7、Redis集会有写操作丢失吗?为什么?
Redis并不能保证数据的强⼀致性,这意味这在实际中集在特定的条件下可能会丢失写操作。
8、Redis集之间是如何复制的?(异步复制)
9、Redis集最⼤节点个数是多少?(16384)
10、Redis是单线程的,如何提⾼多核CPU的利⽤率?
可以在同⼀个服务器部署多个Redis的实例,并把他们当作不同的服务器来使⽤,在某些时候,⽆论如何⼀个服务器是不够的,所以,如果你想使⽤多个CPU,你可以考虑⼀下分⽚(shard)。
11、为什么要做Redis分区?
分区可以让Redis管理更⼤的内存,Redis将可以使⽤所有机器的内存。如果没有分区,你最多只能使⽤⼀台机器的内存。分区使Redis的计算能⼒通过简单地增加计算机得到成倍提升,Redis的⽹络带宽也会随着计算机和⽹卡的增加⽽成倍增长。
12、有哪些Redis分区实现⽅案?
(1)客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。⼤多数客户端已经实现了客户端分区。
(2)代理分区意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的⼀种代理实现就是Twemproxy
(3)查询路由(Query routing) 的意思是客户端随机地请求任意⼀个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster 实现了⼀种混合形式的查询路由,但并不是直接将请求从⼀个r
edis节点转发到另⼀个redis节点,⽽是在客户端的帮助下直接redirected到正确的redis节点。
13、Redis分区有什么缺点?
(1)涉及多个key的操作通常不会被⽀持。例如你不能对两个集合求交集,因为他们可能被存储到不同的Redis实例(实际上这种情况也有办法,但是不能直接使⽤交集指令)。
(2)同时操作多个key,则不能使⽤Redis事务.
(3)分区使⽤的粒度是key,不能使⽤⼀个⾮常长的排序key存储⼀个数据集
(4)当使⽤分区的时候,数据处理会⾮常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF⽂件。
(5)分区时动态扩容或缩容可能⾮常复杂。Redis集在运⾏时增加或者删除Redis节点,能做到最⼤程度对⽤户透明地数据再平衡,但其他⼀些客户端分区或者代理分区⽅法则不⽀持这种特性。然⽽,有⼀种预分⽚的技术也可以较好的解决这个问题。
14、Redis如何实现分布式锁?
使⽤SETNX完成同步锁的流程及事项如下:
使⽤SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功
为了防⽌获取锁后程序出现异常,导致其他线程/进程调⽤SETNX命令总是返回0⽽进⼊死锁状态,需要为该key设置⼀个“合理”的过期时间
释放锁,使⽤DEL命令将锁数据删除
15、如何解决 Redis 的并发竞争 Key 问题
所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对⼀个 key 进⾏操作,但是最后执⾏的顺序和我们期望的顺序不同,这样也就导致了结果的不同!
推荐⼀种⽅案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要使⽤分布式锁,这样会影响性能)
zookeeper分布式锁准备在今后的⾯试⽂章中提到。
16、分布式Redis是前期做还是后期规模上来了再做好?为什么?
既然Redis是如此的轻量(单实例只使⽤1M内存),为防⽌以后的扩容,最好的办法就是⼀开始就启
动较多实例。即便你只有⼀台服务器,你也可以⼀开始就让Redis以分布式的⽅式运⾏,使⽤分区,在同⼀台服务器上启动多个实例。
⼀开始就多设置⼏个Redis实例,例如32或者64个实例,对⼤多数⽤户来说这操作起来可能⽐较⿇烦,但是从长久来看做这点牺牲是值得的。
这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从⼀台服务迁移到另外⼀台服务器⽽已(⽽不⽤考虑重新分区的问题)。⼀旦你添加了另⼀台服务器,你需要将你⼀半的Redis实例从第⼀台机器迁移到第⼆台机器。
17、什么是 RedLock
Redis 官⽅站提出了⼀种权威的基于 Redis 实现分布式锁的⽅式名叫 Redlock,此种⽅式⽐原先的单节点的⽅法更安全。它可以保证以下特性:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。