- 浏览: 50027 次
文章分类
最新评论
1. 缓存分类
1)Client Cache
在大型网站中,往往会考虑使用Client Cache,如京东网站,通过抓包可以看出它就设置了Cache: Cache-Control:max-age=120,其它的大型网站,如淘宝也都设置了Cache的值。它们都是通过Http 协议头中的字段来控制完成:Cache-Control,Expires,Last-Modified。
这样做的做的目的是减少数量传输,如果缓存有效的情况下,就不需要再次传输内容了。
2)Local JVM Cache
本地缓存是相对分布式缓存而言的,它是将Cache的内容存储在JVM中,如Tomcat中存储session。常用的框架有:Ehcache, ConcurrentHashMap, Guava Cache等。本地缓存的局限是受限于本地内存空间的大小。
它的特点是应用开发和cache在同一进程内部,请求缓存非常快速,缺点是多个应用开发程序无法直接共享缓存。
3)Distributed Cache
分布式缓存最大的特点是不受限单个缓存节点的限制,可以扩展缓存的容量。目前在生产环境上主要使用Memcache,Redis以及基于它们而自己研发的分布式缓存框架。阿里使用Tair分布式缓存框架,京东使用了JimDB分布式缓存框架。也有其它的一些开源分布式缓存框架,但大部分还没有真正应用于大规模的生产环境上。
目前,国内使用分布式缓存,基本上是在使用Redis(中国电信等公司),少数大型互联网公司是基于Redis重新开发一个框架或者自己完全开发一套分布式缓存框架(阿里的开源框架Tair)。
2. 缓存关注问题及解决策略
一般而言,我们主要关注缓存以下的问题。
1)缓存大小:内存空间大小有限,缓存不可能无限大;
2)淘汰算法:由1)中可知,有些缓存内容需被覆盖,需要一种淘汰机制来保证哪些被覆盖。一般用LRU算法来实现;
3)过期:缓存的内容什么时候过期。如Tomcat会开一个线程来监控session的过期。
用一句话来概括,即多久更新,如何更新。
解决策略:
在这里只讨论淘汰的策略。一般而言有两种策略:一是定时,到了一定的时间间隔,缓存就失效。它的优点是简单,缺点是灵活性不够;另一个是如果有更新操作时,需要判断是否引进缓存失效,它的优点是灵活,但是处理逻辑相对复杂。
在分布式缓存环境中,面临三个比较大的难题。
1)数据一致性。为了保证系统的高可用性,往往会有多个缓存副本,这样多个缓存副本可能就不一致了。还有为了尽量提高缓存命中率,缓存也是分层:全局缓存,二级缓存。他们是存在继承关系,需要考虑继承关系的缓存之间的一致性问题。另外还有缓存与数据库的一致性问题。
2)缓存雪崩。当缓存系统重启或者所有缓存在同一时刻失效(比如某些系统为了提高速度,会在系统启动是统一将大部分数据刷到缓存中,此时如果设置缓存时间都是24小时,那24小时过后,那就悲剧)时,应用系统由于扛不住压力而直接挂掉。
3)缓存穿透。查询一个必然不存在的数据,查询一个必然不存在的key,每次都会访问DB,如果有人恶意破坏,那么很可能直接对DB造成影响。
解决策略:
缓存雪崩和缓存穿透是从性能出发点考虑的,而数据一致性是数据的实时性和真实时,在这里讨论数据一致性的解决方法。而数据一致性又分为三种不同的情况,一般继承关系的缓存用得还不太多,暂时不去分析它。剩下的就是多个副本缓存的一致性和缓存与数据库的一致性问题了。
副本缓存的一致性问题可以由分布式缓存框架来解决,如Redis集群在牺牲性能的情况下可以保证数据的一致性,这个需要在性能和数据一致性之间进行权衡。
剩下讨论缓存与数据库的一致性问题。主要的策略如下:
1)Cache Miss Reload。数据在数据库中进行CUD操作时,将缓存设置成失效;
2)Update Then SetCache。在缓存的数据更新的同时也触发程序更新缓存;
3)Compensation Mechanism。有些时候缓存的更新不一定能够成功,也有可能会有脏数据进入缓存,如果要确保数据‘绝对’一致性,我们可以采取适当的补偿机制,如定时从数据库的值更新到缓存,或者在更新缓存失败时,插入失败日志,定时重新执行缓存更新等;
4)Reload(Rebuilt)All。有些查询对象的写远大于读,那么如果一定要缓存它的话,那可能就要以牺牲一部分的数据实时性为代价了,我们一般采用定时程序 Reload或Rebuilt所有的缓存。
3.缓存适用场景
缓存并不是一个系统中必须的,特别是写操作特别频繁时。我们希望缓存那些不经常变化且难得获取的数据。
1)主要缓存那些比较难得获取的数据,如查询数据库的记录、xml解析、远程获取IO数据等;
2)主要缓存那些以读为主的数据,数据不会变化得太频繁。
4.最基本的缓存设计思路
它的思想比较简单,一个请求过来,首先要缓存中查找,如果没有找到,再到数据库中去查询,然后将数据库中的结果存储在缓存,这样在后面如果再次查询想再的请求,就不必去数据库中查询了,直接到Cache中去取就行了。
这样设计思路适用的场景是数据变化不频繁,如果缓存的数据变化太变了,每次还是要从数据库中取最新的数据,这样系统的性能反而下降了,因为每次要到缓存中去查找,尽管查询Key-Value很快,但它毕竟还是要花时间的。
如果缓存中的数据有变化,可以参考数据一致性中的解决策略来做。
这个缓存设计还存在几个常见的问题,下面分别讨论这些常见的问题并提出相应的解决策略。
1)DB穿透问题分析
第一次缓存中没有数据,必定要穿透到DB层拿数据并更新缓存。如果并发量特别大的情况下,在这一秒,系统就撑不住了。
还有一个是有人恶意查询不存在的Key。
解决方案
假设数据量不太大,我们可以考虑在系统初始化的时候缓存数据。如果数据量比较多,初始化缓存会给后台带来一定的压力。
2)并发访问同一个缓存失效问题
有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,这也
可能造成DB压力过大。
解决方案
如果多个请求访问同一个缓存,如果Key不存在,就加锁,去获取DB的数据并入缓存,然后解锁,其它的进程发现有锁就等待,发现解锁后就返回缓存里的数据。
3)缓存失效问题(缓存雪崩)
在高并发情况下,应用中存在了大量的缓存,一般我们都会给这些缓存设置一个超时时
间(TTL),比如设置为一个小时。缓存建立好过了一个小时,这些缓存都会失效,于是这时候应用就必须重新建立各种各样的缓存。上边加锁只能解决一个缓存的重复建立问题,缓存雪崩则是各种不同的缓存重新建立。
解决方案
不让所有的缓存失效时间都设置成相同的值,可以按照随机值来生成,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
5.实时数据更新缓存的设计思路
一般而言,缓存策略是不支持实时更新的,如果一定要实现这样的功能,可以考虑异步更新的方式来实现。例如,统计不同页面的浏览量(这样的情景常在电商中出现,如商品的浏览量),那么可以这样来实现:请求过来将缓存中的数据进行修改(修改缓存中的数据比操作数据库还是要快的),然后异步更新到数据库中。
这种模式中,也要注意一个问题,就是第一次访问的问题,在缓存中肯定是不存在的,与第一种模式是相似的,解决方法可以提前加载数据,这可以解决一部分的问题。现在假设数据量非常大,不可能提前加载数据。又存在高并发的情况下,如何解决这个问题呢?
其实处理方式与加锁的方式是一样的,在开始多并发的情况下,只有一个请求去后台查询DB,其它的请求等待,这样只会有一个请求去后台查询DB,返回结果后加入缓存中,同时解锁,这样其它的请求马上可以返回结果。
1)Client Cache
在大型网站中,往往会考虑使用Client Cache,如京东网站,通过抓包可以看出它就设置了Cache: Cache-Control:max-age=120,其它的大型网站,如淘宝也都设置了Cache的值。它们都是通过Http 协议头中的字段来控制完成:Cache-Control,Expires,Last-Modified。
这样做的做的目的是减少数量传输,如果缓存有效的情况下,就不需要再次传输内容了。
2)Local JVM Cache
本地缓存是相对分布式缓存而言的,它是将Cache的内容存储在JVM中,如Tomcat中存储session。常用的框架有:Ehcache, ConcurrentHashMap, Guava Cache等。本地缓存的局限是受限于本地内存空间的大小。
它的特点是应用开发和cache在同一进程内部,请求缓存非常快速,缺点是多个应用开发程序无法直接共享缓存。
3)Distributed Cache
分布式缓存最大的特点是不受限单个缓存节点的限制,可以扩展缓存的容量。目前在生产环境上主要使用Memcache,Redis以及基于它们而自己研发的分布式缓存框架。阿里使用Tair分布式缓存框架,京东使用了JimDB分布式缓存框架。也有其它的一些开源分布式缓存框架,但大部分还没有真正应用于大规模的生产环境上。
目前,国内使用分布式缓存,基本上是在使用Redis(中国电信等公司),少数大型互联网公司是基于Redis重新开发一个框架或者自己完全开发一套分布式缓存框架(阿里的开源框架Tair)。
2. 缓存关注问题及解决策略
一般而言,我们主要关注缓存以下的问题。
1)缓存大小:内存空间大小有限,缓存不可能无限大;
2)淘汰算法:由1)中可知,有些缓存内容需被覆盖,需要一种淘汰机制来保证哪些被覆盖。一般用LRU算法来实现;
3)过期:缓存的内容什么时候过期。如Tomcat会开一个线程来监控session的过期。
用一句话来概括,即多久更新,如何更新。
解决策略:
在这里只讨论淘汰的策略。一般而言有两种策略:一是定时,到了一定的时间间隔,缓存就失效。它的优点是简单,缺点是灵活性不够;另一个是如果有更新操作时,需要判断是否引进缓存失效,它的优点是灵活,但是处理逻辑相对复杂。
在分布式缓存环境中,面临三个比较大的难题。
1)数据一致性。为了保证系统的高可用性,往往会有多个缓存副本,这样多个缓存副本可能就不一致了。还有为了尽量提高缓存命中率,缓存也是分层:全局缓存,二级缓存。他们是存在继承关系,需要考虑继承关系的缓存之间的一致性问题。另外还有缓存与数据库的一致性问题。
2)缓存雪崩。当缓存系统重启或者所有缓存在同一时刻失效(比如某些系统为了提高速度,会在系统启动是统一将大部分数据刷到缓存中,此时如果设置缓存时间都是24小时,那24小时过后,那就悲剧)时,应用系统由于扛不住压力而直接挂掉。
3)缓存穿透。查询一个必然不存在的数据,查询一个必然不存在的key,每次都会访问DB,如果有人恶意破坏,那么很可能直接对DB造成影响。
解决策略:
缓存雪崩和缓存穿透是从性能出发点考虑的,而数据一致性是数据的实时性和真实时,在这里讨论数据一致性的解决方法。而数据一致性又分为三种不同的情况,一般继承关系的缓存用得还不太多,暂时不去分析它。剩下的就是多个副本缓存的一致性和缓存与数据库的一致性问题了。
副本缓存的一致性问题可以由分布式缓存框架来解决,如Redis集群在牺牲性能的情况下可以保证数据的一致性,这个需要在性能和数据一致性之间进行权衡。
剩下讨论缓存与数据库的一致性问题。主要的策略如下:
1)Cache Miss Reload。数据在数据库中进行CUD操作时,将缓存设置成失效;
2)Update Then SetCache。在缓存的数据更新的同时也触发程序更新缓存;
3)Compensation Mechanism。有些时候缓存的更新不一定能够成功,也有可能会有脏数据进入缓存,如果要确保数据‘绝对’一致性,我们可以采取适当的补偿机制,如定时从数据库的值更新到缓存,或者在更新缓存失败时,插入失败日志,定时重新执行缓存更新等;
4)Reload(Rebuilt)All。有些查询对象的写远大于读,那么如果一定要缓存它的话,那可能就要以牺牲一部分的数据实时性为代价了,我们一般采用定时程序 Reload或Rebuilt所有的缓存。
3.缓存适用场景
缓存并不是一个系统中必须的,特别是写操作特别频繁时。我们希望缓存那些不经常变化且难得获取的数据。
1)主要缓存那些比较难得获取的数据,如查询数据库的记录、xml解析、远程获取IO数据等;
2)主要缓存那些以读为主的数据,数据不会变化得太频繁。
4.最基本的缓存设计思路
它的思想比较简单,一个请求过来,首先要缓存中查找,如果没有找到,再到数据库中去查询,然后将数据库中的结果存储在缓存,这样在后面如果再次查询想再的请求,就不必去数据库中查询了,直接到Cache中去取就行了。
这样设计思路适用的场景是数据变化不频繁,如果缓存的数据变化太变了,每次还是要从数据库中取最新的数据,这样系统的性能反而下降了,因为每次要到缓存中去查找,尽管查询Key-Value很快,但它毕竟还是要花时间的。
如果缓存中的数据有变化,可以参考数据一致性中的解决策略来做。
这个缓存设计还存在几个常见的问题,下面分别讨论这些常见的问题并提出相应的解决策略。
1)DB穿透问题分析
第一次缓存中没有数据,必定要穿透到DB层拿数据并更新缓存。如果并发量特别大的情况下,在这一秒,系统就撑不住了。
还有一个是有人恶意查询不存在的Key。
解决方案
假设数据量不太大,我们可以考虑在系统初始化的时候缓存数据。如果数据量比较多,初始化缓存会给后台带来一定的压力。
2)并发访问同一个缓存失效问题
有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,这也
可能造成DB压力过大。
解决方案
如果多个请求访问同一个缓存,如果Key不存在,就加锁,去获取DB的数据并入缓存,然后解锁,其它的进程发现有锁就等待,发现解锁后就返回缓存里的数据。
3)缓存失效问题(缓存雪崩)
在高并发情况下,应用中存在了大量的缓存,一般我们都会给这些缓存设置一个超时时
间(TTL),比如设置为一个小时。缓存建立好过了一个小时,这些缓存都会失效,于是这时候应用就必须重新建立各种各样的缓存。上边加锁只能解决一个缓存的重复建立问题,缓存雪崩则是各种不同的缓存重新建立。
解决方案
不让所有的缓存失效时间都设置成相同的值,可以按照随机值来生成,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
5.实时数据更新缓存的设计思路
一般而言,缓存策略是不支持实时更新的,如果一定要实现这样的功能,可以考虑异步更新的方式来实现。例如,统计不同页面的浏览量(这样的情景常在电商中出现,如商品的浏览量),那么可以这样来实现:请求过来将缓存中的数据进行修改(修改缓存中的数据比操作数据库还是要快的),然后异步更新到数据库中。
这种模式中,也要注意一个问题,就是第一次访问的问题,在缓存中肯定是不存在的,与第一种模式是相似的,解决方法可以提前加载数据,这可以解决一部分的问题。现在假设数据量非常大,不可能提前加载数据。又存在高并发的情况下,如何解决这个问题呢?
其实处理方式与加锁的方式是一样的,在开始多并发的情况下,只有一个请求去后台查询DB,其它的请求等待,这样只会有一个请求去后台查询DB,返回结果后加入缓存中,同时解锁,这样其它的请求马上可以返回结果。
发表评论
-
Java IO 读文件的各种方法总结
2016-01-01 15:00 667IO分为字节流和字符流,字符就是简单的字符串存储,从理伦上讲, ... -
动态代理的应用
2015-12-22 17:30 692代理模式作为开发人员 ... -
Java Restful
2015-12-19 14:01 399对于两个系统之间交互信息,有两种常见的方式:webservic ... -
request.getInputStream() 只能读一次的解决方法
2015-12-17 12:17 2297我们知道request.getInputStream()只能读 ... -
java Hessian 版本冲突问题解决方法
2015-12-11 19:44 821今天在实际的项目发现了一个问题就是hessian的版本不兼容的 ... -
ThreadPoolExecutor参数讲解
2015-12-10 08:14 7791. 线程池可以节省创建多个线程带来的开销问题。 2. 线程 ... -
Java RSA 加密 解密 签名 验签
2015-12-09 10:01 58751. 加密的作用 1)明文变密文(你不知道密钥是很难解密的) ... -
Java Xstream xml 与bean之间的转换
2015-12-09 08:31 695xml文件如下: <mvc> & ... -
XPATH 解析XML
2015-12-09 08:28 4011. 表达式描述 nodename 选取此节点的所有子节 ... -
Java Dom4j 解析XML
2015-12-09 08:23 330Dom4j和JDom是很相似的,用起来十分方便。 XML文件 ... -
Java JDom 解析xml
2015-12-09 08:22 364JDOM在解析XML在代码量之上比之前的方法(DOM和SAX要 ... -
Java SAX 解析xml
2015-12-08 18:13 365在上一篇中http://gaofulai1988.iteye. ... -
Java XML解析系列
2015-12-08 18:00 684Java解析XML有多种方式,因此需要分为几个不同的系列来讲。 ... -
Java 背包算法计算从数组中找若干个数使其最接近某个数
2015-12-08 17:38 1941背包的算法的动态方式如下: f(i,w) = max{ f(i ... -
C3P0 连接分析
2015-12-01 19:05 854最近在看C3P0的原理,还是将C3P0的源码导入到Ecplis ... -
微信开发的原理
2015-11-30 10:10 1279微信在现在的生活中,扮演着举足轻重的角色,现在怎么东西都在微信 ... -
JAVA Timestamp 与Data的转化以及BigDecimal 保留两位小数
2015-11-27 14:47 16041. BigDecimal 保留两位小数 今天在项目中遇到这 ... -
java try catch finally return 继续
2015-11-27 13:45 367之前在博客中有一篇文章讨论过异常中return值的情况,有兴趣 ... -
Java JDBC executeBatch 批量操作
2015-11-27 08:05 1552对JDBC 的 CRUD操作,我相信对于每个开发人员来讲,是十 ... -
Java WeakHashMap 分析
2015-11-26 08:17 581昨天在我们的系统中看 ...
相关推荐
JAVA缓存研究之剖析Jive的缓存机制JAVA缓存研究之剖析Jive的缓存机制
移动边缘网络中计算迁移与内容缓存研究综述_张开元.pdf
1. MySQL缓存概述 2. MySQL缓存研究内容与目的 3. MySQL缓存研究方法 4. MySQL缓存研究报告 5. MySQL缓存实验报告 6. 课题研究结论 7. 总结
大规模无线通信网络移动边缘计算和缓存研究.docx
众核处理器的共享一级指令缓存研究.pdf
移动边缘网络中计算迁移与内容缓存研究综述.pdf
安全技术-网络信息-LTE核心网络中协作式视频缓存研究.pdf
针对低电压下cache硬错误和软错误概率提高导致cache不能正常...基于EEMBC测试基准的实验结果表明,该设计可以在590 mV电压下正常运行,与该领域最新研究 VS-ECC相比,降低了23.6%的纠错码存储信息量,性能提高5.9%。
缓存技术作为提高系统性能的重要手段一直是研究的热点。随着网络存储等新技术的出现,存储的层次越来越复杂,原有的简单缓存管理技术已经不合适 日趋复杂的应用。频率和时间综合考虑的缓存替换方法、多级 缓存的替换...
网络技术-网络基础
因特网中日益增长的内容获取需求促使学术界提出了多种以信息为中心的未来...分析了缓存新特征对ICN研究带来的挑战;从多方面重点阐述了ICN缓存的优化方法,详细分析对比了不同缓存策略;指出了未来研究方向并总结全文。
简要介绍了路由器中缓存管理的发展过程,列举了缓存管理一些最主流的算法,并对它们的性质、优缺点作了较为深刻的比较研究。最后利用试验仿真对四种缓存管理算法进行了缓存利用率和分组丢失率方面的评价,并对缓存...
Hibernate是一种面向Java环境的ORM工具。系统地分析了Hibernate的缓存结构,并描述了二级缓存的查询过程、缓存策略;同时总结了二级缓存使用中的一些限制,以及使用二级缓存的优化策略。
GeoServer瓦片缓存机制研究 GIS数据组织结构
suqid 缓存服务器整理的相关内容,可以参考的。适合于centos7系统的
为提高P2P空间矢量数据索引网络的性能,在已有混合结构P2P空间索引网络的基础上,引入缓存机制,并提出了一种新的面向多图层的空间矢量数据缓存更新策略。该策略针对空间矢量数据多图层特性,综合考虑图层优先级以及...
NDN缓存机制研究,曾潇,高泽华,目前日益增长的用户规模和用户需求给互联网带来了巨大的挑战,内容本身越来越成为用户需求的中心,而且CDN,P2P等内容共享业务给网
基于Ad hoc网络的链路缓存算法研究,高彦,张薇,在Ad hoc网络中,缓存技术是制约按需路由协议性能的主要因素,怎样组织缓存结构并及时更新缓存信息是缓存技术目前的主要研究内容。
WWW缓存机制的研究与应用,李琳琳,熊前兴,针对现有www系统请求响应方式的局限性,提出了一种基于动态页面静态化的缓存解决方案,该方案在实现动态页面静态化时,其引擎的触
GeoServer瓦片缓存机制研究_阳华