Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库通通加载在内存当中进行操做,按期经过异步操做把数据库数据flush到硬盘上进行保存。Redis最大的魅力是支持保存多种数据结构面试
1.为何redis须要把全部数据放到内存中?redis
Redis为了达到最快的读写速度将数据都读到内存中,并经过异步的方式将数据写入磁盘。因此redis具备快速和数据持久化的特征。若是设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。数据库
2. 使用Redis有哪些好处?缓存
速度快、支持多种类型、支持事务、支持设置过时时间;安全
3.redis相比memcached有哪些优点?数据结构
redis能够存储多种类型,而memcached只能存字符串;并发
redis的速度要比memcached快不少;dom
redis支持持久化存储;异步
4. Memcache与Redis的区别都有哪些?分布式
1)、存储方式
Memecache把数据所有存在内存之中,断电后会挂掉,数据不能超过内存大小。
Redis有部份存在硬盘上,这样能保证数据的持久性。
2)、数据支持类型
Memcache对数据类型支持相对简单。
Redis有复杂的数据类型。
3)、使用底层模型不一样
它们之间底层实现方式 以及与客户端之间通讯的应用协议不同。
Redis直接本身构建了VM 机制 ,由于通常的系统调用系统函数的话,会浪费必定的时间去移动和请求。
4)、value大小
redis最大能够达到1GB,而memcache只有1MB
5. redis常见性能问题和解决方案:
Master最好不要作任何持久化工做,如RDB内存快照和AOF日志文件
若是数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
为了主从复制的速度和链接的稳定性,Master和Slave最好在同一个局域网内
尽可能避免在压力很大的主库上增长从库
主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...
这样的结构方便解决单点故障问题,实现Slave对Master的替换。若是Master挂了,能够马上启用Slave1作Master,其余不变。
6. MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
相关知识:redis 内存数据集大小上升到必定大小的时候,就会施行数据淘汰策略。
redis 提供6种数据淘汰策略,上文已经列出。
7.redis的存储分类
redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
redis能够作优先级队列的设置;
redis是一个key-value存储系统。
Redis支持主从同步。
8.Redis有哪些数据结构?
(1)字符串String,常规计数:微博数,粉丝数等。命令:get / set / del / expire
(2)字典Hash,Redis的散列能够存储多个键值对之间的映射。和字符串同样,散列存储的值既能够是字符串又能够是数字值,而且用户一样能够对散列存储的数字执行自增操做或者是自减操做。命令:hget / hset / hdel / hgetall
(3)列表List,存储某个key的list;使用场景:微博 TimeLine、消息队列
rpush users zhangsan(将给定值推送到列表右端),
lpush users lisi(将给定值推送到列表左端)
rpop users(获取给定值最右端一个值,调用后会从users的key中删除该值),
lpop users(获取给定值最左端一个值,调用后会从users的key中删除该值),
lrange users 0-1 获取给定key,给定范围全部值
lindex users 1 获取下标(从0位开始计算)1位置值
(4)集合Set:Redis的集合使用的是无序的方式存储元素,因此不能够像List列表那样,将元素推入集合的某一端,或者从集合的某一端弹出元素。使用场景:共同好友、二度好友,利用惟一性,能够统计访问网站的全部独立 IP,好友推荐的时候,根据 tag 求交集,大于某个 threshold 就能够推荐
(1)经常使用命令以下:
(2)除了常见的命令以外,还有交集、并集、差集的计算,以下:
(5)有序集合SortedSet:和set相比,sorted set增长了一个权重参数score,使得集合中的元素可以按score进行有序排列;场景:排行榜应用,取TOP N操做;这个需求与上面需求的不一样之处在于,前面操做以时间为权重,这个是以某个条件为权重
//将登陆次数和用户统一存储在一个sorted set里 zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3 //当用户登陆时,对该用户的登陆次数自增1 ret = r.zincrby("login:login_times", 1, uid) //那么如何得到登陆次数最多的用户呢,逆序排列取得排名前N的用户 ret = r.zrevrange("login:login_times", 0, N-1)
若是你是Redis中高级用户,还须要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。
Pub/Sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在Redis中,你能够设定对某一个key值进行消息发布及消息订阅,当一个key值上进行了消息发布后,全部订阅它的客户端都会收到相应的消息。这一功能最明显的用法就是用做实时消息系统,好比普通的即时聊天,群聊等功能。
若是你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。
9.使用过Redis分布式锁么,它是什么回事?
先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。
而后接着问若是在setnx以后执行expire以前进程意外crash或者要重启维护了,那会怎么样?
是喔,这个锁就永远得不到释放了。而后回答:我记得set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!
10.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,若是将它们所有找出来?
使用keys指令能够扫出指定模式的key列表。
对方接着追问:若是这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会致使线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可使用scan指令,scan指令能够无阻塞的提取出指定模式的key列表,可是会有必定的重复几率,在客户端作一次去重就能够了,可是总体所花费的时间会比直接用keys指令长。
11.使用过Redis作异步队列么,你是怎么用的?
通常使用list结构做为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
若是对方追问可不能够不用sleep呢?list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
若是对方追问能不能生产一次消费屡次呢?使用pub/sub主题订阅者模式,能够实现1:N的消息队列。
若是对方追问pub/sub有什么缺点?在消费者下线的状况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
若是对方追问redis如何实现延时队列?
使用sortedset,拿时间戳做为score,消息内容做为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒以前的数据轮询进行处理。
12.若是有大量的key须要设置同一时间过时,通常须要注意什么?
若是大量的key过时时间设置的过于集中,到过时的那个时间点,redis可能会出现短暂的卡顿现象。通常须要在时间上加一个随机值,使得过时时间分散一些。
13.Redis如何作持久化的?
bgsave作镜像全量持久化,aof作增量持久化。由于bgsave会耗费较长时间,不够实时,在停机的时候会致使大量丢失数据,因此须要aof来配合使用。在redis实例重启时,优先使用aof来恢复内存的状态,若是没有aof日志,就会使用rdb文件来恢复。
若是再问aof文件过大恢复时间过长怎么办?你告诉面试官,Redis会按期作aof重写,压缩aof文件日志大小。若是面试官不够满意,再拿出杀手锏答案,Redis4.0以后有了混合持久化的功能,将bgsave的全量和aof的增量作了融合处理,这样既保证了恢复的效率又兼顾了数据的安全性。这个功能甚至不少面试官都不知道,他们确定会对你另眼相看。
若是对方追问那若是忽然机器掉电会怎样?取决于aof日志sync属性的配置,若是不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。可是在高性能的要求下每次都sync是不现实的,通常都使用定时sync,好比1s1次,这个时候最多就会丢失1s的数据。
若是对方追问bgsave的原理是什么?你给出两个词汇就能够了,fork和cow。fork是指redis经过建立子进程来进行bgsave操做,cow指的是copy on write,子进程建立后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
14.Pipeline有什么好处,为何要用pipeline?
能够将屡次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候能够发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。
15.Redis的同步机制了解么?
Redis可使用主从同步,从从同步。第一次同步时,主节点作一次bgsave,并同时将后续修改操做记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操做记录同步到复制节点进行重放就完成了同步过程。
16.是否使用过Redis集群,集群的原理是什么?
Redis Sentinal着眼于高可用,在master宕机时会自动将slave提高为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
17.使用redis有什么缺点
分析:你们用redis这么久,这个问题是必需要了解的,基本上使用redis都会碰到一些问题,常见的也就几个。
回答:主要是四个问题
(一)缓存和数据库双写一致性问题
(二)缓存雪崩问题
(三)缓存击穿问题
(四)缓存的并发竞争问题
18.Redis常见命令:
获取链接:redis-cli -p 端口 -a 密码
获取全部key:keys *
获取某个key:keys *USER_RELATION_KEY_*
获取某个key中值:get USER_RELATION_KEY_*
清空全部数据:flushdb
数量获取:dbsize
查看redis信息:info
19.单线程的redis为何这么快
分析:这个问题实际上是对redis内部机制的一个考察。其实根据博主的面试经验,不少人其实都不知道redis是单线程工做模型。因此,这个问题仍是应该要复习一下的。
回答:主要是如下三点
(一)纯内存操做
(二)单线程操做,避免了频繁的上下文切换
(三)采用了非阻塞I/O多路复用机制
题外话:咱们如今要仔细的说一说I/O多路复用机制,由于这个说法实在是太通俗了,通俗到通常人都不懂是什么意思。博主打一个比方:小曲在S城开了一家快递店,负责同城快送服务。小曲由于资金限制,雇佣了一批快递员,而后小曲发现资金不够了,只够买一辆车送快递。
20.redis的过时策略以及内存淘汰机制
分析:这个问题其实至关重要,到底redis有没用到家,这个问题就能够看出来。好比你redis只能存5G数据,但是你写了10G,那会删5G的数据。怎么删的,这个问题思考过么?还有,你的数据已经设置了过时时间,可是时间到了,内存占用率仍是比较高,有思考过缘由么?
回答:
redis采用的是按期删除+惰性删除策略。
为何不用定时删除策略?
定时删除,用一个定时器来负责监视key,过时则自动删除。虽然内存及时释放,可是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,所以没有采用这一策略.
按期删除+惰性删除是如何工做的呢?
按期删除,redis默认每一个100ms检查,是否有过时的key,有过时key则删除。须要说明的是,redis不是每一个100ms将全部的key检查一次,而是随机抽取进行检查(若是每隔100ms,所有key进行检查,redis岂不是卡死)。所以,若是只采用按期删除策略,会致使不少key到时间没有删除。
因而,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key若是设置了过时时间那么是否过时了?若是过时了此时就会删除。
采用按期删除+惰性删除就没其余问题了么?
不是的,若是按期删除没删除key。而后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会愈来愈高。那么就应该采用内存淘汰机制。
在redis.conf中有一行配置
# maxmemory-policy volatile-lru
该配置就是配内存淘汰策略的(什么,你没配过?好好检讨一下本身)
1)noeviction:当内存不足以容纳新写入数据时,新写入操做会报错。应该没人用吧。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。应该也没人用吧,你不删最少使用Key,去随机删。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,移除最近最少使用的key。这种状况通常是把redis既当缓存,又作持久化存储的时候才用。不推荐
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,随机移除某个key。依然不推荐
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过时时间的键空间中,有更早过时时间的key优先移除。不推荐
ps:若是没有设置 expire 的key, 不知足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 noeviction(不删除) 基本上一致。
21.redis和数据库双写一致性问题
分析:一致性问题是分布式常见问题,还能够再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是若是对数据有强一致性要求,不能放缓存。咱们所作的一切,只能保证最终一致性。另外,咱们所作的方案其实从根本上来讲,只能说下降不一致发生的几率,没法彻底避免。所以,有强一致性要求的数据,不能放缓存。
首先,采起正确更新策略,先更新数据库,再删缓存。其次,由于可能存在删除缓存失败的问题,提供一个补偿措施便可,例如利用消息队列。
22.如何应对缓存穿透和缓存雪崩问题
分析:这两个问题,说句实在话,通常中小型传统软件企业,很难碰到这个问题。若是有大并发的项目,流量有几百万左右。这两个问题必定要深入考虑。
回答:以下所示
缓存穿透,即黑客故意去请求缓存中不存在的数据,致使全部的请求都怼到数据库上,从而数据库链接异常。
解决方案:
(一)利用互斥锁,缓存失效的时候,先去得到锁,获得锁了,再去请求数据库。没获得锁,则休眠一段时间重试
(二)采用异步更新策略,不管key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存若是过时,异步起一个线程去读数据库,更新缓存。须要作缓存预热(项目启动前,先加载缓存)操做。
(三)提供一个能迅速判断请求是否有效的拦截机制,好比,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。若是不合法,则直接返回。
缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而致使数据库链接异常。
解决方案:
(一)给缓存的失效时间,加上一个随机值,避免集体失效。
(二)使用互斥锁,可是该方案吞吐量明显降低了。
(三)双缓存。咱们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。本身作缓存预热操做。而后细分如下几个小点
I 从缓存A读数据库,有则直接返回
II A没有数据,直接从B读数据,直接返回,而且异步启动一个更新线程。
III 更新线程同时更新缓存A和缓存B。
23.如何解决redis的并发竞争key问题
分析:这个问题大体就是,同时有多个子系统去set一个key。这个时候要注意什么呢?你们思考过么。须要说明一下,博主提早百度了一下,发现答案基本都是推荐用redis事务机制。博主不推荐使用redis的事务机制。由于咱们的生产环境,基本都是redis集群环境,作了数据分片操做。你一个事务中有涉及到多个key操做的时候,这多个key不必定都存储在同一个redis-server上。所以,redis的事务机制,十分鸡肋。
回答:以下所示
(1)若是对这个key操做,不要求顺序
这种状况下,准备一个分布式锁,你们去抢锁,抢到锁就作set操做便可,比较简单。
(2)若是对这个key操做,要求顺序
假设有一个key1,系统A须要将key1设置为valueA,系统B须要将key1设置为valueB,系统C须要将key1设置为valueC.
指望按照key1的value值按照 valueA–>valueB–>valueC的顺序变化。这种时候咱们在数据写入数据库的时候,须要保存一个时间戳。假设时间戳以下
系统A key 1 {valueA 3:00}
系统B key 1 {valueB 3:05}
系统C key 1 {valueC 3:10}
那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现本身的valueA的时间戳早于缓存中的时间戳,那就不作set操做了。以此类推。
其余方法,好比利用队列,将set方法变成串行访问也能够。总之,灵活变通。