`

缓存(二)

阅读更多

 在我们打开浏览器,决定浏览某个网页之前(指人眼看到屏幕上的内容之前),一般来说浏览器有几个事情要做,首先根据url请求服务器端的html html显示到屏幕上等等.à下载css,js,--------à,然后解析html,------à数据------ 接着大脑才能感受到.à然后眼睛才能感受到,--------à---------

在这个流程中,那么怎么才能让大脑尽可能快的接受到这个信息呢,我想最快的方式是在大脑里放一份该屏幕的拷贝,下次想看这份内容的时候直接拿出大 脑的拷贝就可以了.如果大脑容量有限,那我们可以考虑把这份拷贝放到眼睛里,如果眼睛也放不下,那我们可以考虑把这份拷贝放到浏览器里,从这个逻辑上看, 越靠近大脑的数据越能快速的被我们接受到.

那么本文的目的其实就是为了研究如何使用大脑和眼睛来缓存数据------------------------吃惊吧,ahuaxuan瞎扯的,回到正题,上面这段调侃不是为了说明别的,而是为了说明越靠近用户的数据被用户感受到的速度就越快.也就是近与快的关系
.

接着再让我们抛开缓存先不说,来说说CDN和镜像的问题,CDN的英文名字叫CDN,中文名字一般还是CDN(请换个调朗诵).呵呵,CDN中文名字是内 容分布网络,简单来说就是把内容分布出去,比如放到全国几个地方,举例来说做一个图片服务,上海的用户请求某个图片服务器,那么只需要返回某个离上海最近 CDN节点上的图片,而不需要路由到北京或者云南的节点上去取数据,您要问为啥呢,因为快啊,上海的用户访问北京节点的数据显然在路由层次上,网络时间 消耗上都要多出很多,这说明啥呀,还是那个理儿:近就会快啊


一般来说CDN都是放一些图片,视频,文档之类的数据,那么元数据呢,放一块儿,当然也不是,这时候可以用镜像来解决元数据的问题,于是变成了上海的用户访问上海的镜像,北京的用户访问北京的镜像.这还不是就地取材比较方便嘛
.

,说到这里,想必大家对近和快的关系有了一定的认识了,下面我们来看看如何把这种原理或者规则运用到缓存中去
.

下面让ahuaxuan和大家先调查一下离眼睛最近的是什么,显示器(别跟我说是屏幕保护膜和键盘哈,鼠标也不行),不过这些是硬件呀,那软的 ,非浏览器莫数了.也就是说如果我们把一些可以缓存在浏览器上的数据缓存到浏览器上,那就能加快我们的页面响应速度了.也就是说我们现在找到一个地方, 也许可以放一点可以缓存的数据
.

下面我们要考察考察什么样的数据可以缓存在浏览器上,以及缓存在浏览器上的一些优缺点或者限制因素

什么样的数据可以缓存在浏览器上
?
浏览器上无法就几种数据,html,css,js,image,.那么接着我们来看看他们的变化特性
,
html
数据很多情况下是动态的,但是也有很多情况下是某个时间段内可以是静态的
.
Css
一般是静态的

Js
一般也是静态的

Image
一般也是静态的
.

,看上去后几者基本都可以缓存在浏览器,html是否缓存要看html中数据的特性了.那么问题来了,浏览器是依据什么设置来缓存html,或者css,或者js的呢.答曰,expires或者max-age.
Expires
代表该份数据缓存到浏览器上,直到某个时间点后过期,max-age表示缓存在浏览器上直到某个时间段之后过期
.

对于静态内容:设置文件头过期时间Expires的值为“Never expire”(永不过期)

动态页面,在代码中添加cache-control,表示多少时间之后过期,
:
response.setHeader("Cache-Control", "max-age=3600");
表示1个小时后过期,即在浏览器上缓存一个小时
.

但是这样问题又来了,如果设置10天后过期,那我明天就要改变,css,js都变了,咋办呐,答曰,加版本号吧,这样浏览器就会重新加载新的cssjs
.
但是如果是动态数据,那就没有折了,所以动态数据的max-age一般不推荐太大,否则啊,您呐,就得挨个通知您得用户按一下Ctril+F5
.

一般来说静态数据需要缓存,我们一般通过webserver(apache,lighttpd之流),只需要配置一下即可,而动态数据是比较重 要的,因为其改变的周期段,而且只能由servlet容器或者fastcgi之类的服务器返回,所以其应付大量并发的能力是有限的.那么这里理论上可能有 一个瓶颈,就是如果访问的独立用户较多,那么这份动态数据还是会被请求1*用户数 = n,那么我们可以想象,一样的请求对于我们的servlet容器或者fastcgi来说其实是多余的,我们可以想一个方法,把这些一样的请求挡在 servlet容器或者fastcgi进程之前
.

正如在第一说中说到的,在浏览器和servlet容器或者fastcgi进程之间,还有很大的空间可以发挥,在这一部分的缓存,ahuaxuan称之为
webcache.

目前在webcache,最流行的估计就属squid,然后还有varnish等等.为了有一个比较直观的感受,我们来看看下面这张图呗
:


 
从这张图上,我们可以看出,浏览器1在请求了一份数据之后,其实这份数据已经在webcache上了,浏览器再来请求2的时候,请求到了 webcache这层就返回了,这样就降低了servlet container的压力了.虽然说我们在servlet容器上也是可以建page cache,但是毕竟servlet本身的并发能力有限.(如何在servlet container上使用page cache:http://www.iteye.com/topic/128458)

而且更重要的是一般webcache的并发能力要比servlet container或者fastcgi process要高出很多 (没办法,谁叫它是专业的cache).所以使用webcache也能够提供更高访问量的服务.一举多得,何乐而不为呢.但是声明一下,您呐,别以为上 面这种方式是标准方式,我们还有webserver,负载均衡器等等,上图只是为了便于说明本文的论点,而且互连网需求和解决方案层出不穷,切不可以胡搬 乱套,还是要分析分析再分析,思考,思科再思考.

说到这里即使以前没有接触过得筒子大概也明白了web cache得作用了.下面我们再来看看如何使用web cache,呵呵,其实和浏览器上缓存数据得方式一样.也是通过在response header中指定expires或者max-age来实现的.(但是据ahuaxuan观察在使用squid的时候有一个要求,浏览器的请求必须满足 http的语义,也就是说只有method=get的时候web cache才能缓存数据,如果是post,那么web cache认为这个是一个创建数据的请求,并不会缓存其返回结果
.)

Squid,
如果您要系统的学习squid,请看
:
http://www.squid-cache.org/      http://blog.s135.com/book/squid/

补充,在有些情况下,web cache中的数据很有可能是有状态的.比如根据浏览器的locale返回不同的数据,那么虽然访问的url是一样的,但是返回的值却是不一样的,咋办 ,别担心,我们有vary,只要在response里指定vary参数为accept-languageok.您也可以指定为cookie中的值, 就完全看您的需要了.如果您还是不明白vary的作用,请看: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44

总结:
说到这里,关于近和快的话题也基本可以结束了(这个话题再写下去就变成裹脚布了).所以一般情况下,我们可以认为有如下事实:”==”,但是 近和快并不只是表现在人的体验上,如果换个角度,速度的感受者不是人,而是机器,那么我们也可以这么认为local cacheremote cache更靠近cpu,所以local cache的速度更快(当然他们的功能不是重叠的,各自适用的场景不一样而已,而且很多情况下他们可以配合使用,在后续的文章中将会讨论这个问题

).

如何在只使用tomcat的情况下,自动缓存jscss或者image等文件.
第一步:写一个filter,可以根据路径的正则来判断该路径的请求是否需要设置max-age:

public class CacheFilter implements Filter{  
  
    private static transient Log logger = LogFactory.getLog(CacheFilter.class);  
      
    private Integer cacheTime = 3600 * 24;  
    private List<Pattern> patternList = new ArrayList<Pattern>();  
      
    private static ResourceBundle rb = ResourceBundle.getBundle("cache-pattern");  
    public void destroy() {  
          
    }  
  
    public void doFilter(ServletRequest rq, ServletResponse rqs,  
            FilterChain fc) throws IOException, ServletException {  
          
        fc.doFilter(rq, rqs);  
        if (rq instanceof HttpServletRequest && rqs instanceof HttpServletResponse) {  
            HttpServletRequest request = (HttpServletRequest) rq;  
            HttpServletResponse response = (HttpServletResponse) rqs;  
              
            if (matchPattern(request.getRequestURI())) {  
                response.setHeader("Cache-Control", "max-age=" + cacheTime);  
                if (logger.isDebugEnabled()) {  
                    StringBuilder sb = new StringBuilder();  
                    sb.append(" set cache control for uri = ").append(request.getRequestURI());  
                    sb.append(" and the cache time is ").append(cacheTime).append(" second");  
                    logger.debug(sb.toString());  
                }  
            }  
          
        } else {  
            if (logger.isWarnEnabled()) {  
                logger.warn("---- the request instance is not instanceof HttpServletRequest ---");  
                logger.warn("---- the response instance is not instanceof HttpServletResponse ---");  
            }  
        }  
          
    }  
  
    public void init(FilterConfig arg0) throws ServletException {  
        Enumeration<String> keys = rb.getKeys();  
        while (keys.hasMoreElements()) {  
            String p = keys.nextElement();  
            String value = rb.getString(p);  
            patternList.add(Pattern.compile(value, Pattern.CASE_INSENSITIVE));  
              
            if (logger.isInfoEnabled()) {  
                logger.info(">>>>>>>>>>> init the cache pattern " + value);  
            }  
        }  
          
        if (arg0 != null) {  
            String ct = arg0.getInitParameter("cache-time");  
            if (!"".equals(ct) && null != ct) {  
                cacheTime = new Integer(ct);  
                if (logger.isInfoEnabled()) {  
                    logger.info(">>>>>>>>>> the cache time is " + cacheTime);  
                }  
            }  
        }  
    }  
      
    private boolean matchPattern(String url) {  
        for (Pattern pattern : patternList) {  
            if (pattern.matcher(url).matches()) {  
                return true;  
            }  
        }  
          
        return false;  
    }  
  
    public static void main(String [] args) throws ServletException {  
        CacheFilter cf = new CacheFilter();  
        cf.init(null);  
        System.out.println(cf.matchPattern("/css/prototype.CSS"));  
    }  
}  

 

第二步:classpath路径下创建一个cache-pattern.properties文件,内容如下:

Java代码

1 = .*ext-all.js  

2 = .*prototype.js  

3 = .*/css/.*\\.css  

1 = .*ext-all.js

2 = .*prototype.js

3 = .*/css/.*\\.css


在这个配置文件中,您可以根据jscss的路径来配置哪些目录,或者哪些文件需要设置max-age.

第三步:
web.xml添加如下内容:

Java代码

<filter>  

         <filter-name>cache-filter</filter-name>  

         <filter-class>com.filter.CacheFilter</filter-class>  

         <init-param>  

            <param-name>cache-time</param-name>  

            <param-value>86000</param-value>  

        </init-param>  

    </filter>  

  

<filter-mapping>  

        <filter-name>cache-filter</filter-name>  

        <url-pattern>*.js</url-pattern>  

    </filter-mapping>  

      

    <filter-mapping>  

        <filter-name>cache-filter</filter-name>  

        <url-pattern>*.css</url-pattern>  

</filter-mapping>  

<filter>

         <filter-name>cache-filter</filter-name>

         <filter-class>com.filter.CacheFilter</filter-class>

         <init-param>

            <param-name>cache-time</param-name>

            <param-value>86000</param-value>

        </init-param>

    </filter>

 

<filter-mapping>

        <filter-name>cache-filter</filter-name>

        <url-pattern>*.js</url-pattern>

    </filter-mapping>

   

    <filter-mapping>

        <filter-name>cache-filter</filter-name>

        <url-pattern>*.css</url-pattern>

</filter-mapping>



如此3,就可以将jscss文件缓存于无形.快哉.

仓卒之间成文,再加上ahuaxuan水平有限,本文如有纰漏之处,还望各位看官您不吝指正,先谢过了.

 

 

 

 

 

 

 

 

 

  • 大小: 57.4 KB
分享到:
评论

相关推荐

    hibernate一级缓存、二级缓存和查询缓存

    **hibernate一级缓存、二级缓存和查询缓存** 在Java的持久化框架Hibernate中,缓存机制是提高应用程序性能的关键要素。缓存能够减少数据库的访问次数,提高数据读取速度,并且在一定程度上降低了系统的负载。本文将...

    深入理解MyBatis中的一级缓存与二级缓存

    "深入理解MyBatis中的一级缓存与二级缓存" MyBatis是一种流行的持久层框架,它提供了缓存机制来提高应用程序的性能。在MyBatis中,有两种类型的缓存:一级缓存和二级缓存。下面我们将深入了解MyBatis中的一级缓存和...

    Redis用作二级缓存

    Redis作为二级缓存是数据库系统优化的一个重要策略,特别是在高并发、大数据量的场景下,可以显著提升应用性能。在Mybatis中,二级缓存是一个跨Mapper共享的区域,用于存储查询结果,避免了重复查询数据库,从而降低...

    hibernate一级缓存和二级缓存的区别与联系

    缓存机制分为一级缓存和二级缓存,两者都有助于减少对物理数据库的直接访问,从而提高应用程序的运行效率。 一级缓存是 Hibernate 内置的,默认开启,与 Session 对象关联。它是一个事务范围的缓存,也就是说,每个...

    mybatis一级缓存和二级缓存简单示例

    开启二级缓存后,相同的数据在不同 SqlSession 中查询时,如果一级缓存未命中,则会尝试从二级缓存中获取。二级缓存的生命周期更长,但在并发环境下需要谨慎使用,因为它可能会引发数据不一致的问题。 ### 开启缓存...

    mybatis一二级缓存

    在 MyBatis 中,一级缓存和二级缓存是两个重要的性能优化手段,它们可以有效减少对数据库的访问,提高系统的响应速度。下面将详细阐述这两个缓存机制。 ### 一级缓存 一级缓存是 MyBatis 默认开启的本地会话缓存,...

    hibernate一级和二级缓存配置与详解

    本篇将深入探讨Hibernate的一级缓存和二级缓存,以及查询缓存的配置和使用。 ### 一级缓存 一级缓存是Hibernate默认提供的缓存,它是Session级别的,每个Hibernate Session都有一个私有的、本地的一级缓存。当我们...

    hibernate开启二级缓存和查询缓存

    在 Hibernate 中,二级缓存和查询缓存是提高应用性能的重要机制。下面将详细介绍如何开启并理解这两个缓存机制。 ### 1. 一级缓存与二级缓存 #### 1.1 一级缓存 一级缓存是 Hibernate 内置的 Session 缓存,它是每...

    Hibernate一级缓存和二级缓存

    标题“Hibernate一级缓存和二级缓存”指的是Hibernate框架中的两种缓存机制,它们是提高数据访问性能的关键要素。一级缓存是Session级别的,而二级缓存是SessionFactory级别的,两者在数据库操作中起到了重要的作用...

    三级缓存和二次采样结合使用的案例

    在IT领域,尤其是在移动开发和图像处理中,三级缓存和二次采样是两个非常重要的概念,它们在优化性能和减少资源消耗方面起着关键作用。让我们深入探讨这两个概念及其结合使用的方式。 首先,我们来看“三级缓存”。...

    android图片二级缓存的实现机制

    本文将深入探讨“Android图片二级缓存的实现机制”,并结合开源项目Android-Universal-Image-Loader(UIL)的源码进行分析。 ### 一、什么是图片二级缓存 二级缓存是Android图片加载库常用的一种优化策略,它通常...

    redis多级缓存搭建资料

    二级缓存通常位于一级缓存之后,当一级缓存未命中时,会查询二级缓存。在Redis中,二级缓存可以是另一个Redis实例,或者是一个持久化的数据存储,如MySQL。二级缓存的目的是为了进一步减少主数据库的负载,提供更...

    二级缓存和三级缓存的区别.docx

    ### 二级缓存和三级缓存的区别 #### 一、电脑缓存的工作原理 电脑缓存作为一种高速存储器,主要用于缓解CPU与主内存之间速度不匹配的问题。在计算机执行指令时,CPU首先尝试从缓存中获取所需数据,而不是直接访问...

    Hibernate缓存,性能优化

    - **二级缓存配置**:根据业务需求选择合适的缓存策略和过期机制,合理设置缓存区域,避免不必要的数据冗余和竞争,同时考虑数据一致性问题,确保缓存的有效性。 #### 优化查询和SQL语句 - **减少N+1查询问题**:...

    Hibernate一级缓存和二级缓存详解

    Hibernate一级缓存和二级缓存详解 Hibernate是一种流行的基于Java的持久化框架,它提供了两种缓存机制:一级缓存和二级缓存。了解这两种缓存机制是非常重要的,因为它们可以极大地提高应用程序的性能。 一级缓存 ...

    php缓存多级目录的类

    第一个参数:缓存二级目录 第二个参数:缓存时间 默认1800 第三个参数:是否需要三级目录 0:不需要 1 需要 默认0 第四个参数:缓存后缀 默认 .html 调用方法: $cache = new php_cache('index'); $cache = ...

    hibernate 缓存策略

    本文将深入探讨Hibernate的缓存策略,包括一级缓存、二级缓存以及查询缓存,并结合源码分析其工作原理。 ### 一级缓存 一级缓存是Hibernate默认开启的缓存,也称为Session缓存。每当我们在Session中进行持久化操作...

    hibernate二级缓存实例

    在Java的持久化框架Hibernate中,二级缓存是提高数据访问效率的重要机制。它是一种全局共享的、跨会话的数据存储区域,旨在减少对数据库的直接访问,从而降低系统负载,提升性能。在这个"hibernate二级缓存实例"中,...

    Hibernate缓存详解

    在Hibernate配置文件(hibernate.cfg.xml)中,可以设置二级缓存的相关参数,如开启二级缓存、指定缓存提供者、配置缓存区域等。例如: ```xml &lt;property name="hibernate.cache.use_second_level_cache"&gt;true ...

Global site tag (gtag.js) - Google Analytics