- 浏览: 52792 次
文章分类
最新评论
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 693IO分为字节流和字符流,字符就是简单的字符串存储,从理伦上讲, ... -
动态代理的应用
2015-12-22 17:30 731代理模式作为开发人员 ... -
Java Restful
2015-12-19 14:01 437对于两个系统之间交互信息,有两种常见的方式:webservic ... -
request.getInputStream() 只能读一次的解决方法
2015-12-17 12:17 2376我们知道request.getInputStream()只能读 ... -
java Hessian 版本冲突问题解决方法
2015-12-11 19:44 861今天在实际的项目发现了一个问题就是hessian的版本不兼容的 ... -
ThreadPoolExecutor参数讲解
2015-12-10 08:14 8141. 线程池可以节省创建多个线程带来的开销问题。 2. 线程 ... -
Java RSA 加密 解密 签名 验签
2015-12-09 10:01 61441. 加密的作用 1)明文变密文(你不知道密钥是很难解密的) ... -
Java Xstream xml 与bean之间的转换
2015-12-09 08:31 744xml文件如下: <mvc> & ... -
XPATH 解析XML
2015-12-09 08:28 4321. 表达式描述 nodename 选取此节点的所有子节 ... -
Java Dom4j 解析XML
2015-12-09 08:23 363Dom4j和JDom是很相似的,用起来十分方便。 XML文件 ... -
Java JDom 解析xml
2015-12-09 08:22 414JDOM在解析XML在代码量之上比之前的方法(DOM和SAX要 ... -
Java SAX 解析xml
2015-12-08 18:13 417在上一篇中http://gaofulai1988.iteye. ... -
Java XML解析系列
2015-12-08 18:00 749Java解析XML有多种方式,因此需要分为几个不同的系列来讲。 ... -
Java 背包算法计算从数组中找若干个数使其最接近某个数
2015-12-08 17:38 1984背包的算法的动态方式如下: f(i,w) = max{ f(i ... -
C3P0 连接分析
2015-12-01 19:05 888最近在看C3P0的原理,还是将C3P0的源码导入到Ecplis ... -
微信开发的原理
2015-11-30 10:10 1314微信在现在的生活中,扮演着举足轻重的角色,现在怎么东西都在微信 ... -
JAVA Timestamp 与Data的转化以及BigDecimal 保留两位小数
2015-11-27 14:47 16951. BigDecimal 保留两位小数 今天在项目中遇到这 ... -
java try catch finally return 继续
2015-11-27 13:45 400之前在博客中有一篇文章讨论过异常中return值的情况,有兴趣 ... -
Java JDBC executeBatch 批量操作
2015-11-27 08:05 1627对JDBC 的 CRUD操作,我相信对于每个开发人员来讲,是十 ... -
Java WeakHashMap 分析
2015-11-26 08:17 619昨天在我们的系统中看 ...
相关推荐
JAVA缓存研究之剖析Jive的缓存机制JAVA缓存研究之剖析Jive的缓存机制
【众核处理器的共享一级指令缓存研究】 众核处理器是一种多核处理器的扩展形式,其特点是具有大量的处理核心(核心数远超传统的双核或四核),旨在提高芯片的并行处理能力和性能。在当前的技术背景下,众核处理器的...
MySQL 缓存研究 MySQL 缓存是数据库管理系统中至关重要的一部分,它主要目的是为了提高数据库的性能和响应速度。在数据库系统中,缓存扮演着数据高速存取的角色,通过临时存储频繁访问的数据,减少对磁盘I/O操作,...
### 大规模无线通信网络移动边缘计算和缓存研究 #### 一、引言与背景 随着5G无线通信技术的普及与应用,各种产业和服务迎来了显著的技术革新。但面对未来更高的技术要求,如Tbit/s级的数据传输速率、亚毫米级的...
基于联邦学习的高效边缘缓存研究 系统架构 在我们的系统模型中,中央服务器维护一个共享的全局模型。每个连接的用户都将基于本地训练数据集来计算从服务器下载的全局模型的更新,并将更新和推荐列表返回至服务器。...
在论文中,作者还指出了过去缓存研究的不足之处,特别是针对长短流的处理差异。长短流是指在网络中持续时间较长和较短的数据传输流,它们对缓存的需求和影响不同,因此需要特别考虑。作者提出,未来的研究应更深入地...
【密码嵌入式处理器中的高速缓存研究与设计】 在密码学领域,高效的数据处理是至关重要的,特别是在嵌入式系统中,处理器的性能直接影响着整个系统的运行效率。本文主要探讨了如何在密码嵌入式处理器中设计和实现...
总的来说,基于Hadoop的分布式缓存研究与实践,是对现有大数据处理技术的优化和改进,它充分利用了内存的优势,解决了传统Hadoop在处理大量数据时的性能瓶颈问题。这种技术的应用不仅提升了数据处理的效率,也为未来...
本文介绍了Web缓存的基本原理、关键技术以及常见的算法策略,希望能为从事Web缓存研究和开发的人员提供一定的参考和启示。在未来的工作中,还可以探索更多高效的缓存算法和技术,以满足不断变化的网络环境和用户需求...
在最近几年的研究中,缓存算法的研究热点集中在提升单级缓存的自适应能力以及多级缓存的整体性能上。这些研究不仅仅局限于算法的改进,也包括缓存算法的分类和对不同应用场景的适应性。尽管如此,缓存替换算法的研究...
总结了以往缓存研究的不足,并提出了下一步的研究方向。这表明路由器缓存需求的研究仍在不断发展之中,未来可能会有新的研究成果和更高效的缓存管理策略出现。 关键词路由器、缓存需求、TCP、排队论,揭示了论文...
### Hibernate缓存技术研究 #### 一、引言 Hibernate是一种强大的对象-关系映射(Object-Relational Mapping,简称ORM)工具,主要用于Java环境下的应用程序。它能够将应用程序中的对象模型映射到关系型数据库的表...
GeoServer 瓦片缓存机制研究 GeoServer 作为一个基于 Java 的开源 GIS 服务器,具有成本低廉、良好的扩展性和部署的灵活性等特点。但是,在面对庞大地图数据、庞大的用户交互时,如果仅仅采用 GeoServer 作为 GIS ...
因特网中日益增长的内容获取需求促使学术界提出了多种以信息为中心的未来...分析了缓存新特征对ICN研究带来的挑战;从多方面重点阐述了ICN缓存的优化方法,详细分析对比了不同缓存策略;指出了未来研究方向并总结全文。
### Squid 缓存服务器研究 #### 一、Squid 概述 Squid 是一款广泛应用于互联网数据缓存的开源软件。其主要功能是接收来自客户端的请求,并根据请求内容,从远程服务器获取数据后缓存至本地。当下次再次请求相同的...
分布式数据缓存技术研究[J]. 计算机应用与软件, 2011, 28(6): 1-8. [2] Redis官方文档. https://redis.io/ [3] Memcached官方文档. https://memcached.org/ [4] Hadoop HBase官方文档. ...