Redis面试篇

2021-11-12  本文已影响0人  小驴小驴

Redis篇

一、Redis单线程为什么快?

  1. 网络层面:

    在操作系统层面使用了操作系统提供的Epoll函数,并且在Epoll模型中也只是使用同一个线程去接受请求与处理请求,这有点类似于IO模型中的单Reactor单线程模型。

    也就是因为在取操作与处理是单线程的,那么对数据的操作自然也就不需要添加很多的锁来保护共享资源。因此操作自然没有线程上下文切换与加锁的耗时。

  2. 架构方面:

    1. 数据完全存储在内存中,不涉及到磁盘IO(当然了,这里先撇开数据持久化的问题)

    2. Redis内部的数据结构,如:sds(int、embstr、raw)、hashtable、ziplist、quicklist、skiplist等优秀的数据结构

    3. Redis很多数据类型提供了很多小的优化

      • hashtable它底层是dict的数据结构去实现的,它的扩容阈值就与普通的hash不一致,redis的dict它是扩容会更早,这样就可以减少dict结构中的链表结构的查询时间复杂度O(n)
      • 包括dict在扩容的时候,它是渐进性的rehash的过程,以减少单次rehash的耗时过久
      • 比如在ziplist与hashtable底层都记录了length长度,因此在调用scard、llen函数时,操作时间复杂度为O(1),而不需要全盘查询计数

二、Redis 持久化

Redis持久化主要有AOF与RDB两种方式

  1. RDB

    RDB更像是Redis备份的一种快照方式,RDB可以灵活的在配置文件中配置RDB的触发时机,当开始RDB时,Redis进程会fork出一个子进程,由子进程完成数据快照的持久化工作,当新RDB文件创建并写入完毕之后,会删除旧版的RDB文件,以新文件代替旧文件。

    优点:文件较小、恢复时间快,适合主从同步的异地备份,包括向主从模式的首次同步也主要是依赖RDB文件(之后同步则会依赖主机发送命令给从机)。

    缺点:

    • 可能会丢失一段时间的数据,如果配置不得当的话
    • 但是若配置的RDB触发时间过于紧凑,那么就会经常性的fock出子进程进行数据同步写入磁盘,是个非常大的消耗。而且数据集越大,fock子进程的的速度就会越慢,导致阻塞主线程,虽然AOF也需要fock出子进程,但是AOF可以控制fsync的调用频率,即控制了写磁盘的速率。
  2. AOF

    AOF不同于RDB,AOF会将每次操作的命令记下,然后以fync的频率将命令持久化至磁盘,AOF提供三种策略将命令持久化至磁盘:

    • 每秒fsync一次,这是效率与备份达到平衡的状态,最多丢失1s的数据(默认)
    • 从不sync,将数据交给了操作系统,由操作系统决定是否写入磁盘,容易丢数据
    • 每次新命令都会进行fsync至磁盘,速度最慢,但是最安全

    优点:AOF不太容易丢失数据,如果丢失数据可能也只是很短暂的时间,写磁盘以Append-Only的方式进行追加,这比随机写磁盘效率要高几倍不止。AOF命令更容易读懂。

    缺点:

    • AOF文件过大(Redis通过Rewrite方式去不断进行AOF文件重写)

三、Redis过期机制

一定要分清楚过期机制与内存淘汰机制的区别

Redis过期机制有两种方式:主动模式、被动模式

主动模式:在查询数据的时候判断当前key是否过期,若过期则进行删除

被动模式:redis尽量以1s10次的频率去抽查20个key,判断是否过期,过期则删除,若当次过期的key超过了25%,则重复进行。

算法:

Redis采用绝对时间进行过期,而未采用相对时间进行过期,这一点原因也非常容易想到,推荐看一个算法:时间轮算法【https://zhuanlan.zhihu.com/p/356647675

四、Redis在主从模式下如何过期

因为Rediskey的过期并不是采用相对时间而是采用了绝对时间点进行过期,那么假设在主从redis所在的服务器时钟并不同步,那么就会导致主从的数据无法到达一致性,因此Redis的从机不会进行数据的删除,而是等待主机在删除之后,将DEL命令写入AOF并且发送给从机进行执行。

五、Redis内存淘汰机制

当Redis中的数据量达到了配置中的maxmemeory时(在64位操作系统中,该配置为0标识没有内存限制,在32位系统中,Redis默认为3GB大小),就会根据所配置的策略进行数据回收

常见的策略有:

六、Redis事务

相关关键字:
watch、multi、exec、discard

Redis事务只支持编译错误的事务回滚,并不支持运行时错误的事务回滚。

编译错误:如命令拼写错误

运行时错误:如操作命令与操作数据类型不相符合

关于Redis为什么不支持回滚

官网回答:不应该将开发中出现的问题留到生产环境,包括编译、运行时所执行的命令。

个人理解:在MySQL中实现事务的回滚是通过undolog来进行事务回滚的,那么本身是一个用来做缓存,数据都存放在内存中的中间件速度势必会遭受到影响。

七、Redis主从复制原理

主从复制分为增量同步与全量同步,流程如下:

每个Slave与Master都会有一个Replication id:offset这样的一个偏移量。当某个slave因为短暂的掉线重连之后,会发送psync并且携带自身的offset消息偏移量,而master也会记录offset的偏移量,并且在master的命令缓冲区中会保存起始偏移量,缓存区中保存着起始偏移量之后的所有命令,如果slave传递过来的offset在偏移量所包含的区域中,那么就会进行增量同步,master会将slave offset之后的命令发送给slave执行。

但假设slave传递来的offset没有被master缓存区所包含,那么就会进行全量同步。在进行全量同步时,master主进程会fock出一个子进程进行RDB文件的生成,最终异步的将RDB文件发送给slave,而slave也有一项配置,在RDB加载进内存之前可否使用slave旧数据进行对外服务。

当然了在全量同步的时候,master会缓冲之后的命令,用做当slave保存了rdb文件之后的增量更新。

在新版本的Redis主从复制中,

psync与sync的区别:

sync是redis老版本的同步数据的协议,但是不能支持部分重同步,因此在新版中使用的都是psync协议。

八、缓存雪崩、缓存穿透、缓存击穿

上一篇下一篇

猜你喜欢

热点阅读