面试 - redis缓存

Redis简介:

redis是一个使用最广泛的缓存中间件,根据月度排行网站DB-Engines的数据,Redis是最流行的键值对存储数据库。
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。支持字符串、哈希表、列表、集合、有序集合、位图、HyperLogLogs等数据类型。内置复制、Lua脚本
LRU回收、事务、以及不同级别磁盘持久化功能,同事通过Redis Sentinel提供高可用,通过RedisCLuster提供自动分区。

WWH

what:是什么、该技术是什么、有什么特性?
why:为什么,为什么要使用该技术,该技术解决了什么问题?
how:怎么做、如何使用该技术?
how:该技术是如何实现的,实现原理?

常见Redis面试题:

Redis支持哪些数据类型:

字符串、哈希表、列表、集合、有序集合

为什么要使用redis缓存

结合实际场景说:
订单信息,一般是写比较少,但是短期内后面可能会有较多的查询。项目中使用String类型来缓存保单数据,查询时减少了对数据库的压力,提高了查询接口的QPS.

缓存和数据库不一致问题

使用缓存的话就有双写的问题,涉及到双写问题,就会有数据不一致的情况。需要保存数据一致需要牺牲性能,不过实际场景中一般也不要求这么高德一致性,要求严格一致的话,可以将读请求和写请求串行化,串到一个内存队列里去,这样就可以保证不会出现不一致的情况。
eg:我们采取 Cache Aside Pattern

缓存模式 : Cache Aside Pattern(先淘汰缓存,再写数据库)

  1. 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据放入缓存,同事返回响应读的时候;
  2. 写的时候,先删除缓存,然后在更新数据库;

那么并发情况下出现了数据不一致怎么办?

eg:有个写请求,此时删除了缓存中的数据,但是还没来及写数据库;这时来了一个读请求,又把数据库中的旧数据load到缓存中去了,然后上一个请求的写数据库完成了。这时,数据库中是最新的数据,缓存却是旧数据了。

思路:部分请求串行化或采取补偿操作

  1. 串行化:将数据库与缓存的更新、读取操作进行异步串行化;将相同id的读写请求hash到同一台服务器处理,服务中使用队列一个一个地执行。如果发现队列中有对应资源的 写请求,那么久等待其执行结束后再去取值(需要考虑等待时间过长的问题,该方案影响较大,较为复杂)
  2. 补偿操作:既然是延迟导致的数据不一致,那么根据数据库实际的延迟时间,我们使用定时任务或者消息触发,如果有写请求结束后,我们在指定的时间之后再删除一次该缓存值,这样即使有不一致的脏数据,也只会出现在延迟的这一段实践中。

缓存穿透和雪崩问题

 什么事缓存穿透和雪崩
 何解决缓存穿透和雪崩

tip: 这两个问题带来的影响都是缓存失效或者未命中导致DB压力大,从而拖垮服务。这些情况都是可能导致DB异常从而影响服务的可用性,我们着手于解决该问题即可。其实关键就是过滤无效的数据,增加缓存命中率,并添加对应的隔离措施以增加整个服务的可用性。

缓存穿透: 访问了不存在的key,缓存未命中,请求会穿透到DB,量大时可能会对数据库造成压力导致服务异常,可能的处理方案如下:

  1. 针对这些不存在的key,可以再redis中保存对应的key和空数据,并设置较短的过期时间;
  2. 或者使用Redis Bitmap 来判断数据是否存在已过滤无效请求

缓存雪崩:缓存同事失效或缓存服务异常,瞬时大量请求直接到达DB,对数据库造成压力导致服务异常,可能的处理方案如下:

  1. 保证缓存服务的高可用,采用集群,多主多从模式部署,并开启RDB和AOF备份,在Redis服务出现问题时能快速根据备份文件恢复缓存数据
  2. 缓存过期的时间设置随机化
  3. 调用缓存服务时增加熔断模块,类似于Hystrix.

基于Redis的分布式锁怎么实现?

setnx 和expire组合使用,有坑,可能有如下问题

	 1.会不会有B线程删除了A线成加的锁的情况
	 2.锁超时了怎么办

A:我们通过setNX命令来实现分布式锁,设置了过期时间,不至于会出现线程异常导致锁无法释放的情况

Q:那释放锁的时候怎么做?会不会有B线程删除了A线程加的锁的情况?

A:不会的,我们加锁的时候有为每个线程生成独立的uuid,存储到redis,解锁的时候是使用Lua脚本,判断了uuid一致才会让释放对应的锁。

Q:不错,那锁超时了怎么办呢?

A:我们可以考虑类似租约机制的实现,启动定时任务来给线程续期,延长加锁时间;还需要考虑实际情况。。

为啥Redis单线程模型也能效率这么高
Redis 基于Reactor模式开发了网络事件处理器,叫文件事件处理器(File EventHandler).文件事件处理器是单线程的,Redis才叫做单线程的模型,采用IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器处理事件,为啥快呢:

  1. 纯内存操作
  2. 核心是基于非阻塞的IO多路复用机制
  3. 单线程避免了多线程频繁上下文切换问题
  4. 内部数据结构设计,整个的结构都类似于一个map,查找效率贼高

Redis持久化方式及区别
Q: Redis出问题后数据会全部丢是吗?
A:不会,Redis有持久化机制,支持AOF和RDB两种持久化方式

Q:这两种持久化方式有什么区别,你们使用哪种形式,怎么配置的

A:
RDB:通过fork一个子进程保存当前内存的一个快照实现备份,适合大规模的数据恢复,数据的完整性和一致性不高,RDB可能在最后一次备份时宕机了。另外备份时会占用内存,因为Redis在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据时原来的两倍),最后再将临时文件替换之前的备份文件。
配置方式如下:

# save <指定时间间隔><执行制定次数更新操作>,满足条件就将内存中的数据同步到硬盘中
save<seconds><changes>
#指定本地数据库文件名,一般采用默认的dump.rdb
dbfilename dump.rdb
#默认开启数据压缩
rdbcompression yes

AOF : 通过每条写入命令以 append-only的模式写入一个日志文件中,在Redis重启的时候,可以通过回放AOF日志中的写入命令来重新构建整个数据集。AOF对数据的完整性和一致性支持更好,但是其备份日志文件一般会比RDB方式的备份文件更大,恢复也更慢,同时由于fsync的频率方式,会影响Redis的性能。

#打开aof
appendonly yes
#日志文件
appendfilename "appendonly.aof"
#更新条件
#appendfsync always
appendfsync everysec
#appendfsync no
#触发重写的配置
#时间长了日志会特别大,此时需要触发重写取内存中的数据,并重写到一个临时文件中。
#最后替换旧的aof文件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Redis如何实现分布式和高可用?

A:我们采用集群部署模式,三主三从,总共六台服务器

Q:那Redis主从模式,数据是怎么同步的呢?

A:
Redis主从模式原理:
Redis 2.8之前主从模式,主从之间的数据复制只有全复制机制,通过执行命令SLAVEOF ip port,使得其成为从服务器。全数据复制流程如下:

  1. 从服务器向主服务器发送SYNC命令。
  2. 主服务器收到SYNC命令之后,执行BGSAVE命令在后台生成RDB文件,并使用一个缓冲区记录从现在开始执行的写命令。
  3. 主服务器将生成的RDB文件发送给从服务器,从服务器根据RDB文件更新状态。
  4. 主服务器将缓冲区中的写命令发送给从服务器,从服务器执行这些命令,最终和主服务器达到一致的状态。

命令传播:
数据复制完成后,为了保持一致的状态,主服务的写命令都需要传播给其从服务器。

不足:
如果从服务器和主服务器断开后,又立马重新连接上,那么如果还执行全同步的话就十分浪费,因为全同步非常站cpu、io和带宽等

Redis 2.8之后,支持PSYNC,即部分重同步机制,部分同步机制主要依靠:

  1. 主从服务器的复制偏移量:用于记录主从服务器的状态是否一致,以及数据复制时的偏移量
  2. 主服务器的复制积压缓冲区:固定大小的(默认1M)FIFO队列,用于记录主服务器的写命令
  3. 主服务器的ID:用于判断,从服务器断开连接后重新连接到的主服务器是不是原来那个

部分重同步流程:

 1. 从服务器请求同步,带上当前的offset和之前的主服务器ID;
 2. 如果请求中的主服务ID和当前当前的主服务ID不一致,或者其offset值已经不再复制积压缓冲区内,那么需要执行全同步,流程同上;
 3. 否则,执行部分同步,主服务器将复制积压缓冲区中offset之后的命令发送给从服务器;
 4. 从服务器执行对应写命令,并修改offset,达到和主服务器状态一致。

Redis怎么删除过期数据?
A:Redis有定期删除和惰性删除两种

  1. 定期删除:默认是每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除
  2. 惰性删除:在你获取某个key的时候,Redis会检查一下,这个key如果设置了过期时间那么是否过期了,如果过期了此时就会删除,不会给你返回任何东西。

Q:那如果执行了上述的删除操作之后,Redis内存空间还是不足怎么办?

A:设置了过期时间的,到期后会被上述操作删除掉,如果此时内存还是不够的话,Redis会根据配置的策略来执行对应的操作,主要有noeviction、allkeys-lru、allkeys-random、volatile-lru、volatile-random、volatile-ttl这几种

  1. noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,很少用。
  2. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的,常用。
  3. allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,
  4. volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
  5. volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
  6. volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,优先移除更早过期时间的key
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值