分布式缓存相关面试题

1,349 阅读31分钟

在项目中缓存是如何使用的呢?缓存如果使用不当会造成什么后果?

面试官心里分析

这个问题,互联网公司必问,要是一个人连缓存都不清楚,那确实比较尴尬。

只要问到缓存,上来第一个问题就是先问问你项目中哪里用了缓存?为啥要用?不用行不行?如果用了之后可能会造成什么不良后果?

这就是看看你对你用缓存这个东西背后,有没有思考,如果你是傻乎乎的用,没法给面试官一个合理的解答,只怕是印象会很差,透漏出你是一个不爱思考的人

面试题剖析

一个一个来看

  1. 在项目中缓存是如何使用的?

结合自身的项目来回答,没啥好说的

  1. 为啥项目里要用缓存呢?

用缓存主要是高性能和高并发

先看图

image.png

高性能: 假设这么一个场景,你有个操作,一个请求过来了,吭哧吭哧你各种乱七八糟操作mysql,半天也没查出一个结果,耗时600ms,但是这个结果可能接下来几个小时都不会变,或者变了也可以不用立即反馈给用户。那么此时怎么办呢?

缓存啊,折腾出来600ms的结果,仍缓存里,一个key对应一个value,下次有人在查,别走mysql折腾600ms,直接从缓存里,通过一个key查出来一个value,2ms搞定(打比方,耗时不一定),性能提升300倍

这就是所谓的高性能

就是你把一些复杂操作耗时查出来的结果,如果确定后面不怎么变了,然后但是马上又很多请求去读取,直接放缓存里,从缓存里读取。

高并发: 假设这么一个场景,中午高峰期有100万用户同时访问系统,每秒有4000个请求去查询数据库,如果数据库每秒承受4000个请求,可能会宕机。但是你把一部分数据存放到redis,那么可能每秒3000请求走缓存,1000请求走数据库,系统可以承受。

为什么缓存可以支撑高并发?

因为缓存走的是内存,内存天然就可以支撑4000/s,4万/s请求也是没有问题的。但是数据库一般建议每秒不用超过2000个请求。

  1. 用了缓存会不会有什么不良的后果?
  • 缓存和数据库双写不一致
  • 缓存雪崩
  • 缓存击穿
  • 缓存并发竞争

redis和memcached有什么区别?redis的线程模型是什么?为什么单线程的redis比多线程的memcached效率还要高(为什么redis是单线程的但是还可以支撑高并发?)?

面试官心里分析

这个是问redis的时候最基本的问题吧,redis最基本的一个内部原理和特点,就是redis实际上是单线程工作模型,你要连这个都不知道,那后面玩redis的时候,出了问题岂不是手足无措?

还有面试官可能还会问问你memcached和redis的区别,不过说实话现在缓存基本用的是redis,主要考察你的技术广度。

面试题剖析

  • redis和memcached的区别

这个事你可以比较出N的区别,这里采取redis作者给出的几个区别吧

  1. redis支持服务器端的数据操作,redis相比memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在memcached里,你需要将数据拿到客户端来进行类似的修改在set回去。这大大增加了网络IO的次数和数据体积。在redis中,这些复杂的操作通常和一般的get、set一样高效,所以需要缓存能够支持更复杂的结构和操作,那么redis会是一个不错的选择
  2. 内存使用效率对比:使用简单的key-value存储的话,memcached的内存利用率高更高,而如果redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于memcached。
  3. 性能对比:由于redis只使用单核,而memcached可以使用多核,所以平均每一个核上redis在存储小数据时比memcached性能更高,而在100k以上的数据中,memcached性能要高于redis,虽然redis最近在存储大数据的性能上进行优化,但是比起memcached,还是稍有逊色。
  4. 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据,但是redis目前是原生支持cluster模式
  • redis的线程模型

具体可以查看这篇文章 了解redis的单线程模型工作原理?一篇文章就够了_程序员秋田君的博客-CSDN博客_redis 单线程原理

  • 为什么redis单线程模型也能效率这么高?
  1. 纯内存操作
  2. 核心是基于非阻塞的IO多路复用机制
  3. 单线程反而避免了多线程的频繁上下文切换问题

redis有哪些数据类型?在哪些场景下使用比较适合?

  • string 简单的k-v存储
  • hash 可以存储对象
  • list 可以拿来做分页
  • set 可以去重,可以玩交集、并集、差集啊,例如两个人的粉丝列表一交集,就可以看看共同好友啥的
  • sorted set 排序的set 可以做热搜啥的

redis的过期策略能介绍一下吗?要不你手写一个LRU?

面试官心里分析

之前有同学问过我,说我们生产环境的redis怎么经常丢失一些数据?写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明redis你就没用对过啊,redis是缓存,你给当储存了是吧?

啥叫缓存?用内存当缓存,内存是无限的吗?内存是很宝贵且有限的,磁盘是很廉价且大量的,redis主要是基于内存进行高性能、高并发的读写操作

所以说这是缓存的一个基本概念,数据是会过期的,要么你自己设置一个过期时间,要么是redis自己给干掉

还有你设置好了过期时间,你知道redis是怎么给你弄成过期的吗?什么时候删除掉?为啥好多数据明明应该过期了,结果发现redis内存占用还是很高?

面试题剖析

(1)设置过期时间

我们set key的时候,都可以给一个expire time,就是过期时间,指定这个key比如说只能存活一个小时?十分钟?这个很有用,我们自己指定缓存到期就失效

如果假设你设置一个key的过期时间为1小时,那么接下来1小时后,redis是怎么对这个key进行删除的?

答案是:定期删除+惰性删除

所谓定期删除,指的是redis默认每隔100ms就随机抽取一些设置了过期时间的key,检测是否过期,如果过期了就删除。注意这里可不是每隔100ms就遍历所有的设置过期时间的key,那样就是一场性能上的灾难。实际上redis是每隔100ms随机抽取一些key来检测和删除的

但是问题是,定期删除可能会导致很多过期的key到了时间并没有删除掉。那咋整呢?所有就是惰性删除了,这就是说,在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你fanh

通过上述两种手段结合起来,保证过期的key一定会被干掉

很简单就是说,你的过期key,靠定期删除没有删除完,还有一部分停留在内存里,占用着你的内存,除非你的系统查一下这个key,才会被redis给删除掉

但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存耗尽了,咋整?

答案是:走内存淘汰机制

(2)内存淘汰

如果redis的内存占用过多的时候,此时就会进行内存淘汰,有如下一些策略:

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,一般没人用,为啥要随机,肯定是把最近最少使用的key给干掉啊
  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key(一般不太合适)
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

怎么保证redis的高并发、高可用、持久化?redis的主从复制原理能介绍一下吗?redis的哨兵原理能介绍一下吗?

面试官心里分析

其实问这个问题,主要是考考你,redis单机能承载多少高并发?如果单机扛不住如何扩容抗住更多的并发?redis会不会挂?既然redis会挂怎么保证redis的高可用?

其实针对的都是项目中你肯定要考虑的问题,如果你没考虑过,那确实你对生产系统中的问题思考的太少了

面试题剖析

就是如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,高可用的。

redis高并发跟整个系统的高并发之间的关系

redis你要搞高并发的话,不可避免,要把底层的缓存搞得很好
mysql高并发的话,通过一系列复杂的分库分表可以做到
光是redis是不够的,但是redis是整个大型的缓存架构中,支撑高并发的架构里,非常重要的一个环节

redis不能支撑高并发的瓶颈在哪里?

单机

如果redis要支撑超过10万+的并发,要应该怎么做

单机的redis几乎不太可能,除非你的机器性能特别好、配置特别高、物理机,维护也做的很好,整体操作也不是太复杂,单机一般在几万

读写分离,一般来说,对缓存而言一般是支持读高并发的,写的请求很少

主从架构->读写分离->支撑10万+读qps

redis replication的核心机制

先看一下主从简单的架构图

image.png

  1. redis采用异步方式复制数据到多个slave节点,不过redis2.8开始,slave node会周期性地确认自己每次复制的数据量
  2. 一个master node是可以配置多个slave node的
  3. slave node也可以连接其他的slave node
  4. slave node做复制的时候,是不会block master node的正常工作的
  5. slave node在做复制的时候,也不会block对自己的查询操作,他会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧的数据集,加载新的数据集,这个时候就暂停对外服务了
  6. slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量

master持久化对于主从架构的安全保障的意义

  1. 如果采用主从架构,那么建议必须开启master node的持久化
  2. 不建议用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能master宕机重启的时候数据是空的,然后可能一经过复制,slave node的数据也丢了
  3. 即使采用哨兵机制,slave node可以自动接管master node,但是也可能sentinel还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障

redis主从复制原理、断点续传、无磁盘化复制、过期key处理

先看一下草图

image.png

主从架构的核心原理

  1. 当启动一个slave node的时候,它会发送一个PSYNC命令给master node
  2. 如果这时slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node第一次连接master node,那么会触发一次full resynchronization
  3. 开始full resynchronization的时候,master会启动一个后台线程,开始生产一份RDB快照,同时还会将从客户端收到的所有写命令缓存到内存中,RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后从本地磁盘加载到内存中,然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据
  4. slave node如果跟master node有网络故障,断开了连接,会自动重连,master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb slave操作,用一份数据服务所有的slave node。

主从复制的断点续传

  • 从redis2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断开了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
  • master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的,如果master和slave网络连接断开了,slave会让master从上次的replica offset开始继续复制
  • 但是如果没有找到对应的offset,那么就会执行一次resynchronization

无磁盘化复制

master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘

repl-diskless-sync

repl-diskless-sync-delay 等待一定时长在开始复制,因为要等更多slave重新连接过来

过期key处理

slave不会过期key,只会等待master过期key,如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave

redis replication的完整流运行程和原理的再次深入剖析

完整流运行程图如下:

image.png

数据同步相关的核心机制

指的就是第一次slave连接master的时候,执行的全量复制

(1)master和slave都会维护一个offset

master会在自身不断累加offset,slave也会在自身不断累加offset

slave每秒都会上报自己的offset和master,同时master也会保存每个slave的offset

这倒不是说特定用在全量复制的,主要是master和slave都有知道各自数据的offset,才能知道互相之间的数据不一致的情况

(2)backlog

master node有一个backlog,默认是1MB大小

master node给slave node复制数据时,也会将数据再backlog中同步写一份

backlog主要是用来做全量复制中断后的增量复制的

(3)master run id

info server,可以看到master run id

如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制

如果需要不更改run id重启redis,可以使用redis-cli debug reload命令

image.png

(4)psync

从节点使用psync从master node进行复制,psync runid offset

master node会根据自身的情况返回响应信息,可能是fullresync runid offset触发全量复制,可能是CONTINUE触发增量复制

全量复制

image.png

增量复制

image.png

heartbeat

image.png

异步复制

image.png

redis主从架构下如何才能做到99.99%的高可用性?

系统处于不可用是什么意思?

image.png

系统高可用是什么意思?

image.png

redis哨兵架构的相关基础知识的讲解

image.png

image.png

image.png

image.png

redis哨兵主备切换的数据丢失问题:异步复制、集群脑裂

image.png

image.png

异步复制导致数据丢失如何降低损失

image.png

image.png

redis哨兵的多个核心底层原理的深入解析(包含slave选举算法)

image.png

image.png

image.png

image.png

image.png

image.png

image.png

怎么保证redis挂掉之后在重启数据可以进行恢复?

面试题

redis的持久化有哪几种方式?不同的持久化机制有什么优缺点?持久化机制具体底层是如何实现的?

面试官心里分析

redis如果仅仅只是将数据缓存到内存里面,如果redis宕机了,在重启,内存里的数据就全部都丢失了啊.....你必须的用redis的持久化机制,将数据写入内存的同时,异步的慢慢的将数据写入磁盘文件里,进行持久化 如果reids宕机了,重启,自动从磁盘文件加载之前持久化的一些数据就可以,也许会丢失少许数据,但至少不会将所有的数据都丢失

面试题剖析

redis持久化的意义请看下图

image.png

redis持久化机对于生产环境中的灾难恢复的意义

数据备份,在于发生故障了,大部分数据得以恢复

redis的RDB和AOF两种持久化机制的介绍

RDB和AOF的介绍 请看下图:

image.png

AOF rewrite剖析 请看下图:

image.png

  1. RDB持久化机制,对redis中的数据执行周期性的持久化
  2. AOF机制对每条写命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写指令来重新构建整个数据集
  3. 如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制
  4. 通过RDB和AOF都可以将数据持久化到磁盘中,然后将这些数据备份到其他地方去,如阿里云的服务器如果redis挂了,服务器上内存和磁盘的数据都丢失了,可以从别的地方备份回来,使得系统可以继续对外提供服务
  5. 如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整

redis的RDB和AOF两种持久化机制的优劣势对比

RDB持久化机制的优点

(1)RDB会生成多个数据文件,每个数据文件都代表了某一时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如云服务上

RDB可以做冷备,生成多个文件,每个文件都代表了某一时刻的完整的数据快照

AOF也可以做冷备,只有一个文件,但是你可以,每隔一定时间,去copy一份这个文件出来

RDB做冷备优势在哪?由redis去控制固定时长生成快照文件的事情,比较方便;AOF还需要自己写一些脚本去做这个事情,各种定时,提供恢复数据的时候,速度比AOF块

(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可

RDB 每次写都是直接写redis内存,只是在一定的时候才会将数据写入磁盘中

AOF每次都是要写文件的,虽然可以快速写入os cache,但是还是有一定的时间开销的,速度肯定比RDB略慢一些

(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速

AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,来恢复出来内存中的所有数据

RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可

RDB持久化机制的缺点

(1)如果想要在redis故障时,尽可能的少的丢失数据,那么RDB没有AOF好,一般来说,RDB数据快照文件,都是每隔5秒,或者更长时间生成一次。这个时候就得接受一旦redis宕机,那么会丢失最近5分钟的数据

这个问题也是RDB最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多

(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供服务暂停数毫秒,甚至数秒

一般不要让RDB的时间间隔太长,否则每次生成的RDB文件太大,对redis本身的性能可能会有影响

AOF持久化机制的优点

  1. AOF可以更好的保护数据不丢失,一般AOF会每隔一秒,通过一个后台线程执行一次fsync操作,保证os cache中的数据写入磁盘中,最多丢失1秒钟的数据
  2. AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易损坏,即使文件尾部破损,也很容易修复
  3. AOF日志文件即使过大的时候,出现后台重写的操作,也不会影响客户端的读写,因为rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来,在创建新日志文件的时候,老的日志文件还是照常写入,当新的merge后的日志文件ready的时候,再交换新老日志文件即可
  4. AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复,比如某人不小心用flush all命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flush all命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

AOF持久化机制的缺点

  1. 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
  2. AOF开启后,支持写的qps回避RDB的低,因为AOF一般会配置成每秒fsync一次日志文件,当然每秒一次fsync,性能也还是很高的
  3. 以前AOF发生过BUG,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来,所以说,类似AOF这种较为复杂的基于命令的日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug,不过aof就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多
  4. 唯一比较大的缺点,其实就是做数据恢复的时候,会比较慢,还有做冷备,定期备份不太方便

RDB和AOF该如何选择

  1. 不要仅仅使用RDB,这样会导致你丢失很多数据
  2. 也不要仅仅使用AOF,因为那样有两个问题,第一,你通过aof做冷备,没有RDB做冷备来的恢复速度快;
  3. 第二RDB每次简单粗暴生成数据快照,更加健壮,可以避免aof这种复杂的备份和恢复机制的bug
  4. 综合使用RDB和AOF两种持久化机制

redis集群模式的工作原理能说一下吗?在集群模式下,redis的key是如何寻址的?分布式的寻址都有哪些算法?了解一致性hash算法吗?

面试官心理分析

早些年,如果redis要搞几个节点,每个节点存储一部分的数据,要借助一些中间件来实现,比如说有codis,或者twemproxy。有一些redis中间件,你读写redis中间件,中间件负责将你的数据分布式存储在多台机器上的redis实例中。

现在redis不断在发展,现在大家都用原生的redis cluster,redis集群模式,你可以做到在多台机器上,部署多个redis实例,每个实例存储一部分的数据,同时每个redis实例挂载一个从节点,确保说,主节点挂了,可以切换到从节点。

面试题剖析

redis的集群架构

redis cluster
支撑N个redis master node,每个master node都可以挂载多个slave node
读写分离的架构,对于每个master来说,写就写到master,然后读就从master对应得slave去读
高可用,因为每个master都有slave节点,那么如果master挂掉,redis cluster这套机制,就会自动将某个slave切换成master
redis cluster(多master + 读写分离 + 高可用)
我们只要基于redis cluster去搭建redis集群即可,不需要手工去搭建replication复制+主从架构+读写分离+哨兵集群+高可用

redis cluster vs replication + sentinel

如果你得数据量很少,主要是承载高并发高性能得场景,比如你的缓存一般就几个G,单机足够了
replication,一个master,多个slave,要几个slave跟你得要求的读吞吐量有关系,然后自己搭建一个sentinel集群,去保证redis主从架构的高可用性,就可以了
redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluter

数据分布算法:hash+一致性hash+redis cluster的hash slot

最老土的hash算法以及弊端:

image.png

一致性hash算法(自动缓存迁移)+虚拟节点(自动负载均衡)

image.png

image.png

redis cluster的hash slot算法

image.png

image.png

redis cluster的核心原理分析:gossip通信、jedis smart定位、主备切换

集中式的集群元数据存储和维护:

image.png

gossip协议维护集群元数据:

image.png

一:节点间的内部通信机制

1.基础通信原理

(1)redis cluster节点间采取gossip协议进行通信

跟集中式不同,不是将集群元数据(节点信息,故障,等等)集中存储在某个节点上,而是互相之间不断通信,保持

整个集群所有节点的数据是完整的

维护集群的元数据用得,集中式,一种叫做gossip

集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储,其它节点读取的时候立即就可以感知到

不好在于,所有的元数据的更新压力会全部集中在一个地方,可能导致元数据的存储有压力

gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力

缺点:元数据更新有延时,可能导致集群的一些操作会有一些滞后

(2)10000端口

每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口

每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping之后返回pong

(3)交换的信息

故障信息,节点的增加和移除,hash solt信息等等

2、gossip协议

image.png

ping消息深入

image.png

二、面向集群的jedis内部实现原理

1.基于从定向的客户端

image.png

2.smart jedis

image.png

三、高可用性和主备切换原理

image.png

你能说说我们一般如何应对缓存雪崩和缓存击穿吗?

了解什么是redis的雪崩和穿透?redis崩溃了之后会怎么样?系统该如何应对这种情况?如何处理redis的穿透?

面试官心里分析

其实这是问到缓存必问的,因为缓存雪崩和穿透,那是缓存最大的两个问题,要么不出现,一旦出现就是致命性的问题,所以面试官一定会问你。

面试题剖析

缓存雪崩发送的现象:

image.png

缓存雪崩的事前事中事后的解决方案

事前:redis高可用,避免全盘崩溃

事中:本地ehcache缓存+hystrix限流&降级,避免redis被打死

事后:redis持久化,快速恢复缓存数据

image.png

缓存穿透的现象和解决方法:

image.png

如何保证缓存与数据库双写时的数据一致性?

Cache Aside Pattern缓存+数据库读写模式的分析

最经典的缓存+数据库读写模式:cache aside pattern

1、cache aside pattern

读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存

更新的时候,先删除缓存,更新数据库

2、为什么是删除缓存,而不是更新缓存

原因很简单,因为缓存有的时候,不简单是数据库中直接取出来的值

比如可能更新了某个表的一个字段,然后其对应的缓存,是需要查询另外两个表的数据,并进行运算,才能计算出缓存最新的值的

更新缓存的代价是很高的

如果你频繁修改一个缓存涉及的多个表,那么这个缓存会被频繁的更新

但是问题在于,这个缓存到底会不会被频繁的访问到?

举个例子,一个缓存涉及的表的字段,在1分钟内就修改了20次,那么缓存更新了20次,但是这个缓存1分钟内就被读取了1次

实际上,如果你只是删除缓存的话,那么1分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低

其实删除缓存,而不是更新缓存,就是一个lazy计算的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它需要被使用的时候重新计算

高并发场景下的缓存+数据库双写不一致问题分析与解决方案设计

比如说实时性要求比较高的那块数据的缓存:库存服务

库存可能会修改,每次修改都要去更新这个缓存数据,每次库存的数据,在缓存中一旦过期,或者被清理掉了,前端的nginx服务都会发送请求给库存服务,去获取对应的数据

库存这一块,写数据库的时候,直接更新redis缓存

实际上没那么简单,这里其实就涉及到了一个问题,数据库和缓存双写,数据不一致的问题

1、最初级的缓存不一致问题及解决方案

问题:先修改数据库,在删除缓存,如果缓存删除失败了,那么会导致数据库中是新数据,缓存是旧数据,数据出现不一致

解决思路:先删除缓存,在修改数据库,如果修改数据失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不一致,因为读的时候缓存没有,则读数据库的旧数据,然后更新到缓存中

2、比较复杂的数据不一致问题分析

数据发生变更,先删除了缓存,然后要去修改数据库,此时还没修改

一个请求过来,先读缓存,发现缓存空了,去查询数据库,查到了修改旧的数据,放到了缓存中

数据变更的程序完成了数据库的修改

完了,数据库和缓存中的数据不一样了.........

3、为什么上亿流量高并发场景下,缓存会出现这个问题?

只有在对一个数据进行并发的读写的时候,才可能出现这个问题

其实如果说你的并发量很低的话,特别是读并发很低,每天访问量就1万次,那么很少的情况下,会出现刚才描述的那种不一致的场景

但是问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只要有数据更新的请求,就可能出现上述的数据库+缓存不一致的情况

高并发了以后,问题还是很多的

4、数据库于缓存更新进行异步串行化

image.png

image.png

5、 高并发场景下,该解决方案需要注意的问题

image.png

image.png

你能说说redis的并发竞争问题该如何解决吗?

面试题

redis的并发竞争问题是什么?如何解决这个问题?了解Redis事务的CAS方案吗?

面试官心里分析

这个也是线上非常常见的一个问题,就是多客户端同时并发写一个key,可能本应该先到的数据后到了,导致数据版本错了,或者就是多客户端同时获取一个key,修改之后再写回去,只要顺序错了,数据就错了

而且redis自己就有天然解决这个问题的CAS类的乐观锁方案

面试题剖析

image.png

image.png

你们公司生产环境的redis集群的部署架构是什么样的?

面试题

生产环境中的redis是怎么部署的?

面试官心里分析

看看你聊不了解你们公司的redis生产集群的部署架构,如果你不了解,那么确实你就很失职了,你的redis是主从架构吗?集群架构?用了哪种集群方案?有没有做高可用保证?有没有开启持久化机制确保可以进行数据恢复?redis线上给了几个G的内存?设置了哪些参数?压测后你们redis集群承载多少QPS?

面试题剖析

redis cluster,10台机器,5台机器部署了redis主实例,另外5台机器部署了redis的从实例,每个主实例挂了一个从实例,5个节点对外提供读写服务,每个节点的读写高峰qps可能达到每秒5万。5台机器最多是25万读写请求/s.

机器是32G内存+8核CPU,但是分配给redis进程的是10G内存,一般线上生产环境,redis的内存尽量不要超过10G,超过10G可能会有问题

因为每个主实例挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis从实例会自动变成主实例继续提供读写服务

你往内存写的是什么数据?每条数据的大小是多少?商品数据,每条数据是10kb,100条数据就是1mb,10万条数据是1G,常驻内存的是200万条商品数据,占用内存20给,仅仅不到总内存的50%。