

私活接单qq群:716817407
web
缓存的使用,是一个逐渐演进的过程。面试
问一下你本身,最直接的使用缓存的缘由是什么?spring
无它,惟快而已!数据库
追溯一下本身最开始使用缓存的场景,一些数据库里存储的不变的配置信息,服务启动时,直接加载到本地公共模块,方便其它功能模块共享使用。这即是最基本,最简单的本地缓存应用。json
1、服务与缓存
所谓的服务,简而言之,一层应用 + 一层数据,应用从数据层获取数据而后加工输出。后端
数据层,一般咱们指的是持久化介质上的持久化存储。它有多种形式的,能够是文件,或者数据库。设计模式
数据存储在持久化介质上,而应用运行与内存中。内存和持久化介质是两个有着量级速度差异的不一样介质,由此,应用和数据之间便有了“矛盾”。缓存
有了这“矛盾”的引子,便有了对缓存的迫切需求。微信
咱们说的缓存,必然要是存放于内存中的,这样它便能距离应用更近,更快的给出应用所须要的数据,以得到更快的服务响应。mybatis

固然,并非缓存彻底隔绝持久层数据。缓存,伴随而生的一个词叫作命中率。
当咱们查询的数据存在于缓存中的时候,咱们称之为“命中”,此时,所需数据能够直接由缓存提供。
而对于未“命中”的数据,则须要穿过缓存层,进一步去持久化数据层获取。此种情景,咱们称之为缓存穿透。
数据获取以后,在返回给应用以前,咱们须要从新填充缓存,以供下一次“命中”查询。
当应用发生数据操做变动,咱们则须要将变动同时更新到持久层及缓冲层。此时,咱们又会面临另一个问题,“先”与“后” 的问题。

“先”与“后”的问题,咱们也称之为缓存一致性问题。
若是先更新缓存,则可能面临持久层更新失败,产生缓存脏数据的问题。
然则,假如先更新持久层,咱们又不得不面对从持久层更新成功以后到缓存更新以前这个间期,缓存对外提供旧数据的窘境。
缓存一致性问题,尤为在高并发环境,须要根据特定场景进行更精妙的控制。
好比,并发修改的一致性锁;好比,异步刷新的延迟刷新等等。
2、缓存与更新
上面咱们提到了缓存更新一致性的问题,从实际应用情景来说,能够细分为强一致性需求,弱一致性需求及最终一致性需求。
一、强一致性需求
好比,交易状态信息,已下单、支付中,已支付等应用,须要咱们主动及时进行关联更新并保证事务层面的一致性。
应景而生的许多包括分布式事务等理论也为咱们解决实际问题提供了很好的践行方案。
二、弱一致性需求
一些涉及不过重要的信息更新,可以容忍短期(好比,几分钟)内持久层数据和缓存数据不一致的场景。好比不外显的描述信息,统计性的计数缓存信息等。一般能够采起异步处理的方式。
一些一段短期内(几秒,几分钟)输出固定信息的场景。好比每隔30s更新热点信息,票价信息等。能够经过设置缓存超时自动剔除的方式进行处理。
三、最终一致性需求
保障数据状态的最终一致性。
3、缓存的粒度
所谓粒度,也即缓存信息块层级,大小。选择何种粒度的缓存,取决于咱们应用的总体架构,数据存储规划及具体的应用场景。
拿用户信息来举例,是缓存活跃信息?仍是相对静态的信息?是按单属性层级来缓存?仍是按整个对象信息?
不一样的数据粒度,也决定着咱们存储缓存的形式:整个对象的二进制序列化数据?更透明直观的json字符串?属性与值的一一映射?
每种形式都有各自的使用优缺点,开发者能够从应用、存储及维护成本各方面进行全面性评估选择。另外,关注公众号Java技术栈,在后台回复:面试,能够获取我整理的缓存系列面试题和答案,很是齐全。
4、缓存穿透的危害
第一小节,咱们提到过关于缓存穿透发生的缘由:缓存未命中。那为何会未命中呢?
一、数据暂时不存在于缓存中
所谓暂时,能够指数据初始还没有加载到缓存,lazy load 按需按时时事加载应用;
也能够是缓存数据被咱们特定的缓存过时策略自动或主动过时,一般使用的过时策略包括元素数量限制,内存占用限制及生存时间限制。

其实,不管是初始未加载仍是缓存过时,删除,这些都属于咱们假定的正常应用场景,再次咱们不予过多评论。
二、数据历来不存在
当一个查询不存在数据的请求到来,其必然会穿过缓存,达到持久化存储层。
持久话存储的响应能力是有限的,当这种请求达到必定的量级,服务可能就要面临着宕机的危险。
至此,咱们对于缓存的做用认知,也须要进一步延伸:下降下层负载,保护后端资源。

形成这种缓存穿透的缘由能够简单的分为内外两方面诱因:内部的应用逻辑问题及外部恶意攻击、爬虫干扰等。
内部问题容易解决,内观可预知,良性优化便可;
反而是外部的不可预料,可能须要更谨慎的进行多面的防护性处理。
其实,不论内部仍是外部,在缓存层面须要处理的就只有一件事:有效拦截穿透。
到此,一般惯性的思惟第一步,就是把形成缓存穿透的数据放置到缓存中,不管其是否存在在于持久化存储中。
好比对于正常的已删除的用户数据,作缓存层面的软删除处理,以状态信息作标注(我存在,其实我不存在! 😳)。就能够很好的解决此类问题形成的穿透压力。
可是,咱们有也个清楚的认知就,就是真正可以形成危害的是那些非正常的入侵数据。好比,穷尽遍历的差异数据,一一存入缓存,惟一的结果就是缓存资源的溢满用尽。这是一种至关恐怖的场景。
针对此种“大数据”型攻击,布隆过滤拦截或许能够成为一个不错的选择。

5、也谈缓存雪崩
上面一节中咱们谈到了缓存的承载保护功能,一面快速响应,一面背负保护持久层数据。
可是,若是缓存因为某些缘由一时不能提供正常服务时,全部的请求就会穿透到持久存储层,形成存储层极端宕机状况发生。

那么,咱们应该如何应对这种状况呢?
一、高可用
缓存的高可用是应对缓存雪崩的首要保障:主从,读写分离,动态扩容,一致性均衡,异地容灾等。
实际应用如Redis的哨兵模式,集群部署等。
推荐: Spring Boot 如何快速集成 Redis 哨兵?

二、服务治理之限流、熔断降级
服务治理的目的是什么?服务的稳定性。
限流即对异常流量的控制;熔断、降级标的核心服务资源的保护。
笔者在轻量级熔断降级框架 alibaba sentinel 应用介绍过当下流行的几种流控框架的使用。
缓存、持久化数据存储都是资源,或者咱们能够从对缓存的流控及对持久化数据存储的熔断、降级保护来着手应对缓存雪崩的情景发生。

三、缓存元素的集中过时致使缓存失效
对于设置了过时时间的缓存元素,若是发生元素同时过时,则会有瞬间的外部请求直接到达持久存储层。
在实际的缓存应用中,须要采起必定的措施,实现缓存元素过时时间的均匀分布。另外,关注公众号Java技术栈,在后台回复:面试,能够获取我整理的缓存系列面试题和答案,很是齐全。


2020-07-29

2020-05-12

2020-07-02

2020-07-23

2020-05-19

2020-04-23

2020-05-29

2020-08-15

2020-08-15

2020-08-14

本文分享自微信公众号 - Java小白学心理(gh_9a909fa2fb55)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。