【51CTO.com原创稿件】在项目开发中缓存可以说是一直的存在,但是缓存技术具体该怎么用用在哪里,对于大多数开发人员来说并不知道,甚至有些开发人员认为缓存使用过于复杂。那么通过这篇文章各位读者可以充分理解缓存的使用和原理。
-
缓存能干什么
缓存可以提高系统性能、提高稳定性和可用性。同样缓存也可以减少交互的通信量、降低系统处理量和降低磁盘开销。下面我针对前面所说的内容从六条进行一个简单的概述。
-
提高系统性能:将数据缓存起来避免数据重复处理和传输,一般我们会将变化很少的数据存储在缓存中,比如国家、省份和城市名称;
-
提高稳定性:在大量请求对同一个数据或者逻辑多次调用时会造成很大的资源浪费,甚至会造成系统不稳定。这时我们可以将这些资源缓存起来,每次请求时都从缓存中读取,这样就提高了系统的稳定性;
-
提高可用性:当数据系统服务出现问题时,通过缓存可以继续向请求端提供数据服务,只不过这时的数据有可能是过时的;
-
减少通信量:缓存数据能有效减少在进程和机器间的传输量;
-
降低处理量:将处理好的数据缓存起来,可以避免同样的数据二次处理;
-
降低磁盘访问次数:将数据缓存起来,每次需要数据时先访问缓存,如果存在就返回缓存的数据,如果不存在那么就访问存储在磁盘上的数据。通过这种操作可以有效的降低磁盘的访问量。
-
缓存状态
所谓缓存状态是应用系统在一个时间点上数据的状态,这些数据有可能是持久化到数据库中,也有可能是临时存储在内存中等等。在这一小节里我们将学习到缓存生命周期、范围和陈旧数据如何处理。
-
缓存生命周期
缓存生命周期一共有四种,分别如下表:
生命周期
说明
Permanent State
永久有效:数据永不过期,数据永久存在
Process State
进程有效:在进程有效的生命周期内数据有效
Session State
会话内有效:在特定的会话内数据有效
Message State
消息内有效:在处理特定消息的时间段内有效
- 缓存范围
缓存是有范围的,总结起来说缓存范围包含两大类:物理范围和逻辑范围。这两个范围内又包含了不同的详细范围。具体如下:
-
物理范围
范围
说明
Organization
在组织内所有应用都可以访问缓存
Farm
在应用场范围内所有的机器都可以访问缓存
Machine
在一个机器内可以访问缓存
Process
在一个应用进程内可以访问缓存
AppDomain
在一个应用域内可以访问缓存
- 逻辑范围
范围
说明
Application
在一个应用进程内可以访问缓存(同 Process)
Business Process
在特定业务流程内可以访问缓存
Role
特定角色可以访问缓存
User
特定用户可以访问缓存
- 缓存陈旧数据处理
缓存是数据的快照,但是由于数据源可以被修改,所以缓存就存在陈旧的特点。利用这个特性将数据陈旧的负面影响最小化是缓存状态数据的一个重要任务。一般我们从如下两个方面来定义哪些数据是陈旧数据:
-
主数据更改的可能性:时间越长主数据被修改的可能性就越大,因此我们可以设置时间点来更新缓存数据;
-
旧数据的影响程度:缓存数据不更新或更新不及时是否对整个系统或者核心业务有影响。
根据上面的两个标准,我们将缓存数据的可接受程度定义为容忍度,容忍度分为无法容忍和一定程度容忍。所谓无法容忍,就是当主数据更新时缓存数据必须马上更新。而一定程度的容忍是指允许在一定时间段内缓存数据和主数据不同。
-
应考虑的东西
在使用缓存时,我们应从 5 个方面考虑:
-
过期策略:定义缓存数据多久失效、在什么情况下失效;
-
安全性:如何保证缓存的数据不被其他没有权限的进程、方法访问;
-
管理:定义缓存的最大容量、过期策略和清理策略等;
-
数据格式与访问方法:选择线程安全、可序列化和可规格化的缓存方案以及方法;
-
内容加载:内容如何加载,是在应用程序启动时就提前加载,还是使用到时先从主数据获取数据,之后再放在缓存里。
二、.NET 中的缓存
.NET 中的缓存有七种,分别是:Asp.net 缓存、 Remoting Singleton 缓存、 Memory-Mapped File 、SQL Server 缓存、静态变量缓存、 Asp.net session state 和 客户端缓存 。下面我分别来详细讲解一下。
-
Asp.net 缓存
对于 Asp.Net 开发人员来说,经常需要把常用数据存储到内存中。方法无非就是三种,其中最常用的是 Session 对象 和 Application 对象 。这两种方式都是以键值对的形式缓存数据。它俩的唯一区别是 Session 对象保存的是和单个用户有关的数据,而 Application 对象存储的是和应用程序有关的数据,每个用户都可以访问。除了这两种方法,还有另一种方法不是很常用,但是要比上述方法方便。这个方法就是 Cache 对象 ,它是 Asp.Net 中专门用于缓存数据的,它的应用范围是整个应用程序域。生命周期和应用程序一样,当应用程序启动时 Cache 对象创建,当应用程序关闭时 Cache 对象也随之消失。它具有专门用于缓存管理的特性,下面我们就来看一下 Cache 的讲解(Session 对象 和 Application 对象 因为用的较多因此这里不讲解)。 Cache 对象位于命名空间 System.WebCaching 中,它除了可以存储键值对外,还可以存储 .NET 框架的对象。一般情况下我们使用 HttpContext 类的 Cache 属性或 Page 对象的 Cache 属性来得到 Cache 的引用。我们使用 Cache 时首先需要考虑的是依赖和过期策略。 Asp.Net 中的依赖和过期策略包含如下两种:
-
File Dependency :文件依赖,当硬盘上的一个或多个文件更改时,强制移除缓存数据。
-
基于时间的过期策略:按照预先定义的时间策略使数据失效,参数可以是绝对时间,也可以是相对时间。
Tip:
-
Cache 对象根据缓存项的优先级来决定先移除哪些缓存数据,可以在代码中指定缓存项的优先级。指定优先级使用 CacheItemPriority 枚举项中的值。
-
Asp.Net 不提供缓存的刷新,但是我们可以使用 Response.Cache.SetExpires 方法设置数据失效日期为当前日期,就可以刷新缓存了。
在 Asp.Net 中我们也可以进行输出缓存,输出缓存主要用于缓存页面。将页面请求的响应放入缓存中,以后对这个页面的请求就会从从缓存中获得。我们可以通过添加 Page 指令来实现,也可以通过 HTTPCachePolicy 类来实现。在我们缓存页面的时候需要考虑如下几个方面:
-
经常被请求但不改变的静态页面;
-
更新频率和时间已知的页面(如显示股票价格的页面);
-
根据HTTP参数,有几个可能输出的页面(如根据城市的代号显示该城市天气情况的页面);
-
从Web Service返回的结果。
有时存储整个页面会导致内存使用过大,这时候就应该使用页面片断缓存技术。但是页面片段缓存技术并不是任何时候都适用,只有如下几种情况适用:
-
多个用户使用的页面片断;
-
包含静态数据的页面片断;
-
开销很大的页面片断;
-
多个页面共同使用的页面片断。
-
Remoting Singleton 缓存
.Net 提供了跨应用程序域、跨进程以及跨计算机的程序运行框架。服务器激活对象中 Singleton 类型任何时候都不会同时具有多个实例。在运行过程中如果存在实例,所有客户端请求都由该实例提供服务。如果不存在,服务器将创建一个实例,所有的后继请求都将由该实例来提供服务。
-
Memory-Mapped File
Memory-Mapped File 允许应用程序通过指针来访问磁盘上的文件。这种方法在多个应用程序共享内存时,系统的性能会有明显提升。基于 Memory-Mapped File 的缓存方案可以用在应用程序的每个层中,只不过由于使用 win32 API 调用,所以 只能以非托管代码的方式运行。
-
SQL Server 缓存
将缓存的数据存储在数据库里也是常用的方法,它的优点如下:
-
易于实现;
-
完善的安全模型和很高的健壮性;
-
方便的共享;
-
持久保留;
-
支持大数据量。
当然,缺点也是显而易见的:
-
需要安装SQL Server,对小型应用来说不合适;
-
重新构造数据的性能和读取数据库的性能比较;
-
网络负担大。
-
静态变量缓存
将数据存储器声明为静态变量,并且提供维护接口,由于是在内存中,这种方案可提供对缓存数据的直接、高速的访问,当没有替代方案解决键值对的存储且对速度要求很高时,可以使用静态变量。使用这种方法保存的对象前提是它不经常更改,但是由于没有清理缓存机制,因此这种方法会造成很高的性能开销,并且还要保证线程安全。因此该方法不推荐使用。
-
Asp.net session state
基于HttpSessionState对象的asp.net session state来缓存单个用户的会话状态信息,解决了asp中会话状态的很多限制。Asp.net session state有三种操作模式:
-
进程内模式InProc:
进程内模式是唯一支持Session_End事件的session模式,当用户会话超时或中止时,可以运行Session_End中的事件处理代码来清除资源。但是在 web 应用中 aspnet_wp.exe 的多个实例在同一台服务器上运行,因此进程内模式不适用 web 应用。
-
进程外模式State Server:
该模式使用指定的进程储存状态信息,使用该模式要保证你存储的对象是可序列化的。在 web 应用中使用时,必须保证 web.config 文件中的 <MachineKey> 元素在所有服务器上是唯一的。这样所有的服务器使用同 样的加密方式,才能访问缓存中的数据。
-
SQL server模式:
该模式类似于 SQL Server 缓存 ,这里不多讲解。
-
客户端缓存
使用客户端存储页面信息的方式来降低服务器的负担,虽然具有最低的安全保障和最有限的数据量,但却有最快的性能。常用的客户端缓存方法有如下五种:
-
Hidden Field
该方法也就是所谓的隐藏域,在页面中放置一个 <input type="hidden"/>
,在其 value 属性中存入需要缓存的值。这样做的优点是会和表单一起提交,而且所有浏览器都支持并且和服务端无关。但是同样也具有缺点,不安全,任何人都可以修改,而且存储结构化数据不方便,内容很多时会出现性能问题。
-
View State
这种方法和 Hidden Field 方法一样,只不过这种方法对存储的数据进行了加密,但是同样具有 Hidden Field 的缺点。
-
Hidden Frame
使用Hidden Frame,避免了使用hidden field和使用view state时每次页面回送时的缓存数据往返,优点是可以加载大量数据,可以缓存多个不同的数据。缺点同样也很棘手,首先很多浏览器已经开始不支持 Frame 了,而且客户端可以看到隐藏的 Frame,并且大量的 Frame 会造成页面加载很慢。
-
Cookies
Cookies 也可以存储缓存数据,可以很方便的存储到客户端浏览器中,并且支持过期策略,但是缺点也很明显。首先容易被篡改,并且可存储的 Cookie 数量有限,而且客户端很有可能拒绝 Cookie 。
-
Query String
这种方法只可以在使用 HTTP GET 方式调用URL时使用,服务端可直接读取,而且所有浏览器都可以使用,但是因为是在 URL 中显示出来,所以很容易被篡改,而且有长度限制,字符不能超过 255个字符。
三、总结
通过上述的讲解,相信大家已经理解了缓存的使用,我们在使用时应注意使用的场景和使用的方法。
作者介绍:
朱钢,笔名喵叔,国内某技术博客认证专家,.NET高级开发工程师,7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站的架构设计,目前就职于一家初创公司,从事企业级安全监控系统的开发。
【51CTO原创稿件,合作站点转载请注明原文作者和出处为51CTO.com】