当前位置:首页 » 硬盘大全 » 分布式场景协商缓存使用
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

分布式场景协商缓存使用

发布时间: 2023-08-18 05:04:52

‘壹’ ☆前端优化:浏览器缓存技术介绍

在前端开发中,性能一直都是被大家所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。 其中提高网页反应速度的一个方式就是使用缓存 。缓存技术一直一来在WEB技术体系中扮演非常重要角色,是快速且有效地提升性能的手段。

一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。

所以,缓存技术是无数WEB开发从业人员在工作过程中不可避免的一大问题。 在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度 。了解浏览器的缓存命中原理,是开发WEB应用的基础,本文着眼于此,学习浏览器缓存的相关知识,总结缓存避免和缓存管理的方法,结合具体的场景说明缓存的相关问题。希望能对有需要的人有所帮助。

在实际WEB开发过程中,缓存技术会涉及到不同层、不同端,比如:用户层、系统层、代理层、前端、后端、服务端等, 每一层的缓存目标都是一致的,就是尽快返回请求数据、减少延迟 ,但每层使用的技术实现是各有不同,面对不同层、不同端的优劣,选用不同的技术来提升系统响应效率。所以,我们首先看下各层的缓存都有哪些技术,都缓存哪些数据,从整体上,对WEB的缓存技术进行了解,如下图所示:

本篇文章重点讲的就是上面红色框部分缓存内容。

当浏览器请求一个网站的时候,会加载各种各样的资源,比如:HTML文档、图片、CSS和JS等文件。对于一些不经常变的内容,浏览器会将他们保存在本地的文件中,下次访问相同网站的时候,直接加载这些资源,加速访问。

那么如何知晓浏览器是读取了缓存还是直接请求服务器?如下图网站来做个示例:

第一次打开该网站后,如果再次刷新页面。会发现浏览器加载的众多资源中,有一部分size有具体数值,然而还有一部分请求,比如图片、css和js等文件并没有显示文件大小,而是显示了 from dis cache 或者 from memory cache 字样。这就说明了,该资源直接从本地硬盘或者浏览器内存读取,而并没有请求服务器。

浏览器启用缓存至少有两点显而易见的好处: (1)减少页面加载时间;(2)减少服务器负载;

浏览器是否使用缓存、缓存多久,是由服务器控制的 。准确来说,当浏览器请求一个网页(或者其他资源)时, 服务器发回的响应的“响应头”部分的某些字段指明了有关缓存的关键信息 。下面看下,HTTP报文中与缓存相关的首部字段:

根据上面四种类型的首部字段不同使用策略, 浏览器中缓存可分为强缓存和协商缓存

当浏览器对某个资源的请求命中了强缓存时, 返回的HTTP状态为200 ,在chrome的开发者工具的network里面 size会显示为from cache ,比如:京东的首页里就有很多静态资源配置了强缓存,用chrome打开几次,再用f12查看network,可以看到有不少请求就是从缓存中加载的:

Expires是HTTP 1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示 ,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,包含了Expires头标签的文件,就说明浏览器对于该文件缓存具有非常大的控制权。

例如,一个文件的Expires值是2020年的1月1日,那么就代表,在2020年1月1日之前,浏览器都可以直接使用该文件的本地缓存文件,而不必去服务器再次请求该文件,哪怕服务器文件发生了变化。

所以, Expires是优化中最理想的情况,因为它根本不会产生请求 ,所以后端也就无需考虑查询快慢。它的缓存原理,如下:

Expires是较老的强缓存管理header, 由于它是服务器返回的一个绝对时间 ,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题, 比如:随意修改下客户端时间,就能影响缓存命中的结果 。所以在HTTP 1.1的时候,提出了一个新的header, 就是Cache-Control,这是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示 ,如:Cache-Control:max-age=315360000,它的缓存原理是:

Cache-Control描述的是一个相对时间 ,在进行缓存命中的时候, 都是利用客户端时间进行判断 ,所以相比较Expires,Cache-Control的缓存管理更有效,安全一些。

这两个header可以只启用一个,也可以同时启用, 当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires

此外,还可以为 Cache-Control 指定 public 或 private 标记。 如果使用 private,则表示该资源仅仅属于发出请求的最终用户,这将禁止中间服务器(如代理服务器)缓存此类资源 。对于包含用户个人信息的文件(如一个包含用户名的 HTML 文档),可以设置 private,一方面由于这些缓存对其他用户来说没有任何意义,另一方面用户可能不希望相关文件储存在不受信任的服务器上。需要指出的是,private 并不会使得缓存更加安全,它同样会传给中间服务器(如果网站对于传输的安全性要求很高,应该使用传输层安全措施)。 对于 public,则允许所有服务器缓存该资源 。通常情况下,对于所有人都可以访问的资源(例如网站的 logo、图片、脚本等), Cache-Control 默认设为 public 是合理的

当浏览器对某个资源的请求没有命中强缓存, 就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串 ,比如你打开京东的首页,按f12打开开发者工具,再按f5刷新页面,查看network,可以看到有不少请求就是命中了协商缓存的:

查看单个请求的Response Header, 也能看到304的状态码和Not Modified的字符串,只要看到这个就可说明这个资源是命中了协商缓存,然后从客户端缓存中加载的 ,而不是服务器最新的资源:

【Last-Modified,If-Modified-Since】的控制缓存的原理,如下

【Last-Modified,If-Modified-Since】都是根据服务器时间返回的header,一般来说, 在没有调整服务器时间和篡改客户端缓存的情况下,这两个header配合起来管理协商缓存是非常可靠的,但是有时候也会服务器上资源其实有变化,但是最后修改时间却没有变化的情况 ,而这种问题又很不容易被定位出来,而当这种情况出现的时候,就会影响协商缓存的可靠性。 所以就有了另外一对header来管理协商缓存,这对header就是【ETag、If-None-Match】 。它们的缓存管理的方式是:

Etag和Last-Modified非常相似,都是用来判断一个参数,从而决定是否启用缓存。 但是ETag相对于Last-Modified也有其优势,可以更加准确的判断文件内容是否被修改 ,从而在实际操作中实用程度也更高。

协商缓存跟强缓存不一样,强缓存不发请求到服务器, 所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器 ,所以资源是否更新,服务器肯定知道。大部分web服务器都默认开启协商缓存,而且是同时启用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,比如apache:

如果没有协商缓存,每个到服务器的请求,就都得返回资源内容,这样服务器的性能会极差。

【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】一般都是同时启用,这是为了处理Last-Modified不可靠的情况。有一种场景需要注意:

比如,京东页面的资源请求,返回的repsonse header就只有Last-Modified,没有ETag:

协商缓存需要配合强缓存使用,上面这个截图中,除了Last-Modified这个header,还有强缓存的相关header, 因为如果不启用强缓存的话,协商缓存根本没有意义

如果资源已经被浏览器缓存下来,在缓存失效之前,再次请求时,默认会先检查是否命中强缓存,如果强缓存命中则直接读取缓存,如果强缓存没有命中则发请求到服务器检查是否命中协商缓存,如果协商缓存命中,则告诉浏览器还是可以从缓存读取,否则才从服务器返回最新的资源。其浏览器判断缓存的详细流程图,如下:

‘贰’ JAVA目前比较常用的缓存有哪些 集中式缓存与分布式缓存有何区别 它们应用场景是

java目前常用的缓存:
Generic
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, etc)
EhCache 2.x
Hazelcast
Infinispan
Couchbase
Redis
Caffeine
Guava (deprecated)
Simple
建议使用spring boot集成方式,可插拔,简单。
集中式缓存适用场景:
1、服务器集群部署。
2、数据高一致性(任何数据变化都能及时的被查询到)

分布式缓存适用场景:
系统需要缓存的数据量大
对数据的可用性较高的情况

需要横向扩展,从而达到缓存的容量无限的要求

‘叁’ 缓存系统中的主要使用的数据结构是什么

缓存系统中的主要使用的数据结构是memcached。

memcached是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但被许多网站使用。这是一套开放源代码软件,以BSD license授权发布。

memcached的API使用三十二比特的循环冗余校验(CRC-32)计算键值后,将数据分散在不同的机器上。当表格满了以后,接下来新增的数据会以LRU机制替换掉。

由于memcached通常只是当作缓存系统使用,所以使用memcached的应用程序在写回较慢的系统时(像是后端的数据库)需要额外的代码更新memcached内的数据。

(3)分布式场景协商缓存使用扩展阅读:

一、存储方式

为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。

另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。

二、通信分布式

memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。本文也将介绍memcached的分布式。

‘肆’ EhCache 分布式缓存/缓存集群

一 缓存系统简介 EhCache 是一个纯 Java 的进程内缓存框架 具有快速 精干等特点 是 Hibernate 中默认的 CacheProvider EhCache 应用架构图 下图是 EhCache 在应用程序中的位置

EhCache 的主要特性有 快速 精干 简单 多种缓存策略 缓存数据有两级 内存和磁盘 因此无需担心容量问题 缓存数据会在虚拟机重启的过程中写入磁盘 可以通过 RMI 可插入 API 等方式进行分布式缓存 具有缓存和缓存管理器的侦听接口 支持多缓存管理器实例 以及一个实例的多个缓存区域 提供 Hibernate 的缓存实现 由于 EhCache 是进程中的缓存系统 一旦将应用部署在集群环境中 每一个节点维护各自的缓存数据 当某个节点对缓存数据进行更新 这些更新的数据无法在其它节点 *** 享 这不仅会降低节点运行的效率 而且会导致数据不同步的情况发生 例如某个网站采用 A B 两个节点作为集群部署 当 A 节点的缓存更新后 而 B 节点缓存尚未更新就可能出现用户在浏览页面的时候 一会是更新后的数据 一会是尚未更新的数据 尽管我们也可以通过 Session Sticky 技术来将用户锁定在某个节点上 但对于一些交互性比较强或者是非 Web 方式的系统来说 Session Sticky 显然不太适合 所以就需要用到 EhCache 的集群解决方案 从 版本开始 Ehcache可以使用分布式的缓存了 EhCache 从 版本开始 支持五种集群方案 分别是 ? Terracotta ? RMI ? JMS ? JGroups ? EhCache Server 其中的三种最为常用集群方式 分别是 RMI JGroups 以及 EhCache Server 本文主要介绍RMI的方式 分布式这个特性是以plugin的方式实现的 Ehcache自带了一些默认的分布式缓存插件实现 这些插件可以满足大部分应用的需要 如果需要使用其他的插件那就需要自己开发了 开发者可以通过查看distribution包里的源代码及JavaDoc来实现它 尽管不是必须的 在使用分布式缓存时理解一些ehcahce的设计思想也是有帮助的 这可以参看分布式缓存设计的页面 以下的部分将展示如何让分布式插件同ehcache一起工作 下面列出的是一些分布式缓存中比较重要的方面 ? 你如何知道集群环境中的其他缓存? ? 分布式传送的消息是什么形式? ? 什么情况需要进行复制?增加(Puts) 更新(Updates)或是失效(Expiries)? ? 采用什么方式进行复制?同步还是异步方式? 为了安装分布式缓存 你需要配置一个PeerProvider 一个CacheManagerPeerListener 它们对于一个CacheManager来说是全局的 每个进行分布式操作的cache都要添加一个cacheEventListener来传送消息

二 集群缓存概念及其配置 正确的元素类型 只有可序列化的元素可以进行复制 一些操作 比如移除 只需要元素的键值而不用整个元素 在这样的操作中即使元素不是可序列化的但键值是可序列化的也可以被复制 成员发现(Peer Discovery) Ehcache进行集群的时候有一个cache组的概念 每个cache都是其他cache的一个peer 没有主cache的存在 刚才我们问了一个问题 你如何知道集群环境中的其他缓存?这个问题可以命名为成员发现(Peer Discovery) Ehcache提供了两种机制用来进行成员发现 就像一辆汽车 手动档和自动档 要使用一个内置的成员发现机制要在ehcache的配置文件中指定元素的class属性为 net sf ehcache distribution 自动的成员发现 自动的发现方式用TCP广播机制来确定和维持一个广播组 它只需要一个简单的配置可以自动的在组中添加和移除成员 在集群中也不需要什么优化服务器的知识 这是默认推荐的 成员每秒向群组发送一个 心跳 如果一个成员 秒种都没有发出信号它将被群组移除 如果一个新的成员发送了一个 心跳 它将被添加进群组 任何一个用这个配置安装了复制功能的cache都将被其他的成员发现并标识为可用状态 要设置自动的成员发现 需要指定ehcache配置文件中元素的properties属性 就像下面这样 peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port timeToLive= (timeToLive属性详见常见问题部分的描述) 示例 假设你在集群中有两台服务器 你希望同步sampleCache 和sampleCache 每台独立的服务器都要有这样的配置 配置server 和server <class= net sf ehcache distribution properties= peerDiscovery=automatic multicastGroupAddress= />multicastGroupPort= timeToLive= 手动进行成员发现 进行手动成员配置要知道每个监听器的IP地址和端口 成员不能在运行时动态地添加和移除 在技术上很难使用广播的情况下就可以手动成员发现 例如在集群的服务器之间有一个不能传送广播报文的路由器 你也可以用手动成员发现进行单向的数据复制 只让server 知道server 而server 不知道server 配置手动成员发现 需要指定ehcache配置文件中的properties属性 像下面这样 peerDiscovery=manual rmiUrls=//server:port/cacheName //server:port/cacheName … rmiUrls配置的是服务器cache peers的列表 注意不要重复配置 示例 假设你在集群中有两台服务器 你要同步sampleCache 和sampleCache 下面是每个服务器需要的配置 配置server <class= net sf ehcache distribution properties= peerDiscovery=manual />rmiUrls=//server : /sampleCache |//server : /sampleCache 配置server <class= net sf ehcache distribution properties= peerDiscovery=manual />rmiUrls=//server : /sampleCache |//server : /sampleCache 配置CacheManagerPeerListener 每个CacheManagerPeerListener监听从成员们发向当前CacheManager的消息 配置CacheManagerPeerListener需要指定一个 它以插件的机制实现 用来创建CacheManagerPeerListener 的属性有 class – 一个完整的工厂类名 properties – 只对这个工厂有意义的属性 使用逗号分隔 Ehcache有一个内置的基于RMI的分布系统 它的监听器是RMICacheManagerPeerListener 这个监听器可以用 RMI来配置 <class= net sf ehcache distribution RMI properties= hostName=localhost port= />socketTimeoutMillis= 有效的属性是 hostname (可选) – 运行监听器的服务器名称 标明了做为集群群组的成员的地址 同时也是你想要控制的从集群中接收消息的接口

在CacheManager初始化的时候会检查hostname是否可用 如果hostName不可用 CacheManager将拒绝启动并抛出一个连接被拒绝的异常 如果指定 hostname将使用InetAddress getLocalHost() getHostAddress()来得到 警告 不要将localhost配置为本地地址 因为它在网络中不可见将会导致不能从远程服务器接收信息从而不能复制 在同一台机器上有多个CacheManager的时候 你应该只用localhost来配置 port – 监听器监听的端口 socketTimeoutMillis (可选) – Socket超时的时间 默认是 ms 当你socket同步缓存请求地址比较远 不是本地局域网 你可能需要把这个时间配置大些 不然很可能延时导致同步缓存失败 配置CacheReplicators 每个要进行同步的cache都需要设置一个用来向CacheManagerr的成员复制消息的缓存事件监听器 这个工作要通过为每个cache的配置增加一个cacheEventListenerFactory元素来完成 <! Sample cache named sampleCache ><cache name= sampleCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false ><cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true /></cache>class – 使用net sf ehcache distribution RMICacheReplicatorFactory 这个工厂支持以下属性 replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers 默认是true replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制 默认是true replicateRemovals= true | false – 当元素移除的时候是否进行复制 默认是true replicateAsynchronously=true | false – 复制方式是异步的(指定为true时)还是同步的(指定为false时) 默认是true replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制指定为true时为复制 默认是true replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制(指定为true时为复制) 默认是true 你可以使用ehcache的默认行为从而减少配置的工作量 默认的行为是以异步的方式复制每件事 你可以像下面的例子一样减少RMICacheReplicatorFactory的属性配置 <! Sample cache named sampleCache All missing RMICacheReplicatorFactory properties default to true ><cache name= sampleCache maxElementsInMemory= eternal= true overflowToDisk= false memoryStoreEvictionPolicy= LFU ><cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory /></cache> 常见的问题 Windows上的Tomcat 有一个Tomcat或者是JDK的bug 在tomcat启动时如果tomcat的安装路径中有空格的话 在启动时RMI监听器会失败 参见 bin/wa?A =ind &L=rmi users&P= 和 doc/faq howto bugs/l 由于在Windows上安装Tomcat默认是装在 Program Files 文件夹里的 所以这个问题经常发生 广播阻断 自动的peer discovery与广播息息相关 广播可能被路由阻拦 像Xen和VMWare这种虚拟化的技术也可以阻拦广播 如果这些都打开了 你可能还在要将你的网卡的相关配置打开 一个简单的办法可以告诉广播是否有效 那就是使用ehcache remote debugger来看 心跳 是否可用 广播传播的不够远或是传得太远 你可以通过设置badly misnamed time to live来控制广播传播的距离 用广播IP协议时 timeToLive的值指的是数据包可以传递的域或是范围 约定如下 是限制在同一个服务器 是限制在同一个子网 是限制在同一个网站 是限制在同一个region 是限制在同一个大洲 是不限制 译者按 上面这些资料翻译的不够准确 请读者自行寻找原文理解吧 在Java实现中默认值是 也就是在同一个子网中传播 改变timeToLive属性可以限制或是扩展传播的范围

三 RMI方式缓存集群/配置分布式缓存 RMI 是 Java 的一种远程方法调用技术 是一种点对点的基于 Java 对象的通讯方式 EhCache 从 版本开始就支持 RMI 方式的缓存集群 在集群环境中 EhCache 所有缓存对象的键和值都必须是可序列化的 也就是必须实现 java io Serializable 接口 这点在其它集群方式下也是需要遵守的 下图是 RMI 集群模式的结构图

采用 RMI 集群模式时 集群中的每个节点都是对等关系 并不存在主节点或者从节点的概念 因此节点间必须有一个机制能够互相认识对方 必须知道其它节点的信息 包括主机地址 端口号等 EhCache 提供两种节点的发现方式 手工配置和自动发现 手工配置方式要求在每个节点中配置其它所有节点的连接信息 一旦集群中的节点发生变化时 需要对缓存进行重新配置 由于 RMI 是 Java 中内置支持的技术 因此使用 RMI 集群模式时 无需引入其它的 Jar 包 EhCache 本身就带有支持 RMI 集群的功能 使用 RMI 集群模式需要在 ehcache xml 配置文件中定义 节点 分布式同步缓存要让这边的cache知道对方的cache 叫做Peer Discovery(成员发现) EHCache实现成员发现的方式有两种 手动查找 A 在ehcache xml中配置PeerDiscovery成员发现对象 Server 配置 配置本地hostName port是 分别监听 : 的mobileCache和 : 的mobileCache 注意这里的mobileCache是缓存的名称 分别对应着server server 的cache的配置 <?xml version= encoding= gbk ?><ehcache xmlns:xsi= instance xsi:noNamespaceSchemaLocation= ehcache xsd > <diskStore path= java io tmpdir /> <! 集群多台服务器中的缓存 这里是要同步一些服务器的缓存 server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache 注意 每台要同步缓存的服务器的RMI通信socket端口都不一样 在配置的时候注意设置 > <! server 的配置 > < class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache /></ehcache>以上注意元素出现的位置在diskStore下

同样在你的另外 台服务器上增加配置 Server 配置本地host port为 分别同步 : 的mobileCache和 : 的mobileCache <! server 的配置 >< class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache />Server 配置本地host port为 分别同步 : 的mobileCache缓存和 : 的mobileCache缓存 <! server 的配置 >< class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache />这样就在三台不同的服务器上配置了手动查找cache的PeerProvider成员发现的配置了 值得注意的是你在配置rmiUrls的时候要特别注意url不能重复出现 并且端口 地址都是对的 如果指定 hostname将使用InetAddress getLocalHost() getHostAddress()来得到 警告 不要将localhost配置为本地地址 因为它在网络中不可见将会导致不能从远程服务器接收信息从而不能复制 在同一台机器上有多个CacheManager的时候 你应该只用localhost来配置 B 下面配置缓存和缓存同步监听 需要在每台服务器中的ehcache xml文件中增加cache配置和cacheEventListenerFactory cacheLoaderFactory的配置 <defaultCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false /><! 配置自定义缓存 maxElementsInMemory:缓存中允许创建的最大对象数 eternal:缓存中对象是否为永久的 如果是 超时设置将被忽略 对象从不过期 timeToIdleSeconds:缓存数据空闲的最大时间 也就是说如果有一个缓存有多久没有被访问就会被销毁 如果该值是 就意味着元素可以停顿无穷长的时间 timeToLiveSeconds:缓存数据存活的时间 缓存对象最大的的存活时间 超过这个时间就会被销毁 这只能在元素不是永久驻留时有效 如果该值是 就意味着元素可以停顿无穷长的时间 overflowToDisk:内存不足时 是否启用磁盘缓存 memoryStoreEvictionPolicy:缓存满了之后的淘汰算法 每一个小时更新一次缓存( 小时过期) ><cache name= mobileCache maxElementsInMemory= eternal= false overflowToDisk= true timeToIdleSeconds= timeToLiveSeconds= memoryStoreEvictionPolicy= LFU > <! RMI缓存分布同步查找 class使用net sf ehcache distribution RMICacheReplicatorFactory 这个工厂支持以下属性 replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers 默认是true replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制 默认是true replicateRemovals= true | false – 当元素移除的时候是否进行复制 默认是true replicateAsynchronously=true | false – 复制方式是异步的 指定为true时 还是同步的 指定为false时 默认是true replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制 默认是true replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制 默认是true = > <! 监听RMI同步缓存对象配置 注册相应的的缓存监听类 用于处理缓存事件 如put remove update 和expire > <cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true /> replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true <! 用于在初始化缓存 以及自动设置 > <bootstrapCacheLoaderFactory class= net sf ehcache bootstrap BootstrapCacheLoaderFactory /></cache> C 这样就完成了 台服务器的配置 下面给出server 的完整的ehcache xml的配置 <?xml version= encoding= gbk ?><ehcache xmlns:xsi= instance xsi:noNamespaceSchemaLocation= ehcache xsd > <diskStore path= java io tmpdir /> <!

集群多台服务器中的缓存 这里是要同步一些服务器的缓存 server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache server hostName: port: cacheName:mobileCache 注意每台要同步缓存的服务器的RMI通信socket端口都不一样 在配置的时候注意设置 > <! server 的配置 > < class= net sf ehcache distribution properties= hostName=localhost port= socketTimeoutMillis= peerDiscovery=manual rmiUrls=// : /mobileCache|// : /mobileCache /> <defaultCache maxElementsInMemory= eternal= false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk= false /> <! 配置自定义缓存 maxElementsInMemory:缓存中允许创建的最大对象数 eternal:缓存中对象是否为永久的 如果是 超时设置将被忽略 对象从不过期 timeToIdleSeconds:缓存数据空闲的最大时间 也就是说如果有一个缓存有多久没有被访问就会被销毁 如果该值是 就意味着元素可以停顿无穷长的时间 timeToLiveSeconds:缓存数据存活的时间 缓存对象最大的的存活时间 超过这个时间就会被销毁 这只能在元素不是永久驻留时有效 如果该值是 就意味着元素可以停顿无穷长的时间 overflowToDisk:内存不足时 是否启用磁盘缓存 memoryStoreEvictionPolicy:缓存满了之后的淘汰算法 每一个小时更新一次缓存( 小时过期) > <cache name= mobileCache maxElementsInMemory= eternal= false overflowToDisk= true timeToIdleSeconds= timeToLiveSeconds= memoryStoreEvictionPolicy= LFU > <! RMI缓存分布同步查找 class使用net sf ehcache distribution RMICacheReplicatorFactory 这个工厂支持以下属性 replicatePuts=true | false – 当一个新元素增加到缓存中的时候是否要复制到其他的peers 默认是true replicateUpdates=true | false – 当一个已经在缓存中存在的元素被覆盖时是否要进行复制 默认是true replicateRemovals= true | false – 当元素移除的时候是否进行复制 默认是true replicateAsynchronously=true | false – 复制方式是异步的 指定为true时 还是同步的 指定为false时 默认是true replicatePutsViaCopy=true | false – 当一个新增元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制 默认是true replicateUpdatesViaCopy=true | false – 当一个元素被拷贝到其他的cache中时是否进行复制 指定为true时为复制 默认是true = > <! 监听RMI同步缓存对象配置 注册相应的的缓存监听类 用于处理缓存事件 如put remove update 和expire > <cacheEventListenerFactory class= net sf ehcache distribution RMICacheReplicatorFactory properties= replicateAsynchronously=true /> replicatePuts=true replicateUpdates=true replicateUpdatesViaCopy=false replicateRemovals=true <! 用于在初始化缓存 以及自动设置 > <bootstrapCacheLoaderFactory class= net sf ehcache bootstrap BootstrapCacheLoaderFactory /> </cache></ehcache> 自动发现 自动发现配置和手动查找的方式有一点不同 其他的地方都基本是一样的 同样在ehcache xml中增加配置 配置如下 <! 搜索某个网段上的缓存timeToLive 是限制在同一个服务器 是限制在同一个子网 是限制在同一个网站 是限制在同一个region 是限制在同一个大洲 是不限制 >< class= net sf ehcache distribution properties= peerDiscovery=automatic multicastGroupAddress= multicastGroupPort= timeToLive= /> lishixin/Article/program/Java/hx/201311/25706

‘伍’ 描述一下hadoop中,有那些地方使用了缓存机制,分别有什么作用

描述一下
hadoop
中,有哪些地方使用到了缓存机制,作用分别是什么?

答:
缓存机制就是
DistributedCash

就是在
job
任务执行前,将需要的文件拷贝到
Task
机器
上进行缓存,提高
maprece
的执行效率。

‘陆’ 分布式存储最佳缓存比

作者:深入细节的 SmartX 一线技术团队

近日,VMware 发布了 vSAN 8,对存储架构进行了重大更新。其中最主要的变化,即引入了新的 Express Storage Architecture(ESA)架构:用“存储池”替代了原存储架构(OSA)中的“磁盘组”,并不再需要专用 SSD 承担缓存加速功能,一定程度上避免了 8.0 之前版本中的专用缓存盘利用率低、易发生缓存击穿等问题。
而值得一提的是,在 vSAN 大版本更新之前,SmartX 即通过统一缓存空间和智能冷热数据管理优化了分布式存储缓存机制,有效规避了上述问题。本文将通过重点解读 vSAN(以 vSAN 7 为例)和 SmartX 分布式块存储组件 ZBS* 缓存机制的原理,并测试对比两种缓存机制下虚拟机性能表现,让读者更好地了解两种技术实现机制的区别对业务可能带来的实际影响。

* ZBS 内置于 SmartX 超融合软件 SMTX OS,可与 SmartX 原生虚拟化 ELF 搭配提供服务。

本文重点
vSAN 7 采用划分读写缓存空间的机制,将缓存磁盘按照容量占比划分为写缓冲区(30%)和读缓存区(70%)。这种方式可能出现缓存利用率低、在访问数据量过大时导致缓存击穿,进而引起性能下降等问题。
ZBS 采用统一缓存空间的机制,并通过 2 级 LRU 算法对冷热数据进行管理,在充分利用缓存容量的同时避免了因访问量激增导致虚拟机性能下降的情况。
本文基于相同的硬件配置和 I/O 读写场景,分别测试 VMware 超融合(vSphere 虚拟化 + vSAN 分布式存储)写入 300 GB 数据、SMTX OS(ELF + ZBS)写入 500 GB 数据时虚拟机的性能表现。结果显示,vSAN 7 难以充分利用缓存介质,发生缓存击穿,导致存储性能下降;而 SMTX OS 即便在写入更多数据的情况下也未发生缓存击穿,虚拟机性能保持稳定。
场景问题
混闪配置是超融合或分布式存储现阶段的主流落地模式。混闪配置是指机器中的磁盘使用 SSD + HDD 混合组成,其中 SSD 磁盘作为数据缓存层,而 HDD 磁盘作为数据容量层。以该模式构建的分布式存储池通过软件算法进行冷热数据自动判断,在提供高性能的同时,还可获得较大的存储容量,进而提升资源利用率,获得相对全闪存储更高的性价比。

在将 SSD 磁盘用作数据缓存层时,部分超融合产品会将缓存容量(Cache)划分为读和写各自独立的两部分。例如,vSAN 7 及更早版本会将每个磁盘组(Disk Group)中的缓存磁盘,按照容量占比划分为写缓冲区(30%)和读缓存区(70%),当读取数据未命中缓存或者写缓存已满,将会直接从容量层进行读写。

‘柒’ 华为技术架构师分享:高并发场景下缓存处理的一些思路

在实际的开发当中,我们经常需要进行磁盘数据的读取和搜索,因此经常会有出现从数据库读取数据的场景出现。但是当数据访问量次数增大的时候,过多的磁盘读取可能会最终成为整个系统的性能瓶颈,甚至是压垮整个数据库,导致系统卡死等严重问题。

常规的应用系统中,我们通常会在需要的时候对数据库进行查找,因此系统的大致结构如下所示:

1.缓存和数据库之间数据一致性问题

常用于缓存处理的机制我总结为了以下几种:

首先来简单说说Cache aside的这种方式:

Cache Aside模式

这种模式处理缓存通常都是先从数据库缓存查询,如果缓存没有命中则从数据库中进行查找。

这里面会发生的三种情况如下:

缓存命中:

当查询的时候发现缓存存在,那么直接从缓存中提取。

缓存失效:

当缓存没有数据的时候,则从database里面读取源数据,再加入到cache里面去。

缓存更新:

当有新的写操作去修改database里面的数据时,需要在写操作完成之后,让cache里面对应的数据失效。

关于这种模式下依然会存在缺陷。比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。

Facebook的大牛们也曾经就缓存处理这个问题发表过相关的论文,链接如下:

分布式环境中要想完全的保证数据一致性是一件极为困难的事情,我们只能够尽可能的减低这种数据不一致性问题产生的情况。

Read Through模式

Read Through模式是指应用程序始终从缓存中请求数据。 如果缓存没有数据,则它负责使用底层提供程序插件从数据库中检索数据。 检索数据后,缓存会自行更新并将数据返回给调用应用程序。使用Read Through 有一个好处。

我们总是使用key从缓存中检索数据, 调用的应用程序不知道数据库, 由存储方来负责自己的缓存处理,这使代码更具可读性, 代码更清晰。但是这也有相应的缺陷,开发人员需要给编写相关的程序插件,增加了开发的难度性。

Write Through模式

Write Through模式和Read Through模式类似,当数据发生更新的时候,先去Cache里面进行更新,如果命中了,则先更新缓存再由Cache方来更新database。如果没有命中的话,就直接更新Cache里面的数据。

2.缓存穿透问题

在高并发的场景中,缓存穿透是一个经常都会遇到的问题。

什么是缓存穿透?

大量的请求在缓存中没有查询到指定的数据,因此需要从数据库中进行查询,造成缓存穿透。

会造成什么后果?

大量的请求短时间内涌入到database中进行查询会增加database的压力,最终导致database无法承载客户单请求的压力,出现宕机卡死等现象。

常用的解决方案通常有以下几类:

1.空值缓存

在某些特定的业务场景中,对于数据的查询可能会是空的,没有实际的存在,并且这类数据信息在短时间进行多次的反复查询也不会有变化,那么整个过程中,多次的请求数据库操作会显得有些多余。

不妨可以将这些空值(没有查询结果的数据)对应的key存储在缓存中,那么第二次查找的时候就不需要再次请求到database那么麻烦,只需要通过内存查询即可。这样的做法能够大大减少对于database的访问压力。

2.布隆过滤器

通常对于database里面的数据的key值可以预先存储在布隆过滤器里面去,然后先在布隆过滤器里面进行过滤,如果发现布隆过滤器中没有的话,就再去redis里面进行查询,如果redis中也没有数据的话,再去database查询。这样可以避免不存在的数据信息也去往存储库中进行查询情况。

什么是缓存雪崩?

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

如何避免缓存雪崩问题?

1.使用加锁队列来应付这种问题。当有多个请求涌入的时候,当缓存失效的时候加入一把分布式锁,只允许抢锁成功的请求去库里面读取数据然后将其存入缓存中,再释放锁,让后续的读请求从缓存中取数据。但是这种做法有一定的弊端,过多的读请求线程堵塞,将机器内存占满,依然没有能够从根本上解决问题。

2.在并发场景发生前,先手动触发请求,将缓存都存储起来,以减少后期请求对database的第一次查询的压力。数据过期时间设置尽量分散开来,不要让数据出现同一时间段出现缓存过期的情况。

3.从缓存可用性的角度来思考,避免缓存出现单点故障的问题,可以结合使用 主从+哨兵的模式来搭建缓存架构,但是这种模式搭建的缓存架构有个弊端,就是无法进行缓存分片,存储缓存的数据量有限制,因此可以升级为Redis Cluster架构来进行优化处理。(需要结合企业实际的经济实力,毕竟Redis Cluster的搭建需要更多的机器)

4.Ehcache本地缓存 + Hystrix限流&降级,避免MySQL被打死。

使用 Ehcache本地缓存的目的也是考虑在 Redis Cluster 完全不可用的时候,Ehcache本地缓存还能够支撑一阵。

使用 Hystrix进行限流 & 降级 ,比如一秒来了5000个请求,我们可以设置假设只能有一秒 2000个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑。

然后去调用我们自己开发的降级组件(降级),比如设置的一些默认值呀之类的。以此来保护最后的 MySQL 不会被大量的请求给打死。

‘捌’ “分布式缓存” 是什么概念,怎么理解

我的理解,分布式缓存系统是为了解决数据库服务器和web服务器之间的瓶颈。
如果一个网站的流量很大,这个瓶颈将会非常明显,每次数据库查询耗费的时间将会非常可观。
对于更新速度不是很快的网站,我们可以用静态化来避免过多的数据库查询。
对于更新速度以秒计的网站,静态化也不会太理想,可以用缓存系统来构建。
如果只是单台服务器用作缓存,问题不会太复杂,如果有多台服务器用作缓存,就要考虑缓存服务器的负载均衡。