史上最全redis⾯试题及答案吊打⾯试官
1,什么是Redis?
简单来说 redis 就是⼀个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度⾮常快,因此 redis 被⼴泛应⽤于缓存⽅向。另外,redis 也经常⽤来做分布式锁。redis 提供了多种数据类型来⽀持不同的业务场景。除此之外,redis ⽀持事务 、持久化、LUA脚本、LRU驱动事件、多种集⽅案。
2,redis 和 memcached 的区别?
存储⽅式不同:memcache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存⼤⼩;Redis 有部份存在硬盘上,这样能保证数据的持久性。
数据⽀持类型:memcache 对数据类型⽀持相对简单;Redis 有复杂的数据类型。
使⽤底层模型不同:它们之间底层实现⽅式,以及与客户端之间通信的应⽤协议不⼀样,Redis ⾃⼰构建了 vm 机制,因为⼀般的系统调⽤系统函数的话,会浪费⼀定的时间去移动和请求。 value 值⼤⼩不同:Redis 最⼤可以达到 1gb;memcache 只有 1mb。
3,说⼀说 Redis 的数据过期淘汰策略?
Redis 中数据过期策略采⽤定期删除+惰性删除策略。
定期删除、惰性删除策略是什么?
定期删除策略:Redis 启⽤⼀个定时器定时监视所有的 key,判断key是否过期,过期的话就删除。这种策略可以保证过期的 key 最终都会被删除,但是也存在严重的缺点:每次都遍历内存中所有的数据,⾮常消耗 CPU 资源,并且当 key 已过期,但是定时器还处于未唤起状态,这段时间内 key 仍然可以⽤。 惰性删除策略:在获取 key 时,先判断 key 是否过期,如果过期则删除。这种⽅式存在⼀个
缺点:如果这个 key ⼀直未被使⽤,那么它⼀直在内存中,其实它已经过期了,会浪费⼤量的空间。 2、定期删除+惰性删除策略是如何⼯作的?
这两种策略天然的互补,结合起来之后,定时删除策略就发⽣了⼀些改变,不在是每次扫描全部的 key 了,⽽是随机抽取⼀部分 key 进⾏检查,这样就降低了对 CPU 资源的损耗,惰性删除策略互补了为检查到的key,基本上满⾜了所有要求。但是有时候就是那么的巧,既没有被定时器抽取到,⼜没有被使⽤,这些数据⼜如何从内存中消失?没关系,还有内存淘汰机制,当内存不够⽤时,内存淘汰机制就会上场。Redis 内存淘汰机制有以下⼏种策略:
noeviction:当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错。(Redis 默认策略) allkeys-lru:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最近最少使⽤的 Key。(推荐使⽤) allkeys-random:当内存不⾜以容纳新写⼊数据时,在键空间中,随机移除某个Key。 volatile-lru:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,移除最近最少使⽤的 Key。这种情况⼀般是把Redis 既当缓存,⼜做持久化存储的时候才⽤。 volatile-random:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,随机移除某个 Key。 volatile-ttl:当内存不⾜以容纳新写⼊数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。 修改内存淘汰机制只需要在 f 配置⽂件中配置 maxmemory-policy 参数即可。
4,说说 Redis 都有哪些应⽤场景?
缓存:这应该是 Redis 最主要的功能了,也是⼤型⽹站必备机制,合理地使⽤缓存不仅可以加 快数据的访问速度,⽽且能够有效地降低后端数据源的压⼒。
共享Session:对于⼀些依赖 session 功能的服务来说,如果需要从单机变成集的话,可以选择 redis 来统⼀管理 session。
消息队列系统:消息队列系统可以说是⼀个⼤型⽹站的必备基础组件,因为其具有业务 解耦、⾮实时业务削峰等特性。Redis提供了发布订阅功能和阻塞队列的功 能,虽然和专业的消息队列⽐还不够⾜够强⼤,但是对于⼀般的消息队列功 能基本可以满⾜。⽐如在分布式爬⾍系统中,使⽤ redis 来统⼀管理 url队列。
分布式锁:在分布式服务中。可以利⽤Redis的setnx功能来编写分布式的锁,虽然这个可能不是太常⽤。 当然还有诸如排⾏榜、点赞功能都可以使⽤ Redis 来实现,但是 Redis 也不是什么都可以做,⽐如数据量特别⼤时,不适合 Redis,我们知道 Redis 是基于内存的,虽然内存很便宜,但是如果你每天的数据量特别⼤,⽐如⼏亿条的⽤户⾏为⽇志数据,⽤ Redis 来存储的话,成本相当的⾼。
5,为什么要做Redis分区?
分区可以让Redis管理更⼤的内存,Redis将可以使⽤所有机器的内存。如果没有分区,你最多只能使
⽤⼀台机器的内存。分区使Redis的计算能⼒通过简单地增加计算机得到成倍提升,Redis的⽹络带宽也会随着计算机和⽹卡的增加⽽成倍增长。
6,如何解决 Redis 缓存穿透和缓存雪崩问题?
缓存雪崩: 由于缓存层承载着⼤量请求,有效地 保护了存储层,但是如果缓存层由于某些原因不能提供服务,⽐如 Redis 节点挂掉了,热点 key 全部失效了,在这些情况下,所有的请求都会直接请求到数据库,可能会造成数据库宕机的情况。
预防和解决缓存雪崩问题,可以从以下三个⽅⾯进⾏着⼿:
1、使⽤ Redis ⾼可⽤架构:使⽤ Redis 集来保证 Redis 服务不会挂掉
2、缓存时间不⼀致: 给缓存的失效时间,加上⼀个随机值,避免集体失效
3、限流降级策略:有⼀定的备案,⽐如个性推荐服务不可⽤了,换成热点数据推荐服务
缓存穿透: 缓存穿透是指查询⼀个根本不存在的数据,这样的数据肯定不在缓存中,这会导致请求全部落到数据库上,有可能出现数据库宕机的情况。
预防和解决缓存穿透问题,可以考虑以下两种⽅法:
1、缓存空对象: 将空值缓存起来,但是这样就有⼀个问题,⼤量⽆效的空值将占⽤空间,⾮常浪费。
2、布隆过滤器拦截: 将所有可能的查询key 先映射到布隆过滤器中,查询时先判断key是否存在布隆过滤器中,存在才继续向下执⾏,如果不存在,则直接返回。布隆过滤器有⼀定的误判,所以需要你的业务允许⼀定的容错性。
5,Redis 怎么实现分布式锁?
Redis 分布式锁其实就是在系统⾥⾯占⼀个“坑”,其他程序也要占“坑”的时候,占⽤成功了就可以继续执⾏,失败了就只能放弃或稍后重试。 占坑⼀般使⽤ setnx(set if not exists)指令,只允许被⼀个程序占有,使⽤完调⽤ del 释放锁。
6,Redis 如何做内存优化?
尽量使⽤ Redis 的散列表,把相关的信息放到散列表⾥⾯存储,⽽不是把每个字段单独存储,这样可以有效的减少内存使⽤。⽐如将 Web 系统的⽤户对象,应该放到散列表⾥⾯再整体存储到 Redis,⽽不是把⽤户的姓名、年龄、密码、邮箱等字段分别设置 key 进⾏存储。
7,请问Redis的数据类型有哪些,底层怎么实现?
参考回答:
1)字符串:整数值、embstr编码的简单动态字符串、简单动态字符串(SDS)
2)列表:压缩列表、双端链表
3)哈希:压缩列表、字典
4)集合:整数集合、字典
5)有序集合:压缩列表、跳跃表和字典
8,redis消息队列先进先出需要注意什么?
通常使⽤⼀个list来实现队列操作,这样有⼀个⼩限制,所以的任务统⼀都是先进先出,如果想优先处理某个任务就不太好处理了,这就需要让队列有优先级的概念,我们就可以优先处理⾼级别的任务,实现⽅式有以下⼏种⽅式:
1)单⼀列表实现:队列正常的操作是 左进右出(lpush,rpop)为了先处理⾼优先级任务,在遇到⾼级别任务时,可以直接插队,直接放⼊队列头部(rpush),这样,从队列头部(右侧)获取任务时,取到的就是⾼优先级的任务(rpop)
2)使⽤两个队列,⼀个普通队列,⼀个⾼级队列,针对任务的级别放⼊不同的队列,获取任务时也很简单,redis的BRPOP命令可以按顺序从多个队列中取值,BRPOP会按照给出的 key 顺序查看,并在到的第⼀个⾮空 list 的尾部弹出⼀个元素,redis> BRPOP list1 list2 0
list1 做为⾼优先级任务队列 list2 做为普通任务队列
这样就实现了先处理⾼优先级任务,当没有⾼优先级任务时,就去获取普通任务
⽅式1最简单,但实际应⽤⽐较局限,⽅式3可以实现复杂优先级,但实现⽐较复杂,不利于维护
⽅式2是推荐⽤法,实际应⽤最为合适
9,单线程的 Redis 为什么这么快?
Redis 有多快?官⽅给出的答案是读写速度 10万/秒,如果说这是在单线程情况下跑出来的成绩,你会不会惊讶?为什么单线程的 Redis 速度这么快?原因有以下⼏点:
纯内存操作:Redis 是完全基于内存的,所以读写效率⾮常的⾼,当然 Redis 存在持久化操作,在持久化操作是都是 fork ⼦进程和利⽤Linux 系统的页缓存技术来完成,并不会影响 Redis 的性能。 单线程操作:单线程并不是坏事,单线程可以避免了频繁的上下⽂切换,频繁的上下⽂切换也会影响性能
的。 合理⾼效的数据结构 采⽤了⾮阻塞 I/O 多路复⽤机制:多路I/O复⽤模型是利⽤ select、poll、epoll 可以同时监察多个流的 I/O 事件的能⼒,在空闲的时候,会把当前线程阻塞掉,当有⼀个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询⼀遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了⼤量的⽆⽤操作。
10,为什么Redis需要把所有数据放到内存中?
Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的⽅式将数据写⼊磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。
11,怎么理解Redis事务?
事务是⼀个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执⾏。事务在执⾏的过程中,不会被其他客户端发送来的命令请求所打断。事务是⼀个原⼦操作:事务中的命令要么全部被执⾏,要么全部都不执⾏。
12,如何保证缓存与数据库双写时的数据⼀致性?
你只要⽤缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就⼀定会有数据⼀致性的
问题,那么你如何解决⼀致性问题?
⼀般来说,就是如果你的系统不是严格要求缓存+数据库必须⼀致性的话,缓存可以稍微的跟数据库偶尔有不⼀致的情况,最好不要做这个⽅案,读请求和写请求串⾏化,串到⼀个内存队列⾥去,这样就可以保证⼀定不会出现不⼀致的情况
串⾏化之后,就会导致系统的吞吐量会⼤幅度的降低,⽤⽐正常情况下多⼏倍的机器去⽀撑线上的⼀个请求。
13,Redis 持久化有⼏种⽅式?
Redis 的持久化有两种⽅式,或者说有两种策略:
RDB(Redis Database):指定的时间间隔能对你的数据进⾏快照存储。redis支持的五种数据类型
AOF(Append Only File):每⼀个收到的写命令都通过write函数追加到⽂件中。
14,Redis 常见的性能问题有哪些?该如何解决?
主服务器写内存快照,会阻塞主线程的⼯作,当快照⽐较⼤时对性能影响是⾮常⼤的,会间断性暂停
服务,所以主服务器最好不要写内存快照。 Redis 主从复制的性能问题,为了主从复制的速度和连接的稳定性,主从库最好在同⼀个局域⽹内。
15,为什么Redis的操作是原⼦性的,怎么保证原⼦性的?
对于Redis⽽⾔,命令的原⼦性指的是:⼀个操作的不可以再分,操作要么执⾏,要么不执⾏。
Redis的操作之所以是原⼦性的,是因为Redis是单线程的。
Redis本⾝提供的所有API都是原⼦操作,Redis中的事务其实是要保证批量操作的原⼦性。
多个命令在并发中也是原⼦性的吗?
不⼀定, 将get和set改成单命令操作,incr 。使⽤Redis的事务,或者使⽤Redis+Lua==的⽅式实现.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论