在项目中缓存是如何使用的呢?缓存如果使用不当会造成什么后果?
面试官心里分析
这个问题,互联网公司必问,要是一个人连缓存都不清楚,那确实比较尴尬。
只要问到缓存,上来第一个问题就是先问问你项目中哪里用了缓存?为啥要用?不用行不行?如果用了之后可能会造成什么不良后果?
这就是看看你对你用缓存这个东西背后,有没有思考,如果你是傻乎乎的用,没法给面试官一个合理的解答,只怕是印象会很差,透漏出你是一个不爱思考的人
面试题剖析
一个一个来看
- 在项目中缓存是如何使用的?
结合自身的项目来回答,没啥好说的
- 为啥项目里要用缓存呢?
用缓存主要是高性能和高并发
先看图
高性能: 假设这么一个场景,你有个操作,一个请求过来了,吭哧吭哧你各种乱七八糟操作mysql,半天也没查出一个结果,耗时600ms,但是这个结果可能接下来几个小时都不会变,或者变了也可以不用立即反馈给用户。那么此时怎么办呢?
缓存啊,折腾出来600ms的结果,仍缓存里,一个key对应一个value,下次有人在查,别走mysql折腾600ms,直接从缓存里,通过一个key查出来一个value,2ms搞定(打比方,耗时不一定),性能提升300倍
这就是所谓的高性能
就是你把一些复杂操作耗时查出来的结果,如果确定后面不怎么变了,然后但是马上又很多请求去读取,直接放缓存里,从缓存里读取。
高并发: 假设这么一个场景,中午高峰期有100万用户同时访问系统,每秒有4000个请求去查询数据库,如果数据库每秒承受4000个请求,可能会宕机。但是你把一部分数据存放到redis,那么可能每秒3000请求走缓存,1000请求走数据库,系统可以承受。
为什么缓存可以支撑高并发?
因为缓存走的是内存,内存天然就可以支撑4000/s,4万/s请求也是没有问题的。但是数据库一般建议每秒不用超过2000个请求。
- 用了缓存会不会有什么不良的后果?
- 缓存和数据库双写不一致
- 缓存雪崩
- 缓存击穿
- 缓存并发竞争
redis和memcached有什么区别?redis的线程模型是什么?为什么单线程的redis比多线程的memcached效率还要高(为什么redis是单线程的但是还可以支撑高并发?)?
面试官心里分析
这个是问redis的时候最基本的问题吧,redis最基本的一个内部原理和特点,就是redis实际上是单线程工作模型,你要连这个都不知道,那后面玩redis的时候,出了问题岂不是手足无措?
还有面试官可能还会问问你memcached和redis的区别,不过说实话现在缓存基本用的是redis,主要考察你的技术广度。
面试题剖析
- redis和memcached的区别
这个事你可以比较出N的区别,这里采取redis作者给出的几个区别吧
- redis支持服务器端的数据操作,redis相比memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在memcached里,你需要将数据拿到客户端来进行类似的修改在set回去。这大大增加了网络IO的次数和数据体积。在redis中,这些复杂的操作通常和一般的get、set一样高效,所以需要缓存能够支持更复杂的结构和操作,那么redis会是一个不错的选择
- 内存使用效率对比:使用简单的key-value存储的话,memcached的内存利用率高更高,而如果redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于memcached。
- 性能对比:由于redis只使用单核,而memcached可以使用多核,所以平均每一个核上redis在存储小数据时比memcached性能更高,而在100k以上的数据中,memcached性能要高于redis,虽然redis最近在存储大数据的性能上进行优化,但是比起memcached,还是稍有逊色。
- 集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据,但是redis目前是原生支持cluster模式
- redis的线程模型
具体可以查看这篇文章 了解redis的单线程模型工作原理?一篇文章就够了_程序员秋田君的博客-CSDN博客_redis 单线程原理
- 为什么redis单线程模型也能效率这么高?
- 纯内存操作
- 核心是基于非阻塞的IO多路复用机制
- 单线程反而避免了多线程的频繁上下文切换问题
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的核心机制
先看一下主从简单的架构图
、
- redis采用异步方式复制数据到多个slave节点,不过redis2.8开始,slave node会周期性地确认自己每次复制的数据量
- 一个master node是可以配置多个slave node的
- slave node也可以连接其他的slave node
- slave node做复制的时候,是不会block master node的正常工作的
- slave node在做复制的时候,也不会block对自己的查询操作,他会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧的数据集,加载新的数据集,这个时候就暂停对外服务了
- slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量
master持久化对于主从架构的安全保障的意义
- 如果采用主从架构,那么建议必须开启master node的持久化
- 不建议用slave node作为master node的数据热备,因为那样的话,如果你关掉master的持久化,可能master宕机重启的时候数据是空的,然后可能一经过复制,slave node的数据也丢了
- 即使采用哨兵机制,slave node可以自动接管master node,但是也可能sentinel还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障
redis主从复制原理、断点续传、无磁盘化复制、过期key处理
先看一下草图
主从架构的核心原理
- 当启动一个slave node的时候,它会发送一个PSYNC命令给master node
- 如果这时slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node第一次连接master node,那么会触发一次full resynchronization
- 开始full resynchronization的时候,master会启动一个后台线程,开始生产一份RDB快照,同时还会将从客户端收到的所有写命令缓存到内存中,RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后从本地磁盘加载到内存中,然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据
- 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的完整流运行程和原理的再次深入剖析
完整流运行程图如下:
数据同步相关的核心机制
指的就是第一次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命令
(4)psync
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是fullresync runid offset触发全量复制,可能是CONTINUE触发增量复制
全量复制
增量复制
heartbeat
异步复制
redis主从架构下如何才能做到99.99%的高可用性?
系统处于不可用是什么意思?
系统高可用是什么意思?
redis哨兵架构的相关基础知识的讲解
redis哨兵主备切换的数据丢失问题:异步复制、集群脑裂
异步复制导致数据丢失如何降低损失
redis哨兵的多个核心底层原理的深入解析(包含slave选举算法)
怎么保证redis挂掉之后在重启数据可以进行恢复?
面试题
redis的持久化有哪几种方式?不同的持久化机制有什么优缺点?持久化机制具体底层是如何实现的?
面试官心里分析
redis如果仅仅只是将数据缓存到内存里面,如果redis宕机了,在重启,内存里的数据就全部都丢失了啊.....你必须的用redis的持久化机制,将数据写入内存的同时,异步的慢慢的将数据写入磁盘文件里,进行持久化 如果reids宕机了,重启,自动从磁盘文件加载之前持久化的一些数据就可以,也许会丢失少许数据,但至少不会将所有的数据都丢失
面试题剖析
redis持久化的意义请看下图
redis持久化机对于生产环境中的灾难恢复的意义
数据备份,在于发生故障了,大部分数据得以恢复
redis的RDB和AOF两种持久化机制的介绍
RDB和AOF的介绍 请看下图:
AOF rewrite剖析 请看下图:
- RDB持久化机制,对redis中的数据执行周期性的持久化
- AOF机制对每条写命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写指令来重新构建整个数据集
- 如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制
- 通过RDB和AOF都可以将数据持久化到磁盘中,然后将这些数据备份到其他地方去,如阿里云的服务器如果redis挂了,服务器上内存和磁盘的数据都丢失了,可以从别的地方备份回来,使得系统可以继续对外提供服务
- 如果同时使用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持久化机制的优点
- AOF可以更好的保护数据不丢失,一般AOF会每隔一秒,通过一个后台线程执行一次fsync操作,保证os cache中的数据写入磁盘中,最多丢失1秒钟的数据
- AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易损坏,即使文件尾部破损,也很容易修复
- AOF日志文件即使过大的时候,出现后台重写的操作,也不会影响客户端的读写,因为rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来,在创建新日志文件的时候,老的日志文件还是照常写入,当新的merge后的日志文件ready的时候,再交换新老日志文件即可
- AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复,比如某人不小心用flush all命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flush all命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
AOF持久化机制的缺点
- 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
- AOF开启后,支持写的qps回避RDB的低,因为AOF一般会配置成每秒fsync一次日志文件,当然每秒一次fsync,性能也还是很高的
- 以前AOF发生过BUG,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来,所以说,类似AOF这种较为复杂的基于命令的日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug,不过aof就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多
- 唯一比较大的缺点,其实就是做数据恢复的时候,会比较慢,还有做冷备,定期备份不太方便
RDB和AOF该如何选择
- 不要仅仅使用RDB,这样会导致你丢失很多数据
- 也不要仅仅使用AOF,因为那样有两个问题,第一,你通过aof做冷备,没有RDB做冷备来的恢复速度快;
- 第二RDB每次简单粗暴生成数据快照,更加健壮,可以避免aof这种复杂的备份和恢复机制的bug
- 综合使用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算法以及弊端:
一致性hash算法(自动缓存迁移)+虚拟节点(自动负载均衡)
redis cluster的hash slot算法
redis cluster的核心原理分析:gossip通信、jedis smart定位、主备切换
集中式的集群元数据存储和维护:
gossip协议维护集群元数据:
一:节点间的内部通信机制
1.基础通信原理
(1)redis cluster节点间采取gossip协议进行通信
跟集中式不同,不是将集群元数据(节点信息,故障,等等)集中存储在某个节点上,而是互相之间不断通信,保持
整个集群所有节点的数据是完整的
维护集群的元数据用得,集中式,一种叫做gossip
集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储,其它节点读取的时候立即就可以感知到
不好在于,所有的元数据的更新压力会全部集中在一个地方,可能导致元数据的存储有压力
gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力
缺点:元数据更新有延时,可能导致集群的一些操作会有一些滞后
(2)10000端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口
每个节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping之后返回pong
(3)交换的信息
故障信息,节点的增加和移除,hash solt信息等等
2、gossip协议
ping消息深入
二、面向集群的jedis内部实现原理
1.基于从定向的客户端
2.smart jedis
三、高可用性和主备切换原理
你能说说我们一般如何应对缓存雪崩和缓存击穿吗?
了解什么是redis的雪崩和穿透?redis崩溃了之后会怎么样?系统该如何应对这种情况?如何处理redis的穿透?
面试官心里分析
其实这是问到缓存必问的,因为缓存雪崩和穿透,那是缓存最大的两个问题,要么不出现,一旦出现就是致命性的问题,所以面试官一定会问你。
面试题剖析
缓存雪崩发送的现象:
缓存雪崩的事前事中事后的解决方案
事前:redis高可用,避免全盘崩溃
事中:本地ehcache缓存+hystrix限流&降级,避免redis被打死
事后:redis持久化,快速恢复缓存数据
缓存穿透的现象和解决方法:
如何保证缓存与数据库双写时的数据一致性?
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、数据库于缓存更新进行异步串行化
5、 高并发场景下,该解决方案需要注意的问题
你能说说redis的并发竞争问题该如何解决吗?
面试题
redis的并发竞争问题是什么?如何解决这个问题?了解Redis事务的CAS方案吗?
面试官心里分析
这个也是线上非常常见的一个问题,就是多客户端同时并发写一个key,可能本应该先到的数据后到了,导致数据版本错了,或者就是多客户端同时获取一个key,修改之后再写回去,只要顺序错了,数据就错了
而且redis自己就有天然解决这个问题的CAS类的乐观锁方案
面试题剖析
你们公司生产环境的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%。