redis常见原理面试

redis核心机制及面试

  • 一、面试
    • 1 Redis有哪些数据结构?
    • 2 使用过Redis分布式锁么,它是什么回事?
    • 3 假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?
    • 4 使用过Redis做异步队列么,你是怎么用的?
    • 5 如果有大量的key需要设置同一时间过期,一般需要注意什么?
    • 6 Redis如何做持久化的?
    • 7 Pipeline有什么好处,为什么要用pipeline?
    • 8 Redis的同步机制了解么?
    • 9 是否使用过Redis集群,集群的原理是什么?
      • Redis Cluster原理
    • 10、redis单线程问题
    • 11、为什么说redis能够快速执行
    • 12、redis的内部实现
    • 13、Redis关于线程安全问题
    • 14、使用redis有哪些好处?
    • 15、redis相比memcached有哪些优势?
    • 16、Redis主从复制
    • 17、redis两种持久化方式的优缺点
    • 18、RDB的优点:
    • 19、redis的过期策略以及内存淘汰机制
      • 分析:
      • 回答:
        • 为什么不用定时删除策略?
        • 定期删除+惰性删除是如何工作的呢?
        • 采用定期删除+惰性删除就没其他问题了么?
      • 该配置就是配内存淘汰策略的(什么,你没配过?好好反省一下自己)
      • 使用策略规则:
    • 20、Redis 常见的性能问题都有哪些?如何解决?
    • 21、如何访问 Redis 中的海量数据?
      • 事故产生
      • 分析原因
      • 解决方案
    • 22、Redis集群,集群的原理是什么?
    • 23、redis和数据库双写一致性问题
    • 24、如何解决redis的并发竞争key问题
    • 25、缓存穿透
      • 解决办法
    • 26、缓存雪崩
      • 解决办法
      • 对于“Redis挂掉了,请求全部走数据库”这种情况,我们可以有以下的思路:
        • 事发前:
        • 事发中:
        • 事发后:
    • 27、怎样监控redis阻塞在哪里
    • 28、说说LFU和LRU的区别
    • 29、如果一次性导入100W条数据到redis ,怎么做
    • 30、Redis实现消息队列
    • 31、Redis中的管道有什么用?
    • 32、Redis的同步机制了解么?
    • 33、解决单点问题主要有2种方式
      • 主备方式
      • 主从方式
    • 34、数据同步方式2种
      • 同步方式:
      • 异步方式:
    • 35、reids内存管理
      • 最大内存设置
    • 36、Redis的rehash过程

一、面试

1 Redis有哪些数据结构?

string:最基本的数据类型,二进制安全的字符串,最大512M

list:按照添加顺序保持顺序的 字符串列表

set:无序的字符串集合,不存在重复的元素

sorted set:已排序的字符串集合

hash:key/value对的一种集合

如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。
如果你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。

2 使用过Redis分布式锁么,它是什么回事?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!对方这时会显露笑容,心里开始默念:摁,这小子还不错。

3 假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。
对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

4 使用过Redis做异步队列么,你是怎么用的?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
如果对方追问可不可以不用sleep呢?list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
如果对方追问能不能生产一次消费多次呢?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
如果对方追问pub/sub有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
如果对方追问redis如何实现延时队列?我估计现在你很想把面试官一棒打死如果你手上有一根棒球棍的话,怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
到这里,面试官暗地里已经对你竖起了大拇指。但是他不知道的是此刻你却竖起了中指,在椅子背后。

5 如果有大量的key需要设置同一时间过期,一般需要注意什么?

如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

6 Redis如何做持久化的?

bgsave做镜像全量持久化,aof做增量持久化。因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在redis实例重启时,优先使用aof来恢复内存的状态,如果没有aof日志,就会使用rdb文件来恢复。
如果再问aof文件过大恢复时间过长怎么办?你告诉面试官,Redis会定期做aof重写,压缩aof文件日志大小。如果面试官不够满意,再拿出杀手锏答案,Redis4.0之后有了混合持久化的功能,将bgsave的全量和aof的增量做了融合处理,这样既保证了恢复的效率又兼顾了数据的安全性。这个功能甚至很多面试官都不知道,他们肯定会对你刮目相看。
如果对方追问那如果突然机器掉电会怎样?取决于aof日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。

7 Pipeline有什么好处,为什么要用pipeline?

可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。

8 Redis的同步机制了解么?

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

9 是否使用过Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

Redis Cluster原理

Redis Cluster 是Redis的集群实现,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384 决定。

关于负载均衡,集群的Redis Instance之间可以迁移数据,以Slot为单位,但不是自动的,需要外部命令触发。

关于集群成员管理,集群的节点(Redis Instance)和节点之间两两定期交换集群内节点信息并且更新,从发送节点的角度看,这些信息包括:集群内有哪些节点,IP和PORT是什么,节点名字是什么,节点的状态(比如OK,PFAIL,FAIL,后面详述)是什么,包括节点角色(master 或者 slave)等。

关于可用性,集群由N组主从Redis Instance组成。主可以没有从,但是没有从 意味着主宕机后主负责的Slot读写服务不可用。一个主可以有多个从,主宕机时,某个从会被提升为主,具体哪个从被提升为主,协议类似于Raft,参见这里。如何检测主宕机?Redis Cluster采用quorum+心跳的机制。从节点的角度看,节点会定期给其他所有的节点发送Ping,cluster-node-timeout(可配置,秒级)时间内没有收到对方的回复,则单方面认为对端节点宕机,将该节点标为PFAIL状态。通过节点之间交换信息收集到quorum个节点都认为这个节点为PFAIL,则将该节点标记为FAIL,并且将其发送给其他所有节点,其他所有节点收到后立即认为该节点宕机。从这里可以看出,主宕机后,至少cluster-node-timeout时间内该主所负责的Slot的读写服务不可用。

10、redis单线程问题

Redis是单进程单线程的!

单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。

Redis利用队列技术将并发访问变为串行访问,并用I/O多路复用,消除了传统数据库串行控制的开销。

11、为什么说redis能够快速执行

1、绝大部分请求是纯粹的内存操作(非常快速)
2、采用单线程,避免了不必要的上下文切换和竞争条件
3、非阻塞IO - IO多路复用

12、redis的内部实现

内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。
epoll中的读、写、关闭、连接都转化成了事件,
然后利用epoll的多路复用特性,不在io上浪费一点时间
这3个条件不是相互独立的,特别是第一条,如果请求都是耗时的,采用单线程吞吐量及性能很差。redis为特殊的场景选择了合适的技术方案。

13、Redis关于线程安全问题

redis实际上是采用了线程封闭的观念,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个redis操作的复合操作来说,依然需要锁,而且有可能是分布式锁。

14、使用redis有哪些好处?

1、速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
2、支持丰富数据类型,支持string,list,set,sorted set,hash
3、支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
4、丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

15、redis相比memcached有哪些优势?

1、memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
2、redis的速度比memcached快很多
3、redis可以持久化其数据
4、Redis支持数据的备份,即master-slave模式的数据备份。
5、使用底层模型不同,它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。
Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
6、value大小:redis最大可以达到1GB,而memcache只有1MB

16、Redis主从复制

过程原理:

1、当从库和主库建立MS关系后,会向主数据库发送SYNC命令
2、主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程),并将期间接收到的写命令缓存起来
3、当快照完成后,主Redis会将快照文件和所有缓存的写命令发送给从Redis
4、从Redis接收到后,会载入快照文件并且执行收到的缓存的命令
5、之后,主Redis每当接收到写命令时就会将命令发送从Redis,从而保证数据的一致

缺点:所有的slave节点数据的复制和同步都由master节点来处理,会照成master节点压力太大,使用主从从结构来解决

17、redis两种持久化方式的优缺点

1、RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)

2、AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。

3、Redis 还可以同时使用 AOF 持久化和 RDB 持久化。当redis重启时,它会有限使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更加完整

18、RDB的优点:

1、RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。这种文件非常适合用于进行备份:比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
2、RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心。
3、RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
4、RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快

19、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:当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。这是redis默认的,不过不建议用。

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(不删除) 基本上一致。

使用策略规则:

如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru

如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random

20、Redis 常见的性能问题都有哪些?如何解决?

1、Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

2、Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

3、Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

4、Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

21、如何访问 Redis 中的海量数据?

有时候我们需要知道线上的redis的使用情况,尤其需要知道一些前缀的key值,那我们怎么去查看呢

事故产生

因为我们的用户token缓存是采用了【user_token:userid】格式的key,保存用户的token的值。

我们运维为了帮助开发小伙伴们查一下线上现在有多少登录用户,直接用了keys user_token*方式进行查询。

事故就此发生了。导致redis不可用,假死。

分析原因

我们线上的登录用户有几百万,数据量比较多;keys算法是遍历算法,复杂度是O(n),也就是数据越多,时间复杂度越高。

数据量达到几百万,keys这个指令就会导致 Redis 服务卡顿

因为 Redis 是单线程程序,顺序执行所有指令,其它指令必须等到当前的 keys 指令执行完了才可以继续。

解决方案

那我们如何去遍历大数据量呢?

这个也是面试经常问的。我们可以采用redis的另一个命令scan。我们看一下scan的特点

1、复杂度虽然也是 O(n),但是它是通过游标分步进行的,不会阻塞线程

2、提供 count 参数,不是结果数量,是redis单次遍历字典槽位数量(约等于)

3、同 keys 一样,它也提供模式匹配功能;

4、服务器不需要为游标保存状态,游标的唯一状态就是 scan 返回给客户端的游标整数;

5、返回的结果可能会有重复,需要客户端去重复,这点非常重要;

6、单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零

一、scan命令格式

SCAN cursor [MATCH pattern] [COUNT count]

命令解释:scan 游标 MATCH <返回和给定模式相匹配的元素> count 每次迭代所返回的元素数量

for example:

redis > scan 0 match user_token* count 5
 1) "6"
 2) 1) "user_token:1000"
 2) "user_token:1001"
 3) "user_token:1010"
 4) "user_token:2300"
 5) "user_token:1389"

22、Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

23、redis和数据库双写一致性问题

分析:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。

数据库和缓存双写,就必然会存在不一致的问题。

答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。

另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。
首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

24、如何解决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方法变成串行访问也可以。总之,灵活变通。

25、缓存穿透

缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

解决办法

①对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

②也可以采用一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

26、缓存雪崩

如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

解决办法

①在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

②可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存

③不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀. 比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件

④做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

对于“Redis挂掉了,请求全部走数据库”这种情况,我们可以有以下的思路:

事发前:

实现Redis的高可用(主从架构+Sentinel 或者Redis Cluster),尽量避免Redis挂掉这种情况发生。

事发中:

万一Redis真的挂了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)。“丢车保帅”一定确保数据库安全。

事发后:

redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

27、怎样监控redis阻塞在哪里

咋,你用redis发生了阻塞你不知道咋监控?听天由命,束手无策?你是不是没用过Redis啊?啥,你用过?那你是不是只用过get set啊。

答案:用 monitor命令啊

28、说说LFU和LRU的区别

你不是跟我谈Redis的淘汰策略吗?那我就要问问你他其中的两个淘汰策略是啥意思,总不能只知道英文不知道意思吧。

LFU:最近最不经常使用,根据使用频次的多少淘汰

LRU:最近最少使用,凡是使用过的元素移到队首,淘汰队尾的元素。

29、如果一次性导入100W条数据到redis ,怎么做

这个如果你不知道管道,那算你不会。将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。

30、Redis实现消息队列

普通队列:一般使用list结构作为队列,rpush生产消息,lpop消费消息,blpop阻塞消费。
消费多次:生产一次消费多次的情况使用发布/订阅模式(不建议使用)
延时队列:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理

31、Redis中的管道有什么用?

一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。

这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。

32、Redis的同步机制了解么?

Redis可以使用主从同步,从从同步。
第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。
加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

33、解决单点问题主要有2种方式

主备方式

这种通常是一台主机、一台或多台备机,在正常情况下主机对外提供服务,并把数据同步到备机,当主机宕机后,备机立刻开始服务。
Redis HA中使用比较多的是keepalived,它使主机备机对外提供同一个虚拟IP,客户端通过虚拟IP进行数据操作,正常期间主机一直对外提供服务,宕机后VIP自动漂移到备机上。

优点是对客户端毫无影响,仍然通过VIP操作。

缺点是在绝大多数时间内备机是一直没使用,被浪费着的。

主从方式

这种采取一主多从的办法,主从之间进行数据同步。 当Master宕机后,通过选举算法(Paxos、Raft)从slave中选举出新Master继续对外提供服务,主机恢复后以slave的身份重新加入。

主从另一个目的是进行读写分离,这是当单机读写压力过高的一种通用型解决方案。 其主机的角色只提供写操作或少量的读,把多余读请求通过负载均衡算法分流到单个或多个slave服务器上。

缺点是主机宕机后,Slave虽然被选举成新Master了,但对外提供的IP服务地址却发生变化了,意味着会影响到客户端。 解决这种情况需要一些额外的工作,在当主机地址发生变化后及时通知到客户端,客户端收到新地址后,使用新地址继续发送新请求。

34、数据同步方式2种

无论是主备还是主从都牵扯到数据同步的问题,这也分2种情况:

同步方式:

当主机收到客户端写操作后,以同步方式把数据同步到从机上,当从机也成功写入后,主机才返回给客户端成功,优点也称数据强一致性。
缺点 很显然这种方式性能会降低不少。
解决办法当从机很多时,可以不用每台都同步,主机同步某一台从机后,从机再把数据分发同步到其他从机上,这样提高主机性能分担同步压力。 在redis中是支持这种配置的,一台master,一台slave,同时这台slave又作为其他slave的master。

异步方式:

主机接收到写操作后,直接返回成功,然后在后台用异步方式把数据同步到从机上。 优点这种同步性能比较好,缺点 但无法保证数据的完整性,比如在异步同步过程中主机突然宕机了,也称这种方式为数据弱一致性。

Redis主从同步采用的是异步方式,因此会有少量丢数据的危险。

35、reids内存管理

最大内存设置

默认情况下,在32位OS中,Redis最大使用3GB的内存,在64位OS中则没有限制。

在使用Redis时,应该对数据占用的最大空间有一个基本准确的预估,并为Redis设定最大使用的内存。否则在64位OS中Redis会无限制地占用内存(当物理内存被占满后会使用swap空间),容易引发各种各样的问题。

通过如下配置控制Redis使用的最大内存:

maxmemory 100mb

在内存占用达到了maxmemory后,再向Redis写入数据时,Redis会:

1、根据配置的数据淘汰策略尝试淘汰数据,释放空间

2、如果没有数据可以淘汰,或者没有配置数据淘汰策略,那么Redis会对所有写请求返回错误,但读请求仍然可以正常执行

在为Redis设置maxmemory时,需要注意:

如果采用了Redis的主从同步,主节点向从节点同步数据时,会占用掉一部分内存空间,如果maxmemory过于接近主机的可用内存,就会导致数据同步时内存不足。

所以设置的maxmemory不要过于接近主机可用的内存,留出一部分预留用作主从同步。

36、Redis的rehash过程

过程是:

RedisServer结构体中(Redis使用C语言完成)有一个Dictionary数组,默认容量大小是16, 每个 Dictionary结构体中有三个Dict结构体指针,Dict其实就是一个KV结构,类似于HashMap,其中两个作为数据存储的库,一个作为当前使用,一个作为备用rehash;另外一个Dict存储键的过期时间。

Redis的rehash过程其实就是将上述的16个Dictionary进行rehash,Redis内部支持一个周期循环运行的ctro函数,这个函数定期检查上述的16个Dictionary是否需要rehash,如果有需要,ctro会完成Dictionary的rehash过程,周期结束后并且记录当前循环到Dictionary数组中的哪一个角标,方便再次循环时从上一次循环停止的地方开始。

其中还有一点,Redis的rehash是延迟性的,每次put会将新元素加入到新的表中,每次查询时,首先会在新的表中查找,如果没有,在旧的表中查找,查找到的话将这个元素插入到新的表中(这个过程也会涉及到检查元素是否过期的问题)

你可能感兴趣的:(redis,redis常见面试问题)