redis面试题整理
Redis是单线程
redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销
Reids常用5种数据类型
- string,list,set,sorted set,hash
redis常用的五种类型的应用
String :常用,不讲
hash:存放对象 ,便于修改,存放多级的数据,比如说购物车,用户id为key,商品id 为filed 商品数量为calue
list:用于消息的队列,排行榜,最新列表
-
命令常用
- lpush 添加一个或多个元素插入到list的头部 .
- lpop 从 list 中删除并返回第一个元素
-
rpush添加字符串元素到对应 list 的尾部
-
rpop从list 的尾部删除元素,并返回删除元素
-
llen获取list的元素个数
-
lrange获取列表指定范围内的元素
-
lindex获取列表中指定位置的元素
消息队列 :lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能(有了mq不推荐使用这个)
排行榜:lrange获取列表指定范围内的元素,每隔一段时间计算一次的排行榜存储在list类型
最新列表:每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表
set:其特点是集合元素无序且不重复 ,比如说,好友,关注,感兴趣的人,sinter命令可以获得A和B两个用户的共同好友,sismember命令可以判断A是否是B的好友,scard命令可以获取好友数量
sorted set:游戏排名、微博热点话题等使用场景。
Reids6种淘汰策略:
- noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外。
- **allkeys-lru:**所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
- **volatile-lru:**只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
- **allkeys-random:**所有key通用; 随机删除一部分 key。
- volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
- volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
Redis 持久化方案:
rdb 和 Aof
rdb的执行策略
-
手动
- save 调用 save 命令即可触发 redis 进行 RDB 文件生成备份 ----------会发生阻塞
- bgsave redis 服务器 fork 一个子进程进行 RDB 文件备份生成
-
自动---自动间隔性
- Redis使用fork函数复制一份当前进程(父进程)的副本(子进程)
-
父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中
的临时文件RDB;
-
当子进程写入完所有数据后会用该临时文件RDB替换旧的RDB文件,至此一次快照操作完
成。
AOF的执行策略
- Always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到磁盘里面,在这种模式下,服务器即使遭遇意外停机,也不会丢失任何自己已经成功执行的命令数据
- Everysec:服务器每一秒重调用一次fdatasync,将缓冲区里面的命令写入到磁盘里面,在这种模式写,服务器即使遭遇意外停机时,最多只丢失一秒钟内执行的命令数据
- NO:服务器不主动调用fdatasync,由操作系统决定任何将缓冲区里面的命令写入磁盘里面,在这种模式写,服务器遭遇意外停机时,丢失命令的数据是不确定的
- always的速度慢,everysec和no都很快,默认值:everysec
aof和rdb的优缺点
RDB持久化机制的优点
- RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去
- RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
- 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
RDB持久化机制的缺点
- 如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据
- RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒
- RDB无法实时持久化
AOF持久化机制的优点
- AOF可以更好的保护数据不丢失(顶多丢失1秒)
- AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高
- AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
- 适合做灾难性的误删除紧急恢复(aof的文件里面存放的是命令,如果有删除的操作,直接删除掉最后一个删除的日志命令,重新执行即可)
AOF持久化机制的缺点
- 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大(aof存放的是命令,rdb存放的是2进制的操作命令)
什么是哨兵机制?
Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务:
- 监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
- 提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
主观下线和客观下线:
- 主观下线:刚知道哨兵节点每隔1秒对主节点和从节点、其它哨兵节点发送ping做心跳检测,当这些心跳检测时间超过down-after-milliseconds时,哨兵节点则认为该节点错误或下线,这叫主观下线;这可能会存在错误的判断。
- 客观线下:当足够(大于等于配置文件指定的值)的哨兵认为master下线是,则为客观下线
Redis Sentinel是怎么工作的?
1)每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令。
2)如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被当前 Sentinel 标记为主观下线。
3)如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。
4)当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 。
5)当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次 (在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令 )。
6)若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会变成主观下线。 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
7)sentinel节点会与其他sentinel节点进行“沟通”,投票选举一个sentinel节点进行故障处理,在从节点中选取一个主节点,其他从节点挂载到新的主节点上自动复制新主节点的数据。
故障转移时会从剩下的slave选举一个新的master,被选举为master的标准是什么?
- 跟master断开连接的时长
- slave优先级。按照slave优先级进行排序,slave priority越低,优先级就越高
- 复制offset 如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
- run id 如果上面两个条件都相同,那么选择一个run id比较小的那个slave
执行切换的那个哨兵在完成故障转移后会做什么?
会进行configuraiton配置信息传播。
哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后通过pub/sub消息机制同步给其他的哨兵
同步配置的时候其他哨兵根据什么更新自己的配置呢?
执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的。
如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch 作为新的version号。
这个version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的,其他的哨兵都是根据版本号的大小来更新自己的master配置的
----------------------------详细的可以到https://www.cnblogs.com/ibigboy/p/12205889.html去看看,我很喜欢-----------------------------
Redis是单线程的,但Redis为什么这么快?-------这个问题很不喜欢
1、完全基于内存,
2、使用多路I/O复用模型,非阻塞IO;这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程
什么是雪崩?
- 对于“Redis挂掉了,请求全部走数据库”
- “对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。
怎么解决雪崩?
- 对缓存数据设置相同的过期时间,导致某段时间内缓存失效,解决方案是在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。
- Redis挂掉了 解决方案:万一Redis真的挂了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
什么是缓存穿透?
- 请求的数据在缓存大量不命中,导致请求走数据库。缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪
如何解决缓存穿透?
- 布隆过滤器
什么是布隆过滤器?
- bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小
Reids主从复制
复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。
redis主从复制的特点:
-
redis采用异步方式复制数据到slave节点,从redis2.8开始,slave节点会周期性地确认自己每次复制的数据量;
-
一个master节点可以配置多个slave节点;
-
slave节点可以连接其他的slave节点;
-
slave节点做复制的时候,不会阻塞master节点的正常工作;
-
slave节点做复制的时候,也不会阻塞对自己的查询操作,它会用旧数据集来提供服务,但在复制完成时,需要删除旧数据集,加载新数据集,这时会暂停对外服务;
-
slave节点主要用来横向扩容,做读写分离,扩容的slave节点可以提高读的吞吐量;
-
如果采用主从架构,必须开启master节点的持久化,不建议用slave节点作master节点的数据热备,因为如果一旦关掉master的持久化,可能在master宕机重启时数据是空的,然后一经复制,slave节点也会随之丢失
Redis主从复制分为全量复制和增量复制。
- 全量复制一般发生在Slave初始化阶段,这时slave需要将master上的所有数据都复制一份
- 增量复制一般是 Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程
全量复制的步骤
-
从服务器连接主服务器,发送psync命令;
-
主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
-
主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
-
从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
-
主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
-
从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
增量复制的步骤
-
如果全量复制过程中,master-slave 网络连接断掉,那么 slave 重新连接 master 时,会触发增量复制。
-
master 直接从自己的 backlog 中获取部分丢失的数据,发送给 slave node,默认 backlog 就是 1MB。
-
master 就是根据 slave 发送的 psync 中的 offset 来从 backlog 中获取数据的。
Redis分布式锁实现
用的redis.setnx()命令,记得设置过期时间,finally里面是释放锁,锁的时间考虑一下,业务的执行时间即可没如果执行完毕,未执行完毕,锁的时间到期了,可以考虑在数据库层面加上乐观锁,
本文地址:https://blog.csdn.net/qq_37368570/article/details/107199220
上一篇: 《算法笔记上机实验指南》第4章 入门篇(2)---算法初步 5.6大整数运算
下一篇: day5作业