Redis常见面试题

Redis的持久化方式?

RDB:把数据以快照的方式保存到dump.rdb文件中,定时保存

AOF:把对数据修改(增删改)的操作日志以追加的方式写入到appendonly.aof文件中

区别:

RDB 在15分钟内操作了一个key,5分钟内操作了10个key,1分钟内操作了10000个key,将内存中的数据集以快照的方式写入到磁盘中,具体是通过fork一个子进程,子进程异步的将数据集写入到临时文件,写入成功之后就会替换之前的文件,然后再用二进制压缩存储,如果有修改的数据,则不会持久化到文件中,所以RDB保存的是修改前的数据,会丢失数据,这样做的好处是cow(copy-on-write);

  • copy-on-write(写入时复制):是一种计算机程序设计领域的优化策略,如果有多个调用者要使用同一份资源,它他们会获取相同的指针和资源,当有一个调用者要修改这个资源时,系统会复制一个副本供他使用,而其他调用者使用的资源还是最初的的资源。

AOP是把服务器处理的写、删除操作日志记录到文件里,查询操作不会记录,数据恢复的更完整。

两者的优缺点:

使用RDB作为持久化操作,对于灾难性的故障,我们可以很容易恢复,所以我们经常将它作为备份使用,并且它只是fork一个子进程来进行备份操作,不会影响到服务的其他io操作。相比于AOF,它的启动效率很高。但是在它持久化的过程中发生了宕机,则会丢失数据。如果想保证数据的高可用,这并不是一个好方法。

AOF可以带来更高的数据安全性,即 每秒同步、每修改同步 和不同步。每秒同步如果发生宕机,也只是会丢失这一秒的数据,每次修改同步虽然每次都可以持久化,但效率可想而知。并且它是把持久化的数据都以追加的方式写入文件中,如果在写入的过程中发生宕机文件被破坏,我们也可以通过redis自带的工具redis-check-aof来帮助我们修复文件。如果追加的数据过大,Redis会自动触发 rewrite 功能,fork一个子进程,将旧的文件里面的数据写到新文件,会剔除掉一些冗余的数据,如果在重写文件的过程中,服务器同时也接受了其他操作的命令,Redis会设置一个AOF重写缓冲区,将子进程操作过程中服务器操作的新的命令写入到缓冲区中,当子进程写完后,子进程会像服务器发送一个信号,这时,服务器会把缓冲区里的数据都追加到文件中,最后再替换新旧文件。因为是追加数据,所以AOF文件通常要比RDB大的多,在运行效率上也慢于RDB。

 

 

为什么哈希槽的大小是16384?

原作者的回答:

  • Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.

  • At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

1.如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。

redis节点之间通信交换的数据有消息头消息体组成,消息体无外乎是一些节点标识啊,IP啊,端口号啊,发送时间等等,关系不大,主要是消息头,其中最占空间的是 myslots[CLUSTER_SLOTS/8] ,16384/8/1024=8kb,因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

2.redis的集群主节点数量基本不可能超过1000个。

如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

3.槽位越小,节点少的情况下,压缩率高

Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

 

 

Redis为何这么快?

官方提供的数据是可以达到100000+的QPS(每秒内的查询次数),redis确实是单线程的,因为redis完全是基于内存的操作,CPU不是redis的瓶颈,redis的瓶颈是机器内存的大小和网络带宽,既然单线程容易实现,而且CPU不会成为瓶颈,所以就使用单线程了,毕竟多线程也有多线程的麻烦

第一,redis是完成基于内存的,绝大部分请求是纯粹的内存操作,非常迅速。第二,数据结构简单,对数据操作非常方便。第三,用单线程就避免了上下文切换,不存在多线程导致的CPU切换,也不用去考虑加锁解锁的问题,也没有死锁问题导致的性能消耗。第四,使用了多路复用IO模型

多路复用IO模型:只有单个线程,通过跟踪每个I/O流的状态, 来管理多个I/O流。

 

Redis和Memcached的区别

1.memcached把数据全部保存在内存里面,一断电就挂了,redis有部分数据会保存到硬盘上。

2.memcached只支持简单的key-value,而redis支持5种数据类型,还有三种特殊的数据类型

3.memcached的value只有1mb,redis可以达到1gb

 

Redis的回收策略

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-enviction(驱逐):禁止驱逐数据

 

说说主从复制?

一般业务大多是读多写少,所以我们一般配置多台从机,主机负责写,从机负责读。复制流程大致是这样的:

建立连接

首先从机执行slaveof命令,保存主节点信息,这里的slaveof命令是异步的,它在保存主节点信息后立刻放回,实际的建立连接的阶段是在这之后进行的

从节点内部通过定时任务(每秒执行一次)维护复制相关逻辑,如果发现主节点信息,便根据主节点的ip和port建立socker连接

  • 从节点会为该socket建立一个专门处理复制工作相关的文件事件处理器,复制后续的复制工作

如果从节点无法建立连接,则定时任务会不断地重连直到成功或者执行 slaveof on one 取消主从复制。

从节点发送ping,主节点返回pong,表示能够通信,如果返回超时,说明socket不可以,从节点断开,重连。如果返回其他命令,说明当前正在执行其他超时命令,则从节点断开,重连。

如果主节点设置了requirepass参数,则从节点要进行身份认证,否则从节点断开 socket 连接并重新发起连接。 

数据同步阶段

当从节点发送ping命令收到pong后,此时表示可以进行数据同步了。从节点向主节点发送psync命令,主节点根据当前状态来进行不同的复制流程,全量复制和部分复制。

需要注意的是:

  • 主从首次建立连接时全量复制,当主从断开后再重连,则需要根据偏移量来判断是进行全量复制还是部分复制。
  • 数据同步前,从节点是主节点的客户端,因为主节点只需要响应从节点的请求,但到了数据同步阶段,主从节点互为客户端,因为这时候主节点需要自动向从节点发送请求(如推送缓冲区的数据)。

命令传播

当主节点数据同步完成后,为了保证数据一致性,主节点需要持续不断的把写命令给从节点,在这个异步的过程中,主节点把写命令发送给从节点并不会等待从节点的回复,因此主从节点之间的延迟是难免的,所有主从节点保证的是最终一致性。

 

主要作用是:

数据冗余:实现数据的热备份

故障恢复:当主机点出现问题,可以由从节点提供服务

负载均衡:主机负责写,从机负责读

高可用基石:哨兵和集群都是在主从复制基础上来完成的。

 

那你能详细说下数据同步的过程吗?

主节点把数据发送给从节点的过程中,主节点还会接送一些写操作,这些数据会存储在复制缓冲区,当从节点同步主节点数据完成后,主节点会把缓冲区的数据继续发给从节点,用于部分复制

主节点执行写命令时,不但会把命令发送给从节点,还会写入复制积压缓冲区,用于复制命令丢失的数据补救。

 

 

那你能具体说下全量复制和部分复制的过程吗?

offset:它代表着当前节点接受数据的字节数,主节点和从节点都各自维护自己的主从复制偏移量offset,当主节点有写入命令时,offset=offset+命令的字节长度。从节点在收到主节点发送的命令后,也会增加自己的offset,并把自己的offset发送给主节点。这样,主节点同时保存自己的offset和从节点的offset,通过对比offset来判断主从节点数据是否一致。比如,主节点的 offset 是 500,从节点的 offset 是 400,那么主节点在进行数据传输时只需要将 401 ~ 500 传递给从节点即可,这就是部分复制。

复制积压缓冲区

  1. 由主节点维护
  2. 固定大小,默认为 1MB,配置参数为:repl-backlog-size
  3. 是一个先进先出的队列

在命令传播节点,主节点除了将写命令传递给从节点,也会将写命令写入到复制积压缓冲区中,当做一个备份,用于在部分复制流程中。由于它是先进先出的队列,且大小固定,所以他只能保存主节点最近执行的写命令,当主从节点的 offset 相差较大时,超出了复制积压缓冲区的范围,则无法进行部分复制,只能进行全量复制了,所以为了能够提高网络中断引起的全量复制,我们需要认真评估复制积压缓冲区的大小,将其适当调大,比如网络中断时间是 60s,主节点每秒接收的写命令为 100KB,则复制积压缓冲区的平均大小应该为 6MB,所以我们可以将其大小设置为 6MB,甚至是 10MB,来保证绝大多数中断情况下都可以使用部分复制。

runId:一个由 40 位随机的十六进制的字符组成的字符串,当主从节点断开重连时,从节点会将这个 runid 发送给主节点,主节点会根据从节点发送的 runid 来判断选择何种复制

  • 如果从节点发送的 runid 与当前主节点的 runid 一致时,主节点则尝试进行部分复制,当然能不能进行部分复制还要看偏移量是否在复制积压缓冲区
  • 如果从节点发送的 runid 与当前主节点的 runid 不一致时,则进行全量复制

 

上面是全量复制的流程。主要有以下几步:

1、从节点发送psync ? -1命令(因为第一次发送,不知道主节点的runId,所以为?,因为是第一次复制,所以offset=-1)。

2、主节点发现从节点是第一次复制,返回+FULLRESYNC {runId} {offset},同时也会将自身的 runid 和 offset发送给从节点

3、从节点接收主节点信息后,会保存主节点的 runid 和 偏移量 offset

4、主节点在发送+FULLRESYNC后,启动bgsave命令,生成RDB文件(数据持久化)

5、主节点发送RDB文件给从节点,从节点接收保存到本地并将其作为自己的数据文件,如果本地有则会先清空自己的RDB文件,最后从节点加载RDB文件,将数据保存到自己的数据库中

6、如果从节点开启了AOF,从节点会异步重写AOF文件

关于部分复制有以下几点说明:

用于处理网络中断的数据同步

当主从节点中断时间超过 repl-timeout ,主节点会认为从节点出现故障不可达,但主节点依旧能响应命令,但是无法发送给从节点,不过主机节点的复制积压缓冲区依然可以保存最近一段时间的命令数据。当连接恢复之后,从节点发送psync参数给主节点,主节点判断发送过来的runid是否与自身一致,如一致,说明该从节点复制的当前主节点,然后查看请求的 offset 是否在复制积压缓冲区,如果数据存在,就对从节点发送+continue命令,表示可以进行部分复制,否则就进行全量复制。最后主节点只需要根据 offset 将复制积压缓冲区的数据补发给从节点即可

 

那主从复制会存在哪些问题呢?

主机一旦宕机,从节点会要晋升成主节点,需要人工干涉配置。

主节点的写能力和存储能力都受单机能力的影响

如果复制中断,从节点会发起psync,如果不成功要进行全量复制,全量复制可能会造成秒级误差。

 

那你说下哨兵有哪些功能?

主要功能包括主节点存活检测、主从运行情况检测、自动故障转移、主从切换

不断监控主服务器和从服务器是否正常进行,如果出现问题会向通知其他应用程序和管理员。当主节点不能正常过程,它会在从节点里面重新选举一个主节点,其他从节点指向这个新节点。客户端初始化连接的是哨兵节点集合,从中获取主节点的信息。

 

那你能说下哨兵的工作原理吗?

1.首先,每个哨兵节点都会定期执行以下任务:每隔10s向节点发送info信息,获取主从服务器的信息,来更新哨兵下的服务器实例;每个哨兵每秒一次的频率向他认知的主服务器、从服务器以及其他哨兵服务器发送一个ping命令。

2.如果一个实例最后一次恢复ping命令的时间超过down-after-milliseconds,那么会被哨兵指定为主观下线。

3.如果主服务器被标记为主观下线,那么监视这个主服务器的所有其他哨兵服务器会以每秒一次的频率来确定主服务器是否进入主观下线状态。

4.如果主服务器被标记为主观下线,并且有足够的哨兵(至少要达到配置文件指定的数量)在指定时间范围内都同意这一判断,那么这个主服务器被标记为客观下线。

5.一般情况下,每个哨兵会以每10s一次的频率来向他它已知的主服务器和从服务器发送info命令,当一个主服务器被标记为客观下线时,哨兵会向该主服务器下的所有从服务器发送info命令,时间从每10秒发送一次改为每秒发送一次。

6.所有哨兵会判断主服务器的状态,如果处于sdown状态,则会投票自动在从节点中选取一个主节点,将剩下的从节点指定主节点进行数据复制。

7.当没有足够数量的哨兵同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向哨兵的ping命令返回有效回复时,主服务器的主观下线状态就会被移除。

 

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

Master写内存快照,Master AOF持久化,会阻塞主线程的工作,所以Master最好不要写内存快照

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

 

redis 最适合的场景?

会话缓存

全页缓存

队列

排行榜/计数器

发布/订阅

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值