精华内容
下载资源
问答
  • 问题 项目缓存是如何使用的?为什么要用缓存缓存使用不当会造成什么后果?...这就是看看你对缓存这个东西背后没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答,那面试官你印象肯定...

    问题

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

    分析

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

    只要问到缓存,上来第一个问题,肯定是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用了以后可能会有什么不良的后果?

    这就是看看你对缓存这个东西背后有没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答,那面试官对你印象肯定不太好,觉得你平时思考太少,就知道干活儿。

    面试题剖析

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

    这个,需要结合自己项目的业务来。

    为什么要用缓存?

    用缓存,主要有两个用途:高性能高并发

    高性能

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

    缓存啊,折腾 600ms 查出来的结果,扔缓存里,一个 key 对应一个 value,下次再有人查,别走 mysql 折腾 600ms 了,直接从缓存里,通过一个 key 查出来一个 value,2ms 搞定。性能提升 300 倍。

    就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好。

    高并发

    mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql 单机支撑到 2000QPS 也开始容易报警了。

    所以要是你有个系统,高峰期一秒钟过来的请求有 1万,那一个 mysql 单机绝对会死掉。你这个时候就只能上缓存,把很多数据放缓存,别放 mysql。缓存功能简单,说白了就是 key-value 式操作,单机支撑的并发量轻松一秒几万十几万,支撑高并发 so easy。单机承载并发量是 mysql 单机的几十倍。

    缓存是走内存的,内存天然就支撑高并发。

    用了缓存之后会有什么不良后果?

    常见的缓存问题有以下几个:

    1. 缓存与数据库双写不一致
    2. 缓存雪崩、缓存穿透
    3. 缓存并发竞争

    问题1:

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

    分析

    你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?

    面试题剖析

    一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去。

    串行化可以保证一定不会出现不一致的情况,但是它也会导致系统的吞吐量大幅度降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

    Cache Aside Pattern

    最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。

    • 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
    • 更新的时候,先更新数据库,然后再删除缓存

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

    原因很简单,很多时候,在复杂点的缓存场景,缓存不单单是数据库中直接取出来的值。

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

    另外更新缓存的代价有时候是很高的。是不是说,每次修改数据库的时候,都一定要将其对应的缓存更新一份?也许有的场景是这样,但是对于比较复杂的缓存数据计算的场景,就不是这样了。如果你频繁修改一个缓存涉及的多个表,缓存也频繁更新。但是问题在于,这个缓存到底会不会被频繁访问到?

    举个栗子,一个缓存涉及的表的字段,在 1 分钟内就修改了 20 次,或者是 100 次,那么缓存更新 20 次、100 次;但是这个缓存在 1 分钟内只被读取了 1 次,有大量的冷数据。实际上,如果你只是删除缓存的话,那么在 1 分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低。用到缓存才去算缓存。

    其实删除缓存,而不是更新缓存,就是一个 lazy 计算的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它到需要被使用的时候再重新计算。像 mybatis,hibernate,都有懒加载思想。查询一个部门,部门带了一个员工的 list,没有必要说每次查询部门,都里面的 1000 个员工的数据也同时查出来啊。80% 的情况,查这个部门,就只是要访问这个部门的信息就可以了。先查部门,同时要访问里面的员工,那么这个时候只有在你要访问里面的员工的时候,才会去数据库里面查询 1000 个员工。

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

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

    redis-junior-inconsistent

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

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

    数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。随后数据变更的程序完成了数据库的修改。完了,数据库和缓存中的数据不一样了...

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

    只有在对一个数据在并发的进行读写的时候,才可能会出现这种问题。其实如果说你的并发量很低的话,特别是读并发很低,每天访问量就 1 万次,那么很少的情况下,会出现刚才描述的那种不一致的场景。但是问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只要有数据更新的请求,就可能会出现上述的数据库+缓存不一致的情况

    解决方案如下:

    更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新读取数据+更新缓存的操作,根据唯一标识路由之后,也发送同一个 jvm 内部队列中。

    一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条一条的执行。这样的话,一个数据变更的操作,先删除缓存,然后再去更新数据库,但是还没完成更新。此时如果一个读请求过来,没有读到缓存,那么可以先将缓存更新的请求发送到队列中,此时会在队列中积压,然后同步等待缓存更新完成。

    这里有一个优化点,一个队列中,其实多个更新缓存请求串在一起是没意义的,因此可以做过滤,如果发现队列中已经有一个更新缓存的请求了,那么就不用再放个更新请求操作进去了,直接等待前面的更新操作请求完成即可。

    待那个队列对应的工作线程完成了上一个操作的数据库的修改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,然后写入缓存中。

    如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回;如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。

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

    • 读请求长时阻塞

    由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。

    该解决方案,最大的风险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在里面,然后读请求会发生大量的超时,最后导致大量的请求直接走数据库。务必通过一些模拟真实的测试,看看更新数据的频率是怎样的。

    另外一点,因为一个队列中,可能会积压针对多个数据项的更新操作,因此需要根据自己的业务情况进行测试,可能需要部署多个服务,每个服务分摊一些数据的更新操作。如果一个内存队列里居然会挤压 100 个商品的库存修改操作,每隔库存修改操作要耗费 10ms 去完成,那么最后一个商品的读请求,可能等待 10 * 100 = 1000ms = 1s 后,才能得到数据,这个时候就导致读请求的长时阻塞

    一定要做根据实际业务系统的运行情况,去进行一些压力测试,和模拟线上环境,去看看最繁忙的时候,内存队列可能会挤压多少更新操作,可能会导致最后一个更新操作对应的读请求,会 hang 多少时间,如果读请求在 200ms 返回,如果你计算过后,哪怕是最繁忙的时候,积压 10 个更新操作,最多等待 200ms,那还可以的。

    如果一个内存队列中可能积压的更新操作特别多,那么你就要加机器,让每个机器上部署的服务实例处理更少的数据,那么每个内存队列中积压的更新操作就会越少。

    其实根据之前的项目经验,一般来说,数据的写频率是很低的,因此实际上正常来说,在队列中积压的更新操作应该是很少的。像这种针对读高并发、读缓存架构的项目,一般来说写请求是非常少的,每秒的 QPS 能到几百就不错了。

    我们来实际粗略测算一下

    如果一秒有 500 的写操作,如果分成 5 个时间片,每 200ms 就 100 个写操作,放到 20 个内存队列中,每个内存队列,可能就积压 5 个写操作。每个写操作性能测试后,一般是在 20ms 左右就完成,那么针对每个内存队列的数据的读请求,也就最多 hang 一会儿,200ms 以内肯定能返回了。

    经过刚才简单的测算,我们知道,单机支撑的写 QPS 在几百是没问题的,如果写 QPS 扩大了 10 倍,那么就扩容机器,扩容 10 倍的机器,每个机器 20 个队列。

    • 读请求并发量过高

    这里还必须做好压力测试,确保恰巧碰上上述情况的时候,还有一个风险,就是突然间大量读请求会在几十毫秒的延时 hang 在服务上,看服务能不能扛的住,需要多少机器才能扛住最大的极限情况的峰值。

    但是因为并不是所有的数据都在同一时间更新,缓存也不会同一时间失效,所以每次可能也就是少数数据的缓存失效了,然后那些数据对应的读请求过来,并发量应该也不会特别大。

    • 多服务实例部署的请求路由

    可能这个服务部署了多个实例,那么必须保证说,执行数据更新操作,以及执行缓存更新操作的请求,都通过 Nginx 服务器路由到相同的服务实例上

    比如说,对同一个商品的读写请求,全部路由到同一台机器上。可以自己去做服务间的按照某个请求参数的 hash 路由,也可以用 Nginx 的 hash 路由功能等等。

    • 热点商品的路由问题,导致请求的倾斜

    万一某个商品的读写请求特别高,全部打到相同的机器的相同的队列里面去了,可能会造成某台机器的压力过大。就是说,因为只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以其实要根据业务系统去看,如果更新频率不是太高的话,这个问题的影响并不是特别大,但是的确可能某些机器的负载会高一些。

    问题2:

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

    分析

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

    面试题剖析

    缓存雪崩

    对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据库必然扛不住,它会报一下警,然后就挂了。此时,如果没有采用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。

    这就是缓存雪崩。

    redis-caching-avalanche

    大约在 3 年前,国内比较知名的一个互联网公司,曾因为缓存事故,导致雪崩,后台系统全部崩溃,事故从当天下午持续到晚上凌晨 3~4 点,公司损失了几千万。

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

    • 事前:redis 高可用,主从+哨兵,redis cluster,避免全盘崩溃。
    • 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。
    • 事后:redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

    redis-caching-avalanche-solution

    用户发送一个请求,系统 A 收到请求后,先查本地 ehcache 缓存,如果没查到再查 redis。如果 ehcache 和 redis 都没有,再查数据库,将数据库中的结果,写入 ehcache 和 redis 中。

    限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。

    好处:

    • 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。
    • 只要数据库不死,就是说,对用户来说,2/5 的请求都是可以被处理的。
    • 只要有 2/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来一次。

    缓存穿透

    对于系统A,假设一秒 5000 个请求,结果其中 4000 个请求是黑客发出的恶意攻击。

    黑客发出的那 4000 个攻击,缓存中查不到,每次你去数据库里查,也查不到。

    举个栗子。数据库 id 是从 1 开始的,结果黑客发过来的请求 id 全部都是负数。这样的话,缓存中不会有,请求每次都“视缓存于无物”,直接查询数据库。这种恶意攻击场景的缓存穿透就会直接把数据库给打死。

    redis-caching-penetration

    解决方式很简单,每次系统 A 从数据库中只要没查到,就写一个空值到缓存里去,比如 set -999 UNKNOWN。然后设置一个过期时间,这样的话,下次有相同的 key 来访问的时候,在缓存失效之前,都可以直接从缓存中取数据。

    缓存击穿

    缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

    解决方式也很简单,可以将热点数据设置为永远不过期;或者基于 redis or zookeeper 实现互斥锁,等待第一个请求构建完缓存之后,再释放锁,进而其它请求才能通过该 key 访问数据。

    问题3:

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

    分析

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

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

    面试题剖析

    某个时刻,多个系统实例都去更新某个 key。可以基于 zookeeper 实现分布式锁。每个系统通过 zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作某个 key,别人都不允许读和写。

    zookeeper-distributed-lock

    你要写入缓存的数据,都是从 mysql 里查出来的,都得写入 mysql 中,写入 mysql 中的时候必须保存一个时间戳,从 mysql 查出来的时候,时间戳也查出来。

    每次要写之前,先判断一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。

    转载来源:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/why-cache.md

    展开全文
  • 缓存

    2018-07-18 16:53:01
    利用项目闲暇时间,对缓存知识进行了一次梳理,整理成了脑图,这里配合脑图进行一下说明。 脑图:缓存知识点整理 [TOC] 缓存简介 缓存的本质是让数据更接近使用者,如何设计缓存、哪些数据适合进行缓存缓存...

    缓存

    [TOC]
    利用项目闲暇时间,对缓存知识进行了一次梳理,整理成了脑图,这里配合脑图进行一下说明。
    脑图:缓存知识点整理

    整体内容

    缓存脑图

    缓存简介

    1、缓存的本质是让数据更接近使用者,这里的使用者如何理解?不一定是真实用户,可以理解为调用方。如何设计缓存、哪些数据适合进行缓存、缓存的方式、缓存的回收策略、缓存带来的问题都是我们需要考量的点。
    2、缓存的一个主要考察点是缓存的命中率,缓存命中率=从缓存中读取次数/总读取次数。
    3、适合缓存的数据有:热点数据、I/O瓶颈数据、CPU瓶颈数据、符合5分钟法则的数据、符合局部性原理的数据。
    4、缓存的回收策略:
    何时回收:基于空间(空间达到某个阀值就回收)、基于条数(条数达到某个阀值就回收)、基于时间(按存活期、空闲期回收)
    回收哪些: 先进先出;最近最少使用;最不常用等。
    如何回收: delete

    java应用缓存

    java应用缓存是为了在极高并发场景下,减轻后端数据库压力的一种缓存方式,需要一定程度上允许缓存不一致的情况。
    根据缓存位置,可以分为堆内缓存、堆外缓存、磁盘缓存。
    堆内缓存,是指缓存位置在java堆中,无需序列化反序列化,速度最快,缺点是当数据量大时,GC变得很慢。
    堆外缓存,是指缓存位置在java堆外的内存中,减少的GC时间,但是增加了序列化反序列化的开销。
    磁盘缓存,相对于内存缓存而言,在机器重启后数据不会丢失,速度相对而言也是最慢的。
    支持的插件有:guava cache(只支持堆内缓存)、ehcache(支持堆内、堆外、磁盘缓存)等。
    引入java应用缓存后,需要考虑分布式场景下,如何保证数据的一致性。
    可以有如下几种方案:
    1、单节点通知其他节点,缺点是系统耦合、关系复杂。
    2、MQ通知,缺点是引入了MQ,系统变得复杂。
    3、定时任务从后端读取数据,更新缓存,放弃了实时一致性。

    http缓存

    http缓存有两种形式,强制缓存和对比缓存。有不同的交互流程、不同的表现形式、不同的实现方式、不同的使用场景,下面从这几个方面进行分析。

    交互流程:

    强制缓存-命中流程:请求缓存库,返回数据。
    强制缓存-未命中流程:从服务器获取数据,返回数据和缓存规则,将数据写入缓存库。

    对比缓存-命中流程:请求缓存库,返回缓存标识;将标识带到后台服务器验证是否有效;有效情况下,从缓存库获取数据。
    对比缓存-未命中流程:请求缓存库,返回缓存标识;将标识带到后台服务器验证是否有效;无效情况下,返回数据和缓存规则;将数据写入缓存。

    表现形式(以谷歌浏览器为例):

    强制缓存:返回码200,size显示:from memory cache(放在内存中,浏览器关闭会丢失)或者from disk cache(持久化到磁盘),time显示0
    对比缓存:返回码304,大小和时间都比较小

    实现方式

    强制缓存:
    1)关键字Expires:Expires的值为服务端返回的到期时间,即下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据。这是HTTP 1.0支持的关键字,现在是HTTP 1.1,基本可以忽略。服务器时间可能不准,容易有误差。
    2)关键字Cache-Control
    对比缓存:
    1)关键字Last-Modified / If-Modified-Since:Last-Modified:服务器在相应请求时,告诉浏览器资源的最后修改时间。If-Modified-Since:浏览器在请求时,告诉服务器上次请求时,服务器返回的资源最后修改时间。
    2)关键字Etag / If-None-Match(优先级较高):Etag:服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识。If-None-Match:再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。

    使用场景

    对比缓存比强制缓存多了一次交互流程,但是是否可以走缓存交由后端控制,更具灵活性,需要根据具体场景分析,具体采用哪种缓存方式。

    redis缓存

    redis是分布式系统中比较常用的NOSQL数据库,因此我们对他进行比较深入的了解。
    从redis数据类型及使用场景、redis开发禁用命令、redis与memcache的比较、redis效率高的原因、redis过期策略及内存淘汰机制、redis持久化、redis集群、缓存遇到的问题这几个方面来分析。

    redis数据类型及使用场景

    redis有五种数据类型:string/hash/list/set/sorted set
    String是使用最多的一种数据类型,可以存储字符串、数字、序列化后的对象等。
    hash数据结构实际为map,当值较少时,数据结构为一维数组。使用场景:存储Obj,可以很方便的对属性设值取值。
    list数据结构实际为双端链表,提供了左插左移,右插右移等功能。使用的场景:分布式场景中全局唯一ID–发号器。
    set数据结构为去重的列表,同时提供了判重、取交并集等操作。使用场景:粉丝列表,很方便的做防重,通过交并集做推荐等功能。
    sorted set为有序的set,使用场景:文章列表,按创建时间或修改时间排序等。

    redis开发禁用命令

    在开发过程中,有些redis的命令会消耗大量的系统资源,可能会造成系统卡死等异常。我们的不建议使用的。这里列举一下,在设计的时候就不要使用这些。keys、monitor、flushall、flushdb

    redis与memcache的比较

    redis相比较于memcache,支持更丰富的数据类型,memcache只支持string。
    redis相比较于mamcache,效率更高,速度更快。
    redis支持持久化的功能。
    redis的value值最大可支持到1G,memcache最大只能支持1M。但要注意,在设计缓存时,要尽量避免将大对象存放到redis中,避免造成IO损耗,引起卡死。

    redis效率高的原因

    redis相比较于关系型数据库或者其他非关系型数据库,效率高一直是一个优势。效率高的原因主要有这么几点:
    1)纯内存操作,物理上面就快。
    2)单线程操作。单线程操作有这么几个好处:避免多线程操作中的上下文切换、加解锁动作,这些动作比较耗性能;简化了逻辑,使得能用简单的方式实现复杂的数据结构。然而我们需要注意的是,并不是说单线程就一定比多线程好,也不是说非关系型数据库就要设计成单线程,这取决于使用场景和取舍。
    3)采用NIO的多路复用机制。客户端在操作时,产生不同是socket连接。服务端的多路复用程序将这些socket置于队列中,按顺序进行处理。文件事件分派期依次从队列中取值,转发到不同的处理器中进行处理。

    redis过期策略及内存淘汰机制

    提到过期策略,我们需要先思考一个问题,我们设置了超时时间的那些key,是在什么时候被删除的?
    可能有以下三种方法:
    1)定时删除:可以理解为准实时删除,每创建一个key,都建一个定时器,不停的扫描失效时间,失效的话就删除key值,同时销毁定时器。
    2)惰性删除:每次请求缓存的时候,都校验一下失效时间,如果已失效,则删除key值。
    3)定期删除:起一个定时任务,每隔一段时间扫描设置了失效时间的这些key,如果已经到期,则进行删除。
    定时删除虽然能达到准实时,但是对性能的损耗也是最高的。
    惰性删除可能存在这样的问题:某个key值访问频率非常低,有可能过期后一直得不到删除,会占用内存。
    定期删除介于两者之间,内存友好度不如定时删除,CPU友好度不如惰性删除。
    redis采用的是惰性删除+定期删除的策略。
    这里提一下redis定期删除的策略:在规定时间内,分多次遍历服务器中的数据库,从数据库的字典中随机检查一部分键的过期时间,并删除其中的过期键。

    当内存达到阀值时该如何处理?是直接抛出异常,还是根据规则清理部分内存呢?
    redis提供了以下内存淘汰机制:
    1)noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
    2)allkeys-lru:在主键空间中,优先移除最近未使用的key。
    3)allkeys-random:在主键空间中,随机移除某个key。
    4)volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
    5)volatile-random:在设置了过期时间的键空间中,随机移除某个key。
    6)volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。

    redis持久化

    redis提供了持久化的功能,持久化的主要作用是为了容灾。
    redis提供了两种持久化的策略,RDB/AOF。
    RDB是指持久化指定时间内的数据快照。优点是文件小,恢复的速度快。缺点是不具有实时性,可能会丢失数据,另外可能会影响性能,造成系统卡顿。
    AOF是指持久化写操作指令。优点是实时性好,基本可以做到同步。缺点是文件比较大,恢复的速度慢。
    我们推荐一种线上的持久化策略:为提高写性能,主关闭RDB和AOF,每天定时取一次RDB,并转移至远程。
    从关闭RDB,开启AOF,每天对AOF压缩一次,压缩前备份。

    redis集群

    单节点的redis会遇到什么样的问题呢?
    1、高可用问题,单节点无法保证高可用。
    2、容量问题,单节点存储容量有限,达到32G后性能下降。
    3、并发度问题,单机的并发能力有限,可能不满足高并发要求。
    因此redis3.0提供了redis的集群redis-cluster。
    逻辑图:
    逻辑图
    写操作时,数据通过CRC16运算,将数据均匀的分到16384个slot中,slot按照配置分配在master上,master之间数据没有交集。一个master可以配置多个slaver,slaver与master保持同步,slaver可以增加读的并发程度。master之间两两保持心跳,检测存活。
    特殊情况下的容灾策略:
    1)某master挂掉,其对应的某个slaver升级为master
    2)某master及其对应的slaver都挂掉,集群不可用
    3)超过半数的master挂掉,集群不可用

    这种实现机制会有这样的问题:master与master需要保持两两通信、master与对应的slaver需要保持通信;读取时,随机到某个slaver上,还需要进行CRC16运算,重新寻找slot所在的服务器,存在二次寻址。因此显得结构比较厚重,性能有损耗。

    豆瓣提供了另一种解决方案:codis。

    缓存遇到的问题

    在分布式场景中,由分布式、高并发经常会产生一些问题,我们对这些问题进行了总结,并提供了解决方案。

    缓存和数据库双写一致性问题

    这种问题的表现是缓存与数据库的值不一致。问题产生的原因通常是操作数据库与操作缓存的顺序,以及操作方式引起的。
    1)先更新数据库,再更新缓存
    若更新缓存失败如何处理呢,缓存的更新动作场景比较复杂,难以通过一些手段对其进行处理,我们这里不建议采用这种方式。
    2)先删除缓存,再更新数据库
    场景1:A删缓存,B读库,B写缓存,A写库
    这样的场景会出现最终数据库和缓存不一致的情况。
    方案进化1:先删除缓存,再更新数据库,延时1s,再删缓存
    这样就解决了场景1中的问题,这里的1S是个需要考量的点,如果在这1S内有数据进来,会读取到脏数据。如果删除缓存失败应该如何处理呢?
    方案进化2:先删除缓存,再更新数据库,延时1s,再删缓存,异步解析binlog,重试删缓存。
    3)先更新数据库,再删除缓存
    后删缓存面临同样的问题:删除失败怎么办?
    方案进化:先更新数据库,再删除缓存,异步解析binlog,重试删缓存

    我们公司采用了折中的方案:
    1、采用先删除、再更新数据库的方式。
    2、单机写redis时,用读写锁实现回源机制,降低单机并发量。

    缓存击穿与缓存雪崩问题

    场景1:大量请求同时请求某缓存不存在的值
    场景2:某批缓存同时失效,请求直接到了数据库
    方案1:互斥锁,更新前先获得锁,无锁不更新–会降低吞吐量
    方案2:预热与异步更新,起定时任务去数据库读取数据写入缓存,保证数据从缓存中读取
    方案3:给缓存失效时间加上随机数,避免同时大批数据缓存失效
    方案4:双缓存,A缓存设失效时间,如未读取到,从B缓存获取,B缓存不设失效时间,或者B缓存自动做缓存异步更新
    方案5:java堆缓存,避免直接访问数据库

    缓存并发竞争问题

    场景:大量客户端请求redis,获取值后进行操作,再写入redis。可能写入非预期值
    方案1:利用redis自带的incr命令
    方案2:利用redis事务机制处理
    方案3:利用redis的setnx实现内置的锁

    数据库缓存

    数据库缓存具体的存储方式我们这里就不关心了,主要关系缓存的工作流程,以及命中条件。
    工作流程:
    1、服务器接收SQL,以SQL和一些其他条件为key查找缓存表(额外性能消耗)
    2、如果找到了缓存,则直接返回缓存(性能提升)
    3、如果没有找到缓存,则执行SQL查询,包括原来的SQL解析,优化等.
    4、执行完SQL查询结果以后,将SQL查询结果存入缓存表(额外性能消耗)
    命中条件:
    Sql的大小写必须完全一样;
    发起sql的客户端必须使用同样的字符集和通信协议;
    sql查询同一数据库下的同一个表(不同数据库可能有同名表);
    Sql查询结果必须确定,即不能带有now()等函数;
    当查询表发生DML或DDL,其缓存即失效;
    针对mysql/information_schema/performance_schema的查询不缓存;
    使用临时表的sql也不能缓存;

    mybatis缓存

    mybatis的缓存可以设置一级缓存和二级缓存。
    一级缓存默认开启,作用域为sqlsession。
    二级缓存默认不开启,作用域为namespace,通过实现接口或者引入ehcache实现。
    一级缓存失效的情况:
    1、不同的SqlSession对应不同的一级缓存
    2、同一个SqlSession但是查询条件不同
    3、同一个SqlSession两次查询期间执行了任何一次增删改操作
    4、同一个SqlSession两次查询期间手动清空了缓存

    nginx缓存

    NG缓存根据场景不同可以分为这两类:
    浏览器到NG–缓存在浏览器
    NG到后端–缓存在NG

    CDN缓存

    CDN缓存是基于HTTP协议的。

    这里是从开发者的角度去看缓存这个事情,对于部分缓存方式没有深入的研究,等以后知识面开阔了再补充。

    展开全文
  • Django项目缓存优化

    2019-08-19 13:23:35
    今天的Python学习教程绝对是纯技术的分享, 关于Django项目缓存优化问题的详细讲解! 一起来看看: 一、为什么要使用缓存 ​大家可以想一下Django的请求响应流程: → 用户浏览器输入URL地址 → Web服务器将HTTP请求...

    今天的Python学习教程绝对是纯技术的分享, 关于Django项目缓存优化问题的详细讲解!

    一起来看看:

    一、为什么要使用缓存

    ​大家可以想一下Django的请求响应流程:

    → 用户浏览器输入URL地址

    → Web服务器将HTTP请求转发给uWSGI服务器

    → uWSGI服务器将Request请求转发给Django应用

    → Django中间件处理Request请求

    → 视图View处理

    → 模型类Models获取数据

    → 模板Template渲染

    → 再次经过Django中间件返回

    → uWSGI服务器将Response返回给Web服务器

    → Web服务器响应客户端的HTTP请求。

    ​这其中耗时最多的2个环节通常是视图中业务逻辑处理和从Models获取数据(SQL查询),对于相同目的请求,也就是业务处理逻辑和SQL查询的数据都一样的请求,每次都进行了重复的计算,并且数据是从硬盘读取而非内存。

    ​所以使用缓存有如下好处:

    • 降低服务器负载
    • 避免重复计算
    • 提高系统性能

    二、如何进行缓存

    ​很简单,一个Request请求过来,先去缓存中查询,有就返回;没有就去数据库查询并处理,然后把结果缓存好(供下次请求使用),再返回。用伪代码解释的话就是这样
    在这里插入图片描述

    三、缓存的类型

    Memcached 效率最高,最快的缓存
    Database caching 数据库缓存,这个指把数据缓存到数据表,比如你项目中使用的MySQL,就在MySQL中建表来专门缓存数据。不是指用Redis数据库
    Filesystem caching 文件系统缓存,将缓存会把键值存储到独立的文件中去
    Local-memory caching 使用系统内存缓存
    Dummy caching (for development) 假缓存,只在开发过程中使用,以调试缓存接口,数据并没有真正缓存
    Using a custom cache backend 自定义缓存后端,比如使用Redis
    那么问题来了,我该使用哪种缓存呢?
    其实常用的也就2种:Memcached或者Reids,其它基本不用考虑了。Redis国内用得多,支持RDB和AOF两种持久化方式,支持高可用集群,技术和方案很成熟。Memcached是纯内存存储,本身不支持持久化,不支持分布式,但是它内存管理效率高。

    四、缓存粒度分类

    • Per-site cache 把整个网站都缓存了,只需要在项目中设置加入缓存中间键的配置,系统便会自动对整个网站进行缓存
    • Per-view cache 缓存某个视图
      Template fragment caching 模板的片段,比如Django模板继承base.html,通常是不变的导航栏
    • Low-level cache API 低级别缓存API,比如缓存某个函数的结果,或者某个API接口
      那么问题又来了,项目中我该选择什么样的缓存粒度?

    是否需要缓存很简单,看内容是否变化。如果整个视图的数据通常都不变,就使用视图缓存,某些模板片段的数据不变就使用模板片段缓存等等。所以一个项目里面多种缓存粒度都有的
    在这里插入图片描述
    五、Django缓存设置
    这里只说一下Redis和Memcached的,其它很少用的就不罗列了,需要注意的是系统上要安装对应的缓存服务,Django开发环境中要安装连接缓存服务的包(比如django-redis或pymemcache)

    Memcache缓存设置

    最简单的,配置地址和端口,不一定是要在本机,也可以是其它网段的服务器或集群
    在这里插入图片描述
    在本机的话,也可以使用unix Socket
    在这里插入图片描述
    也可以使用多态服务器,不同端口缓存
    在这里插入图片描述
    Redis缓存设置

    截图一下实战课程中Redis缓存的配置,缓存网站的数据
    在这里插入图片描述

    Django channels频道层的缓存
    在这里插入图片描述
    Celery缓存,broker和任务的执行结果在这里插入图片描述

    六、缓存的使用

    ​对于Django项目缓存的数据,我们取出来或存进去操作,可以不需要直接操作底层的缓存数据,比如使用原生的Redis或Memcached命令,只需要使用Django提供的缓存API即可。就像我们使用Django ORM一样,无需关注底层数据库是MySQL, PostgreSQL或SQLite,ORM语句都一样。

    ​例如,访问缓存
    在这里插入图片描述
    ​使用缓存
    在这里插入图片描述
    ​除了set(), get()还有get_or_set(), get_many(), set_many(), delete(), delete_many(), clear(), touch(), incr(), decr(), close()操作。大家可以去看看官网文档一个个操作下,要注意的是有的API不是每一个Django版本都有,比如cache.touch()是Django 2.1版本才有的。

    七、Django缓存优化性能评估

    ​缓存使用了,那效果怎么样,有什么指标可以衡量?用什么工具来衡量?

    Django Debug Toolbar

    这点在之前的Python学习教程中有跟大家讲到过!

    django-debug-toolbar是一个开源的工具,可以在看板上展示django对request/response处理的详细信息,比如当前请求响应的CPU耗时,settings/headers/request信息,当前请求使用的模板文件,静态文件,具体SQL语句和执行时间等等,看板要显示什么信息是可以灵活配置的。

    右边的栏目就是django-debug-tool的看板

    在这里插入图片描述
    此页面共有9次SQL查询,耗时8.62毫秒
    在这里插入图片描述
    缓存命中3次,cache.get(),用时约0.91毫秒
    在这里插入图片描述
    meter压力测试

    django-debug-tool是开发人员用,从功能角度测试缓存效果。而Jmeter就是专门测试人员用的,用于性能测试和压力测试。项目使用缓存后,整体性能是不是提高了,高负载情况下系统稳定性怎么样。测试方面的知识就不具体展开了,不太清楚的伙伴可以私信或者留言哈!更多的Python学习教程也会继续为大家更新!

    展开全文
  • java项目缓存技术

    千次阅读 2019-08-27 14:31:19
    一、什么缓存 1、Cache是高速缓冲存储器 一种特殊的存储器子系统,其中复制了频繁使用的数据以利于快速访问 2、凡是位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为 ...

    https://blog.csdn.net/baidu_33497625/article/details/50801571

    一、什么是缓存

    1、Cache是高速缓冲存储器 一种特殊的存储器子系统,其中复制了频繁使用的数据以利于快速访问
    2、凡是位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为 Cache

    二、缓存的分类

    1、基于web应用的系统架构图

    2、在系统架构的不同层级之间,为了加快访问速度,都可以存在缓存

    • 操作系统磁盘缓存->减少磁盘机械操作
    • 数据库缓存->减少文件系统I/O
    • 应用程序缓存->减少对数据库的查询 
    • Web服务器缓存->减少应用服务器请求
    • 客户端浏览器缓存->减少对网站的访问

    三、操作系统缓存

    1、文件系统提供的Disk Cache:操作系统会把经常访问到的文件内容放入到内存当中,由文件系统来管理
    2、当应用程序通过文件系统访问磁盘文件的时候,操作系统从Disk Cache当中读取文件内容,加速了文件读取速度
    3、Disk Cache由操作系统来自动管理,一般不用人工干预,但应当保证物理内存充足,以便于操作系统可以使用尽量多的内存充当Disk Cache,加速文件读取速度
    4、特殊的应用程序对文件系统Disk Cache有很高的要求,会绕开文件系统Disk Cache,直接访问磁盘分区,自己实现Disk 
    5、Cache策略

    • Oracle的raw device(裸设备) – 直接抛弃文件系统
    • MySQL的InnoDB: innodb_flush_method = O_DIRECT

    3.1 高速缓存cache

    cache位于cpu和主存储器间的高速小容量存储器,由静态存储信片SRAM组成,接近cpu的速度。cache可以大幅度提升cpu内部读取数据的命中率,从而提高系统的性能。

    通过由以下方面组成:

    联想存储器:根据内容进行寻址的存储器,只存在部分信息,根据内容进行检索;

    地址转换部件:通过联想模块简历的目录表以实现快速地址转换。命中直接访问cache。未命中从内存读取放入cache。

    替换部件:在缓存已满时,按一定策略进行数据块替换(先进先出FIFO、最近最少用LRU、随机替换、最不常用LFU),并修改地址转换部件。

    1)cache一致性问题

    • 对cache进行更新时,存在cache与主存如何保持一致的问题;
    • 多个设备访问主存,IO可直接读写内存,如果cache内容被修改,则IO设备读出对应主存单元的内容无效。弱IO修改了主存单元,则cache无效;
    • 多个cpu带各自的cache而共享主存,某个cpu修改了自身的cache,则对应的主存单元和其他的cpu中对应的内容都变为无效。

    2)解决方法

    关键在于处理好写操作

    全写法write Through(通写法、写直达法、直写法):若写命中九同时写cache和主存;若写不命中,1)写分配:先写主存块中更新相应的存储空间,然后再分配cache行,更新主存块九装入cache行,利用空间的局部性,每次不命中都要从主存读一个块;2)非全写分配:直接写主存单元,不把主内存快装入cache。

    回写法write back一次性写方式、写回法:只写cache不写主存,但是控制复杂。


    四、数据库缓存


    1、重要性

    • 数据库通常是企业应用系统最核心的部分
    • 数据库保存的数据量通常非常庞大
    • 数据库查询操作通常很频繁,有时还很复杂
    • 以上原因造成数据库查询会引起非常频繁的磁盘I/O读取操作,迫使CPU挂起等待,数据库性能极度低下

    2、缓存策略
         a、Query Cache

      • 以SQL作为key值缓存查询结果集
      • 一旦查询涉及的表记录被修改,缓存就会被自动删除
      • 设置合适的Query Cache会极大提高数据库性能
      • Query Cache并非越大越好,过大的Qquery Cache会浪费内存。
      • MySQL: query_cache_size= 128M

         b、Data Buffer

      • data buffer是数据库数据在内存中的容器
      • data buffer的命中率直接决定了数据库的性能
      • data buffer越大越好,多多益善
      • MySQL的InnoDB buffer:innodb_buffer_pool_size = 2G
      • MySQL建议buffer pool开大到服务器物理内存60-80%

    4.1 数据库缓存的三种方式

    1)cache Aside更新模式:同时更新缓存和数据库;

    失效:应用程序从cache取数据,没取到,则从数据库读取,成果之后放到缓存;

    命中:应用程序从cache取数据,取到返回;

    更新:把数据放到数据库,成功后,让缓存失效;

    为什么先更新数据库,后让缓存失效?

    1、先更新数据库,后更新缓存:两个并发写操作回导致脏数据;

    2、先删除缓存,再更新数据库:逻辑错误,两个并发读和写操作导致脏数据;

    3、先更新数据库,再删除缓存;推荐使用,极端情况(查询缓存不命中,进行数据库查询,并发出现更新操作,更新了数据库,删除了缓存,然而读操作从数据库读取老数据回了缓存,造成数据不一致,这种极少发生。)

    2)Read/Write through 更新模式:先更新缓存,缓存负责同步更新数据库;

    只需要维护缓存

    Read through :查询操作中更新缓存;

    Write through :更新数据的时候,更新缓存;

    3)Write behind caching 更新模式:先更新缓存,缓存定时异步更新数据库;

    好处:直接操作内存,速度快,可以合并对同一数据的多次操作到数据库,所以性能得到很大的提高;

    问题:数据不是强一致,可能回丢失(系统断电等);缓存失效才实现真正的持久性存储;

    五、应用程序缓存


    1、对象缓存

    • 由O/R Mapping框架例如Hibernate提供,透明性访问,细颗粒度缓存数据库查询结果,无需业务代码显式编程,是最省事的缓存策略
    • 当软件结构按照O/R Mapping框架的要求进行针对性设计,使用对象缓存将会极大降低Web系统对于数据库的访问请求
    • 良好的设计数据库结构和利用对象缓存,能够提供极高的性能,对象缓存适合OLTP(联机事务处理)应用

    2、查询缓存

    • 对数据库查询结果集进行缓存,类似数据库的Query Cache
    • 适用于一些耗时,但是时效性要求比较低的场景。查询缓存和对象缓存适用的场景不一样,是互为补充的
    • 当查询结果集涉及的表记录被修改以后,需要注意清理缓存

    3、页面缓存
         a、作用

      • 针对页面的缓存技术不但可以减轻数据库服务器压力,还可以减轻应用服务器压力
      • 好的页面缓存可以极大提高页面渲染速度
      • 页面缓存的难点在于如何清理过期的缓存

        b、分类
             I、动态页面静态化

      • 利用模板技术将访问过一次的动态页面生成静态html,同时修改页面链接,下一次请求直接访问静态链接页面
      • 动态页面静态化技术的广泛应用于互联网CMS/新闻类Web应用,但也有BBS应用使用该技术,例如Discuz!
      • 无法进行权限验证,无法显示个性化信息
      • 可以使用AJAX请求弥补动态页面静态化的某些缺点

            II、Servlet缓存

      • 针对URL访问返回的页面结果进行缓存,适用于粗粒度的页面缓存,例如新闻发布
      • 可以进行权限的检查
      • OScache提供了简单的Servlet缓存(通过web.xml中的配置)
      • 也可以自己编程实现Servlet缓存

            III、页面内部缓存

      • 针对动态页面的局部片断内容进行缓存,适用于一些个性化但不经常更新的页面(例如博客)
      • OSCache提供了简单的页面缓存
      • 可以自行扩展JSP Tag实现页面局部缓存


    六、web服务器端缓存

     

    • 基于代理服务器模式的Web服务器端缓存,如squid/nginx
    • Web服务器缓存技术被用来实现CDN(内容分发网络 content delivery network)
    • 被国内主流门户网站大量采用
    • 不需要编程,但仅限于新闻发布类网站,页面实时性要求不高

    七、基于ajax的浏览器缓存

     

    • 使用AJAX调用的时候,将数据库在浏览器端缓存
    • 只要不离开当前页面,不刷新当前页面,就可以直接读取缓存数据
    • 只适用于使用AJAX技术的页面

    一、cookie机制和session机制的区别

    具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。

    同时我们也看到,由于才服务器端保持状态的方案在客户端也需要保存一个标识,所以session

    机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择

    二、会话cookie和持久cookie的区别

    如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。

    如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。

    存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。

    三、如何利用实现自动登录

    当用户在某个网站注册后,就会收到一个惟一用户ID的cookie。客户后来重新连接时,这个

    用户ID会自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录,从而使用户务需给出明确的用户名和密码,就可以访问服务器上的资源。

    四、如何根据用户的爱好定制站点

    网站可以使用cookie记录用户的意愿。对于简单的设置,网站可以直接将页面的设置存储在cookie中完成定制。然而对于更复杂的定制,网站只需仅将一个惟一的标识符发送给用户,由服务器端的数据库存储每个标识符对应的页面设置。

    五、cookie的发送

    1.创建Cookie对象

    2.设置最大时效

    3.将Cookie放入到HTTP响应报头

    如果你创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie:存储在浏览器的内存中,用户退出浏览器之后被删除。如果你希望浏览器将该cookie存储在磁盘上,则

    需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。

    发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个Set-CookieHTTP请求报头中。由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此我们将这个方法称为是addCookie,而非setCookie。同样要记住响应报头必须在任何文档内容发送到客户端之前设置。

    六、cookie的读取

    1.调用request.getCookie

    要获取有浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值。

    2.对数组进行循环,调用每个cookie的getName方法,直到找到感兴趣的cookie为止

    cookie与你的主机(域)相关,而非你的servlet或JSP页面。因而,尽管你的servlet可能只发送了单个cookie,你也可能会得到许多不相关的cookie。

    例如:

    StringcookieName=“userID”;

    Cookiecookies[]=request.getCookies();

    if(cookies!=null){

    for(inti=0;i

    Cookiecookie=cookies[i];

    if(cookieName.equals(cookie.getName())){

    doSomethingWith(cookie.getValue());}}}

    七、如何使用cookie检测初访者

    A.调用HttpServletRequest.getCookies()获取Cookie数组

    B.在循环中检索指定名字的cookie是否存在以及对应的值是否正确

    C.如果是则退出循环并设置区别标识

    D.根据区别标识判断用户是否为初访者从而进行不同的操作

    八、使用cookie检测初访者的常见错误

    不能仅仅因为cookie数组中不存在在特定的数据项就认为用户是个初访者。如果cookie数组为null,客户可能是一个初访者,也可能是由于用户将cookie删除或禁用造成的结果。

    但是,如果数组非null,也不过是显示客户曾经到过你的网站或域,并不能说明他们曾经访问过你的servlet。其它servlet、JSP页面以及非JavaWeb应用都可以设置cookie,依据路径的设置,其中的任何cookie都有可能返回给用户的浏览器。

    正确的做法是判断cookie数组是否为空且是否存在指定的Cookie对象且值正确。

    展开全文
  •     先说一个前端开发中会遇到的问题,我们更新已...浏览器缓存是前端优化的一个重要问题,缓存可以带来很多好处: (1)减少冗余的数据传输,节省带宽; (2)减轻服务器的请求负担,有缓存...
  • memcache真实项目缓存实例

    千次阅读 2015-06-10 15:57:17
    memcache,缓存,优化,公司真实项目
  • 什么要使用缓存

    2021-06-24 07:12:18
    有什么好处?使用不当有什么后果? 分析 为什么使用,也就是说要回答出来使用缓存的优缺点就可以了。 项目中的缓存如何使用 这个需要结合自己的业务场景来说,没有的话哪怕硬加一个。 为什么使用缓存 主要是两方面,...
  • 很多人首先会想从服务器缓存方面着手程序进行优化,许多不同的服务器缓存方式都他们自己的特点,像我曾经参与的一些项目中,根据缓存的命中率不同使用过 Com+/Enterprise Libiary Caching/Windows服务,静态文件等...
  • Java电商项目面试--缓存(Guava Cache)

    千次阅读 2018-08-21 15:29:24
    面试题:手写LRU(今日头条面试题) 面试题:手撕LFU,要求get和put都为O(1) 一、Guava Cache适用场景 1、你愿意消耗一部分内存来提升速度;...整体上来说Guava cache 是本地缓存的不二之选,简单易用,...
  • 在WEB开发中用来应付高流量最有效的办法就是用缓存技术,能有效的提高服务器负载性能,用空间换取时间。 缓存一般用来 存储频繁访问的数据 临时存储耗时的计算结果 内存缓存减少磁盘IO 使用缓存的2个主要原因: ...
  • 目录 1、多级缓存 (一)集成Caffeine (二)Caffeine驱逐策略 ...分布式缓存一些数据是不适合存放在本地缓存的,比如登录凭证,这个数据和用户直接的关联,如一个请求访问A服务器凭证...
  • 总结新项目缓存处理

    千次阅读 2008-01-21 11:40:00
    其实静态页就是一种缓存处理,可以最大的降低服务器的负载,还有就是SEO上的好处。静态页处理属于永久缓存,对于信息的详细页面只有在数据修改时才进行更新和当模版修改时进行批量的更新,对于一级页面进行编辑...
  • 一、bug起因 最近做公司的项目样式进行了修改后,新版本上线。...其实浏览器缓存有好处的,第一次访问网站会从服务器获取静态的资源,然后将静态资源在游览器中缓存,下次用户在访问时,就直接获取...
  • } } 3.@Cacheable缓存注解的使用 (标注在service业务层方法上) 执行流程:先执行@Cacheable注解中的getCache(String name)方法,根据name判断ConcurrentMap中是否缓存,如果没有缓存那么创建缓存并保存数据,...
  • 这两天感冒了,十分的不在状态,结果今天一天迷迷糊糊,上周计划的做查询缓存的任务,今天竟然没有完成,下午又没有按时交任务,感觉自己都羞愧难当,就像组长说的 我或许真的不适合做技术,好多东西,非常简单,...
  • 什么缓存缓存,简单说就是为了节约原始资源重复获取的开销,而将结果数据副本存放起来以供获取的方式。 二.什么时候使用缓存 1.以 幂等和安全的方式资源的获取操作 2.缓存数据必须是重复获取的: 缓存...
  • Mybatis缓存

    千次阅读 多人点赞 2016-07-01 14:41:13
    三、Mybatis缓存 ...在数据库的一次会话中,我们可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库, 而我们在极短的时间内做了完全相同的查询,那么它们
  • 作为一名java程序员,关于缓存,求职面试时经常会遇到。张工是一名java程序员,最近到某知名互联网公司面试,面试官提出这样的一个问题:缓存穿透和缓存雪崩有什么区别?对于缓存,张工平时只...
  • 今天的 Python学习教程 绝对是纯技术的分享, 关于Django项目缓存优化问题的详细讲解! 一起来看看: 一、为什么要使用缓存 大家可以想一下Django的请求响应流程: ...
  • 缓存穿透:正常来说,一个合理设计的缓存命中率肯定是在50%以上,如果大量 的去避开缓存 ,就会因为 miss cache 造成DB的负载 缓存击穿:某一个高流量的 热点Key,在失效的一瞬间,造成的负载 缓存雪崩:很多...
  • Hibernate缓存策略(一级缓存、二级缓存

    万次阅读 多人点赞 2018-05-16 16:38:52
    缓存内的数据是物理数据源中的数据的复制,应用程序运行时先从缓存中读写数据。 缓存就是数据库数据在内存中的临时容器,包括数据库数据在内存中的临时拷贝,它位于数据库与数据库访问中间层,ORM在查询数据时,...
  • 利用客户端缓存对网站进行优化 - asp.net客户端缓存2008年05月29日 星期四 12:59基础知识 1) 什么是”Last-Modified”? 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时一...
  • 关于Redis的知识总结了一个脑图分享给...这就是看看你对缓存这个东西背后没有思考,如果你就是傻乎乎的瞎用,没法给面试官一个合理的解答,那面试官你印象肯定不太好,觉得你平时思考太少,就知道干活儿。 面试题
  • 有什么好处?相信不用说大家都知道。 目前笔者在做一个Java开发的Web项目项目启动的时候需要将大量不变的平台数据放入缓存中,方便快速读取。一开始笔者很疑惑,Java是不能直接操作内存的,但是我们缓存却是要...
  • 最近项目在做多工程之间的缓存及单点登录时用到redis,心得总结如下: Redis 三个主要使其别于其它很多竞争对手的特点: Redis是完全在内存中保存数据的数据库,使用磁盘只是为了持久性目的;  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 101,370
精华内容 40,548
关键字:

缓存对项目有什么好处