面试题: 这些问题是互联网公司必问问题,要是一个人连缓存都不太清楚,那确实比较尴尬。只要问到缓存,上来第一个问题,肯定是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用了以后可能会有什么不良的后果?这就是看看你对缓存这个东西背后有没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答,那面试官对你印象肯定不太好,觉得你平时思考太少,就知道干活儿。 为什么要用缓存:高性能、高并发 场景一:前端发一个请求,在你一顿操作后,半天才从数据库查询出数据,耗时6000ms,但是这个结果在接下来的几个小时内都不会改变数值,或者变了也不会需要立即反馈给用户,那么咋办?当然是选择缓存,把花费6000ms查出来的数据丢缓存中,下次在去查的时候,直接从缓存中缓存,2ms搞定,性能提高3000倍。 ==》就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好。 场景二:mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql 单机支撑到 所以要是你有个系统,高峰期一秒钟过来的请求有 1万,那一个 mysql 单机绝对会死掉。你这个时候就只能上缓存,把很多数据放缓存,别放 mysql。缓存功能简单,说白了就是 ==》缓存是走内存的,内存天然就支撑高并发。 用了缓存之后会有什么不良后果? 常见的缓存问题有以下几个: 面试题: 如何保证缓存和数据库的双写一致性? 现在保证双写一致的问题最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。 更新的时候(两种策略,在并发的情况下,根据场景和代价进行选择) 为什么是删除缓存,而不是更新缓存? 场景:举个栗子,一个缓存涉及的表的字段,在 1 分钟内就修改了 20 次,或者是 100 次,那么缓存更新 20 次、100 次;但是这个缓存在 1 分钟内只被读取了 1 次,有大量的冷数据。实际上,如果你只是删除缓存的话,那么在 1 分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低。用到缓存才去算缓存。 (lazy加载思想,细品) 两种更新策略在特殊场景下都会产生不一致的问题:但是我们需要去分析不一致后对生产的影响 先更新数据库,然后再删除缓存 场景:大量并发请发,同时包含读和写操作,首先一个读操作,没有正确读取到缓存的数据,从而去数据库读取,同时一个写操作,写完数据后,让缓存失效,然后之前的读操作将旧数据写入缓存中,造成脏数据。 该情况出现的概率非常低,首先这个条件发生是需要读缓存的时候,缓存失效,而且并发一个写的操作,而实际数据库的写操作比读操作慢的多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。 所以此策略的代价小 先删除缓存,在更新数据库 场景:两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。 产生脏数据的概览较大 对于高并发下,如何保证双写一致性的更多内容可以看这篇文件。 https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-consistence.md 什么是缓存雪崩? 简介:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。 场景:对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了。此时,如果没有采用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。 有哪些解决办法? 用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 Redis。如果 ehcache 和 Redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 Redis 中。 对高频请求,做准对性的限流处理,甚至可以使用sentinel的hotkey热点规则,对某一热点进行限流处理,熔断降级,限流,返回友好提示。 好处: 什么是缓存穿透? 缓存穿透说简单点就是大量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层。举个例子:某个黑客故意制造我们缓存中不存在的 key 发起大量请求,导致大量请求落到数据库。 场景:对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是黑客发出的恶意攻击。黑客发出的那 4000 个攻击,缓存中查不到,每次你去数据库里查,也查不到。比如数据库 id 是从 1 开始的,结果黑客发过来的请求 id 全部都是负数。这样的话,缓存中不会有,请求每次都“视缓存于无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。 有哪些解决办法? 最基本的就是首先做好参数校验,一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id 不能小于 0、传入的邮箱格式不对的时候直接返回错误消息给客户端等等。 1)缓存无效 key : 如果缓存和数据库都查不到某个 key 的数据就写一个到 redis 中去并设置过期时间,具体命令如下: **2)布隆过滤器:**布隆过滤器是一个非常神奇的数据结构,通过它我们可以非常方便地判断一个给定数据是否存在于海量数据中。我们需要的就是判断 key 是否合法,有没有感觉布隆过滤器就是我们想要找的那个“人”。具体是这样做的:把所有可能存在的请求的值都存放在布隆过滤器中,当用户请求过来,我会先判断用户发来的请求的值是否存在于布隆过滤器中。不存在的话,直接返回请求参数错误信息给客户端,存在的话才会走下面的流程。 布隆过滤器将我们给定的值通过多次hash计算,存入位数组中。hash碰撞是不可避免的,因此,布隆过滤器说某个key值存在是,这个值可能不存在,存在误判。但是如果说这个值不存在时,那就一定不存在。所以我们可以用这个特性来解决缓存穿透问题。 更多关于布隆过滤器的内容可以看我的这篇原创:《不了解布隆过滤器?一文给你整的明明白白!》 ,强烈推荐。 什么是缓存击穿? 缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。 不同场景下的解决方式可如下: 面试题: Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗? 这个也是线上非常常见的一个问题,就是多客户端同时并发写一个 key,可能本来应该先到的数据后到了,导致数据版本错了;或者是多客户端同时获取一个 key,修改值之后再写回去,只要顺序错了,数据就错了。 而且 Redis 自己就有天然解决这个问题的 CAS 类的乐观锁方案。 解决方案: 第一种方案:分布式锁+时间戳 这种情况准备一个分布式锁(redis分布式锁或者zookeeper分布式锁:用一个状态值表示锁,对锁的占用和释放通过状态值来标识),通过进行加锁,实现把并行读写改成串行读写,从而避免资源竞争。 如果需要顺序执行,我们就需要带上时间,当操作获取到锁的时候,同时获取缓存中的时间,如果发现自己的时间戳早于缓存中的时间戳,那么就不做set操作。 第二种方案:消息队列 在高并发的情况下,结合消息队列,也是实现从并行到串行的转变,把Redis.set操作放在队列中使其串行化,必须的一个一个执行,从而解决并发竞争问题。这种方式在一些高并发的场景中算是一种通用的解决方案。 区别 Redis的线程模型 Redis 内部使用文件事件处理器 为啥 Redis 单线程模型也能效率这么高? Redis 过期策略是:定期删除+惰性删除。 所谓定期删除,指的是 Redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。 假设 Redis 里放了 10w 个 key,都设置了过期时间,你每隔几百毫秒,就检查 10w 个 key,那 Redis 基本上就死了,cpu 负载会很高的,消耗在你的检查过期 key 上了。注意,这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的灾难。 但是问题是,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个 key 的时候,Redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。 获取 key 的时候,如果此时 key 已经过期,就删除,不会返回任何东西。 但是实际上这还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 Redis 内存块耗尽了,咋整? 答案是:走内存淘汰机制。 内存淘汰机制 (MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?) Redis 内存淘汰机制有以下几个: 4.0 版本后增加以下两种: 面试题: 其实问这个问题,主要是考考你,redis 单机能承载多高并发?如果单机扛不住如何扩容扛更多的并发?redis 会不会挂?既然 redis 会挂那怎么保证 redis 是高可用的? 如果你用 redis 缓存技术的话,肯定要考虑如何用 redis 来加多台机器,保证 redis 是高并发的,还有就是如何让 redis 保证自己不是挂掉以后就直接死掉了,即 redis 高可用。 高并发: 主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支撑读高并发。 下面的文章很好的讲诉了redis主从架构,以及主从的核心原理 https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-master-slave.md 高可用: Redis 的高可用架构,叫做 master node 在故障时,自动检测,并且将某个 slave node 自动切换为 master node 的过程,叫做主备切换。这个过程,实现了 Redis 的主从架构下的高可用。 Redis 哨兵集群实现高可用 哨兵的介绍 sentinel,中文名是哨兵。哨兵是 Redis 集群架构中非常重要的一个组件,主要有以下功能: 哨兵用于实现 Redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。 哨兵的核心知识 Redis 基于哨兵的高可用性。 面试题: Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的? 两种方式: RDB 优缺点 AOF 优缺点 RDB 和 AOF 到底该如何选择 参考:
1.why-cache?
2000QPS
也开始容易报警了。key-value
式操作,单机支撑的并发量轻松一秒几万十几万,支撑高并发 so easy。单机承载并发量是 mysql 单机的几十倍。
2.缓存与数据库双写不一致?
3.缓存雪崩,缓存穿透,缓存击穿
SET key value EX 10086
。这种方式可以解决请求的 key 变化不频繁的情况,如果黑客恶意攻击,每次构建不同的请求 key,会导致 redis 中缓存大量无效的 key 。很明显,这种方案并不能从根本上解决此问题。如果非要用这种方式来解决穿透问题的话,尽量将无效的 key 的过期时间设置短一点比如 1 分钟。
4.缓存并发竞争
5.redis 和 memcached
file event handler
,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
6.Redis 的过期策略都有哪些?内存淘汰机制都有哪些?
7.如何保证Redis的高可用和高并发?
failover
故障转移,也可以叫做主备切换。
8.Redis 持久化
append-only
的模式写入一个日志文件中,在 Redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。
fsync
操作,最多丢失 1 秒钟的数据。append-only
模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。rewrite
log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。flushall
命令清空了所有数据,只要这个时候后台 rewrite
还没有发生,那么就可以立即拷贝 AOF 文件,将最后一条 flushall
命令给删了,然后再将该 AOF
文件放回去,就可以通过恢复机制,自动恢复所有数据。fsync
一次日志文件,当然,每秒一次 fsync
,性能也还是很高的。(如果实时写入,那么 QPS 会大降,Redis 性能会大大降低)
https://github.com/doocs/advanced-java
https://github.com/Snailclimb/JavaGuide
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算