金三银四面试季,为了做好面试路上的好帮手,对于对Redis没有把握的同学,这里有40道Redis问题面试常见问题,让你面试不慌张,争取Offer拿到手软!1、什么是Redis?Redis完全开源免费,遵守BSD协议,是一个高性能的key-value数据库。Redis与其他键值缓存产品相比,具有以下三个特点:Redis支持数据持久化,可以将内存中的数据保存到磁盘,重启时可以再次加载使用。Redis不仅支持简单的key-value类型数据,还提供list、set、zset、hash等数据结构的存储。Redis支持数据备份,即主从模式的数据备份。Redis的优点:高性能:Redis的读取速度可达110,000次/s,写入速度为81,000次/s。丰富的数据类型:Redis在二进制情况下支持Strings、Lists、Hashes、Sets和OrderedSets数据类型。原子性:Redis的所有操作都是原子性的,也就是说要么执行成功,要么失败则根本不执行。单个操作是原子的。多操作也支持事务,即原子性,由MULTI和EXEC指令包裹。丰富的特性:Redis还支持发布/订阅、通知、key过期等特性。Redis与其他键值存储有何不同?Redis拥有更复杂的数据结构,并提供对它们的原子操作,这是一条不同于其他数据库的进化路径。Redis的数据类型是基于基本数据结构的,对程序员是透明的,不需要额外的抽象。Redis运行在内存中但可以持久化到磁盘,所以在高速读写不同的数据集时需要权衡内存,因为数据量不能大于硬件内存。内存数据库的另一个优势是,与在磁盘上同样复杂的数据结构相比,在内存中操作非常简单,因此Redis可以做很多内部复杂度很高的事情。此外,它们在磁盘格式方面是紧凑的并且是追加生成的,因为它们不需要随机访问。2、Redis的数据类型是什么?Redis支持五种数据类型:string(字符串)、hash(散列)、list(列表)、set(集合)和zsetsortedset(有序集合)。String和hash在我们实际项目中比较常用。如果你是Redis的高级用户,还需要添加以下数据结构HyperLogLog、Geo、Pub/Sub。如果你说你玩过RedisModule,比如BloomFilter、RedisSearch、Redis-ML,面试官的眼睛就会开始放光。3、使用Redis有什么好处?速度快,因为数据存在于内存中,类似于HashMap,HashMap的优点是查找和运算的时间复杂度为O1)支持丰富的数据类型,支持string、list、set、zset、hash等支持事务,并且操作是原子性的,所谓原子性就是所有的数据变化要么执行要么根本不执行丰富的特性,可以用于缓存,消息,key设置过期时间,之后会自动删除到期4.Redis与Memcached相比有什么优势?Memcached的所有值都是简单的字符串。Redis作为其替代者,支持更丰富的数据类型。Redis比Memcached快得多。Redis可以持久化它的数据。5、Memcache和Redis有什么区别?存储方式Memecache将所有数据存储在内存中,断电后挂掉,数据不能超过内存大小。Redis的一部分存储在硬盘上,保证了数据的持久化。数据支持类型Memcache支持相对简单的数据类型。Redis具有复杂的数据类型。使用不同的底层模型,与客户端通信的底层实现方式和应用协议也不同。Redis直接自己搭建了VM机制,因为一般系统调用系统函数的话,会浪费一定的时间去移动和请求。6、Redis是单进程单线程的吗?Redis是单进程和单线程的。Redis使用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。7、串型智能存储器的最大容量是多少?512M。8、Redis的持久化机制是什么?各自的优缺点?Redis提供了两种持久化机制RDB和AOF机制:RDB(RedisDataBase)持久化模式:是指以数据集快照的形式记录Redis数据库所有键值对的半持久化模式,并将数据写入在某个时间点输入一个临时文件。持久化结束后,用这个临时文件替换上次持久化的文件,实现数据恢复。优点:只有一个文件dump.rdb,方便持久化。容灾性好,一个文件可以保存到安全盘。为了性能最大化,fork子进程完成写操作,让主进程继续处理命令,这样IO就最大化了。使用单独的子进程进行持久化,主进程不会进行任何IO操作,保证了Redis的高性能。相对于大数据集,启动比AOF效率更高。缺点:数据安全性低。RDB每隔一定时间持久化一次。如果Redis在持久化之间发生故障,就会发生数据丢失。因此,这种方式更适用于对数据要求不严格时的AOF(Append-onlyfile)持久化方式:表示将所有命令行记录完全持久化存储为Redis命令请求协议的格式,保存为aof文件。优点:数据安全,aof持久化可以配置appendfsync属性,一直存在,每条命令操作都会在aof文件中记录一次。通过append方式写入文件,即使中途宕机,也可以使用redis-check-aof工具解决数据一致性问题。AOF机制的rewrite模式。在AOF文件改写前(文件过大时会合并重写命令),可以删除部分命令(如处理不当的flushall)。缺点:AOF文件比RDB文件大,恢复速度慢。当数据集很大时,效率不如RDB启动。9、Redis常见性能问题及解决方案Master最好不要写内存快照。如果Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作。当快照比较大时,对性能影响很大,会间歇性的暂停服务。如果数据比较重要,一个Slave开启AOF备份数据,策略设置为每秒同步一个。为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内。尽量避免在高压下向主库添加从库。不要使用图结构进行主从复制。使用单向链表结构更稳定,即:Master<-Slave1<-Slave2<-Slave3...这种结构方便解决单点故障问题,实现Slave对Master的替换.如果Master挂掉了,可以马上让Slave1成为Master,其他不变。10.Redis过期键删除策略?定时删除:创建定时timer,同时设置key的过期时间。让计时器在密钥的过期时间到来时立即删除密钥。懒删除:不管key是否过期,但是每次从key空间中获取一个key,检查获取的key是否过期,如果过期则删除该key;如果未过期,则返回密钥。定期删除:程序每隔一段时间检查一次数据库,并删除其中过期的键。要删除多少过期密钥,要检查多少数据库,取决于算法。11.Redis回收策略(淘汰策略)?volatile-lru:从设置了过期时间的数据集(server.db[i].expires)中选择最近最少使用的数据进行淘汰volatile-ttl:从设置了过期时间的数据集(server.db[i]].过期)。expires)选取即将过期的数据并剔除volatile-random:从数据集(server.selecttheleastrecentlyuseddatafrom.dict)中选取数据并剔除allkeys-random:从数据集中随机选取数据(server.selecttheleastrecentlyuseddatafrom.dict).db[i].dict)Eliminateno-enviction(expel):禁止驱逐数据注意这里的6个机制,volatile和allkeys指定是从设置了过期时间的数据集中还是从所有数据集中剔除数据。下面的lru、ttl、random是三种不同的淘汰策略,再加上一个永不回收的no-enviction策略。使用策略规则:如果数据呈现幂律分布,即有的数据访问频率高,有的数据访问频率低,则使用allkeys-lru如果数据呈现均等分布,即所有数据访问频率相同,则使用allkeys-random12。为什么Redis需要把所有的数据都放在内存中?Redis为了达到最快的读写速度,将数据读入内存和将数据写入磁盘是异步的。所以Redis具有速度快,数据持久化的特点。如果数据不保存在内存中,磁盘I/O速度会严重影响Redis的性能。在内存越来越便宜的今天,Redis会越来越流行。如果设置了最大内存使用量,现有数据记录数达到内存限制后无法插入新值。13、你了解Redis的同步机制吗?Redis可以使用主从同步和从从同步。第一次同步时,master节点会进行一次bgsave,同时将后续的修改操作记录到内存缓冲区中。完成后将rdb文件完全同步到复制节点,复制节点接收到rdb镜像后加载到内存中。加载完成后,通知主节点将修改后的操作记录同步到复制节点进行重放,完成同步过程。14、Pipeline有什么好处,为什么要用Pipeline?如果Pipeline执行的指令之间没有因果关系,则可以将多次IO往返的时间减少到一次。在使用redis-benchmark进行压测时,可以发现影响RedisQPS峰值的一个重要因素是Pipeline批处理指令数。15.你用过Redis集群吗?集群的原理是什么?RedisSentinal专注于高可用性。当Master宕机时,会自动将slave提升为master,继续提供服务。RedisCluster注重扩展性,当单个Redis内存不足时使用Cluster进行分片存储。16、Redis集群方案在什么情况下会导致整个集群不可用?在一个有A、B、C三个节点的集群中,如果没有复制模型,如果B节点出现故障,整个集群会因为缺少5501-11000范围内的槽而不可用。17.Redis支持的Java客户端有哪些?官方推荐哪一款?Redisson、Jedis、lettuce等官方推荐使用Redisson。18、Jedis和Redisson的优缺点是什么?Jedis是用Java实现的Redis客户端,其API提供了对Redis命令的全面支持;Redisson实现了分布式和可扩展的Java数据结构。与Jedis相比,功能更简单,不支持字符串操作。不支持排序、事务、管道和分区等Redis功能。Redisson的目的是促进用户与Redis的关注点分离,让用户可以更专注于处理业务逻辑。19、如何在Redis中设置密码和验证密码?设置密码:configsetrequirepass123456授权密码:auth12345620说说Redishashslot的概念?Redis集群没有使用一致性哈希,而是引入了哈希槽的概念。Redis集群有16384个哈希槽。每个key通过CRC16校验后,取16384取模,决定放置哪个slot。集群的每个节点负责一些哈希槽。21、Redis集群的主从复制模型是什么?为了在部分节点失效或大部分节点无法通信时使集群可用,集群采用主从复制模型,每个节点都会有N-1个副本。22、写操作在Redis集群中会不会丢失?为什么?Redis不保证数据的强一致性,这意味着在实践中,集群在某些情况下可能会丢失写操作。23.Redis集群是如何复制的?异步复制。24.Redis集群的最大节点数是多少?16384.25.Redis集群如何选择数据库?Redis集群目前无法选择数据库,默认为0个数据库。26.如何测试Redis的连通性?使用ping命令。27.如何理解Redis事务?事务是一个独立的操作:事务中的所有命令都被序列化并按顺序执行。交易执行过程中,不会被其他客户端发送的命令请求打断。一个事务是一个原子操作:要么执行事务中的所有命令,要么不执行任何命令。28、Redis事务相关的命令有哪些?MULTI、EXEC、DISCARD、WATCH。29、如何设置Rediskey的过期时间和永久有效?EXPIRE和PERSIST命令。30、Redis是如何优化内存的?尽可能使用哈希表(hashes)。哈希表(意思是存储在哈希表中的数字很小)占用的内存非常少,所以你应该尽可能地将你的数据模型抽象成一个哈希表。例如,如果你的web系统中有一个用户对象,不要为用户的名字、姓氏、电子邮件和密码设置单独的键,而是将用户的所有信息存储在一个哈希表中。31.Redis回收过程是如何进行的?客户端运行新命令并添加新数据。Redis检查内存使用情况,如果大于maxmemory的限制,就会按照设定的策略进行回收。执行新命令等。所以我们不断地越过内存限制的边界,不断地到达边界,然后不断地回收到边界以下。如果一个命令的结果导致大量内存被使用(比如将非常大的集合的交集保存到一个新的键),用不了多久就会被这个内存使用量超过内存限制。32.减少Redis内存占用的方法有哪些?如果你使用的是32位的Redis实例,可以利用好Hash、list、sortedset、set等集合类型的数据,因为通常很多小的Key-Values可以存储在一个更紧凑的方式。33.当Redis内存不足时会发生什么?如果达到设置的上限,Redis写命令会返回错误信息(但是读命令仍然可以正常返回。)或者你可以将Redis作为缓存使用配置淘汰机制,当Redis到达内存上限时限制,它将清除旧内容。34.一个Redis实例最多可以存储多少个key?List、Set、SortedSet,最多能存储多少个元素?理论上,Redis最多可以处理232个key,经过实践检验,每个实例至少存储2.5亿个key。我们正在测试一些更大的值。任何列表、集合和有序集合都可以容纳232个元素。换句话说,Redis的存储限制是系统中可用的内存量。35、MySQL中有2000万条数据,而Redis中只有2000万条数据。如何保证Redis中的数据都是热数据?当Redis内存数据集的大小上升到一定大小时,就会执行数据淘汰策略。相关知识:Redis提供了6种数据淘汰策略:volatile-lru:从数据集(server.selectthewillexpiredata)中选择最近最少使用的数据,从数据集(server.db[i].expires)中选择将过期的数据,淘汰volatile-random:从数据集(server.db[i].expires)中选择已设置过期时间的数据,剔除allkeys-lru:从数据集(server.db[i].dict)中选择最近最少使用的数据andeliminationallkeys-random:从数据集(server.db[i].dict)中随机选取数据,消除no-enviction(expulsion):禁止驱逐数据36.Redis最适合的场景是什么?Sessioncache(SessionCache),使用Redis最常用的场景就是会话缓存(sessioncache)。使用Redis来缓存session相对于其他存储(比如Memcached)的优势在于Redis提供了持久化。当维护一个不严格的缓存时一致,大多数人会不高兴,如果所有用户的购物车信息丢失。现在,他们会吗?幸运的是,随着Redis多年来的改进,很容易找到有关如何正确使用Redis进行会话缓存的文档。甚至著名的商业平台Magento也为Redis提供了一个插件。FullPageCache(FPC),除了基本的sessiontoken,Redis还提供了一个非常简单的FPC平台。回到一致性问题,即使Redis实例重启,用户也不会因为磁盘持久化而看到页面加载速度下降。这是一个很大的改进,类似于PHP的本地FPC。再次以Magento为例,Magento提供了一个插件来使用Redis作为全页缓存后端。另外,对于WordPress用户,Pantheon有一个非常不错的插件wp-redis,可以帮助你以最快的速度加载你访问过的页面。Queue,Reids在内存存储引擎领域的优势之一就是提供list和set操作,这使得Redis可以作为一个很好的消息队列平台。Redis作为队列的操作类似于本地编程语言(如Python)对列表的push/pop操作。如果您在Google上快速搜索“Redis队列”,您会立即找到大量开源项目,这些项目旨在使用Redis创建非常好的后端工具来满足各种队列需求。例如,Celery有一个使用Redis作为代理的后端,你可以在这里查看。排行榜/计数器,Redis在内存中递增或递减数字方面做得很好。Sets和SortedSets也让我们进行这些操作变得非常简单,而Redis正好提供了这两种数据结构。所以,我们要从排序的集合中得到前10名的用户——我们称之为“user_scores”,我们只需要执行如下:当然,这假设你是根据你的用户的分数进行升序排序。如果你想返回用户和用户的分数,你需要这样执行:ZRANGEuser_scores010WITHSCORESAgoraGames是一个很好的例子,用Ruby实现,它的排行榜使用Redis存储数据,你可以在这里找到它看。发布/订阅,最后(但并非最不重要)是Redis的发布/订阅功能。发布/订阅确实有很多用例。我见过人们在社交网络连接中使用它,作为基于发布/订阅的脚本的触发器,甚至使用Redis的发布/订阅功能来构建聊天系统!37、假设Redis中有1亿个key,其中10w个key以某个固定且已知的前缀开头,如何全部找到?使用keys命令扫描出指定模式的按键列表。对方接着问:如果这个Redis是为在线业务提供服务,使用keys命令会有什么问题?这时候你就不得不回答Redis的一个关键特性:Redis是单线程的。keys指令会导致线程阻塞一段时间,在线服务会暂停,直到该指令执行完毕才能恢复服务。这时候就可以使用scan命令了。scan命令可以无阻塞地提取指定模式的key列表,但是会有一定的重复概率。在客户端做一次去重就够了,但是整体花费的时间会比直接使用keys命令的长度要长。38、如果有大量key需要同时设置过期,需要注意什么?如果大量key的过期时间设置的过于密集,Redis在过期时可能会出现短暂的卡顿。一般需要在时间上加上一个随机值,使过期时间更加分散。39.你用过Redis作为异步队列吗?你是怎么用的?答:一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,需要sleep一会再试。如果对方问你能不能用sleep?list还有一个指令叫做blpop,在没有消息的时候会阻塞,直到有消息到达。如果对方问是否可以一次生产多次消费?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。如果对方问pub/sub有什么缺点?当消费者下线时,生产的消息会丢失,必须使用RabbitMQ等专业的消息队列。如果对方问Redis是如何实现延迟队列的?我猜你现在真的很想把面试官打死。如果你手里拿着棒球棒,你怎么会问这么详细的问题。但是你很克制,然后淡定的回复:使用sortedset,以时间戳为score,以消息内容为key调用zadd生产消息,consumer使用zrangebyscore命令获取N之前轮询的数据秒处理。至此,面试官已经偷偷给你竖起了大拇指。可他不知道的是,此刻你竖起中指,在椅子后面。40、你用过Redis分布式锁吗?它是关于什么的?先用setnx去竞争锁,然后用expire给锁加一个过期时间,防止锁忘记释放。这时候对方会告诉你,你的回答很好,然后问如果在setnx执行后,expire执行前,进程意外崩溃或者需要重启维护怎么办?这时候,你要给出惊人的反馈:哦,是的,这个锁永远不会被释放。然后你需要挠头,假装想一会,好像接下来的结果是你自己主动的,然后回答:我记得set命令的参数很复杂,这个应该可以设置setnx和expire同时合成一个命令使用!
