使用静态缓存提升网站性能的五种方法

上次写了一篇数据库缓存,由于快餐式的风格,遭到了广大读友的吐槽。上篇风格有点“虚”,我本身是一个技术控,偏向经验/干货的分享,本文主要描述静态缓存方面的一些心得及分享。作为系列二,有所不足之处,依旧希望大家勇于“亮砖”。
说起静态缓存技术,CDN是金典代表之作。静态缓存技术面非常广,涉及的开源技术包含apache、Lighttpd、nginx、varnish、squid等。
静态缓存,一般指web类应用中,将图片、js、css、视频、html等静态文件/资源通过磁盘/内存等缓存方式,提高资源响应方式,减少服务器压力/资源开销的一门缓存技术。
本文中主要通过:浏览器缓存、磁盘缓存、内存缓存、nginx的内存缓存、CDN五个方面围绕静态缓存而展开。

一、浏览器缓存

浏览器缓存,也称为客户端缓存,是静态缓存中最常见最直接的表现形式,很多时候都往往被人忽略掉。
案例1:
我们经常在nginx的配置文件中看到以下缓存配置:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
     expires 1d;
}
location ~ .*\.(js|css)?$
{
     expires 15d;
}

案例2:
在经常写jsp的时候,html标签中关于http头信息也可以注意到“expires”的字样:

<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="expires" content="60">    
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">

对于案例1和案例2中(nginx设置的expires优先级大于代码中设置的expires优先级),expires是给一个资源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可,所以不会产生额外的流量。此种方法非常适合不经常变动的资源。如果文件变动较频繁,不要使用expires来缓存。
比如对于常见类web网站来说,css样式和js脚本基本已经定型,所以最适合的方法是expires来缓存一些内容到访问者浏览器。

案例3:
通过chrome访问服务器端的一张图片,通过F12键打开开发者前端调试工具(如图1):

图1

第一次访问,响应200状态,当第二次及后续访问的时候,变成304状态(如图2),客户端已经开始取浏览器缓存内容,而不需要去服务器端获取对应的请求内容,即nginx中expires参数设置已经生效。等待客户端缓存时间过期后,会再次请求服务器端内容来更新本地缓存。
图2

介绍到这里,突然想起一个有意思的需求。比如,访问一张静态文件,不想客户端缓存,需要每次都去服务器端取数据。我们可以用“last-modified”参数来实现,即“last-modified”是根据文件更新时间来确定是否再次发送加载。
Nginx核心配置如下:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
     add_header  Last-modified  10;
     expires 1d;
}

我们更改掉服务器传回客户端的“last-modified”文件修改时间参数的值,这样导致客户端本地保存的文件时间每次跟服务器端传回来的时间不一致,所以每次客户端“误认为”服务器端有静态文件更新,所以每次都会去服务器端取“所谓的最新数据”。这样我们可以看到,不管在浏览器访问多少次,返回的http状态都是200,再也找不到304状态了。

误区:在nginx中设置expires,并不是指把静态内容缓存在nginx中,而是设置客户端浏览器缓存的时间,这是很多人误区所在。

二、磁盘缓存

除了存储在客户端的静态缓存(浏览器静态)技术外,在服务器端的静态缓存技术主要分为磁盘缓存类和内存缓存类两大类。单纯围绕nginx的squid、varnish等一类中间件,处理静态数据的性能十分优秀。核心是nginx基于epoll网络模型,而相比apache基于select网络模型。所以apache的优势在于密计算型,稳定性好。而nginx偏向静态处理,反向代理,高并发。比如apache+php的稳定性比nginx+php要好,而性能是明显nginx要优秀许多。

以上仅单纯是对磁盘中静态数据处理的能力,所谓磁盘缓存,指另外的一种缓存静态文件的技术。以nginx配置为例:

#levels设置目录层次 
#keys_zone设置缓存名字和共享内存大小 
#inactive在指定时间内没人访问则被删除在这里是1天 
#max_size最大缓存空间
proxy_cache_path /alidata/www/default/cache_dir/ levels=1:2  keys_zone=cache_one:200m inactive=1d max_size=30g;

server {
    listen       82;
    server_name  _;
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|html)$
    {
        proxy_cache cache_one;                    # keys_zone后的内容对应
        proxy_cache_valid  200 304 301 302 10d;   #哪些状态缓存多长时间  
        proxy_cache_valid  any 1d;                #其他的缓存多长时间  
        proxy_cache_key $host$uri$is_args$args;   #通过key来hash,定义KEY的值

        proxy_pass http://10.168.247.180:81;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    }

   access_log  /alidata/nginx/logs/default-cache.log;

可以看出nginx主要通过proxy_cache来实现web cache,熟悉nginx的同学,不难看出,以上配置在location这里,不仅可以实现静态文件的缓存,还可以实现动态文件的缓存(这里放在下章节详细介绍)。我们编写个test.html测试文件,然后并访问。test.html源码如下:

<html>
<head>
<title>test cache</title>
<meta http-equiv="expires" content="-1">  
</head>
<body>
<br>
![](eg_tulip.jpg)
</body>
</html>

我们发现服务器的cache目录里面,多了两个缓存文件:

/alidata/www/default/cache_dir/c/68/b0ad5d3e7f099bfff9e4fc6a159d868c
/alidata/www/default/cache_dir/f/fa/53edc39ed253e14415a29412cfc01faf

有意思的,这两个文件里面的内容分别为(通过less命令查看):


图3:b0ad5d3e7f099bfff9e4fc6a159d868c
图4:53edc39ed253e14415a29412cfc01faf

所以不难看出,nginx把html内容和图片二进制全部缓存到本地磁盘上了。下次用户再次来访问test.html的时候,nginx直接将缓存在本地磁盘的文件返回给用户。特别是后端如若是部署的tomcat、iis等,nginx强大的静态缓存能力,有效减少了服务器压力。

三、内存缓存

紧接上面描述的磁盘缓存,内存缓存顾名思义,就是把静态文件缓存在服务器端的内存中。所以这种缓存,如若命中缓存的话,取内存中的缓存数据返回比取磁盘中的缓存数据返回,性能要高很多。以varnish为例,varnish核心配置如下:
启动命令:

varnishd -f default.vcl -s malloc,2G -a 0.0.0.0:80 -w 1024,51200,10 -t 3600 -T 192.168.100.2:3500

参数简介:

-a  address:port 监听端口
-f  指定配置文件
-s 指定缓存类型 malloc为内存, file 文件缓存
-t 默认TTL
-T address:port 管理端口
-w 最小线程,最大线程,超时时间

default.vcl核心配置如下:

sub vcl_fetch {
if (req.request == "GET" && req.url ~ "\.(gif|jpg|jpeg|png|bmp|swf|html)$") {
set obj.ttl = 3600s;
}
}

Varnish对.gif、.jpg、.jpeg、.png等结尾的URL缓存时间设置1小时。varnish设置完毕后,我们用命令行方式,通过查看网页头来查看命中情况:

[root@test-varnish ~]# curl -I http://***.***.***.***/test.html  
HTTP/1.1 200 OK  
Server: Apache/2.2.27 (Unix) PHP/5.3.18 mod_perl/2.0.4 Perl/v5.10.1  
Last-Modified: Sat, 10 Jul 2016 11:25:15 GMT  
ETag: "55dh9-233f-33d23c3758dg2"  
Content-Type: text/html  
Content-Length: 23423  
Date: Fri, 18 May 2016 21:29:16 GMT  
X-Varnish: 1364285597  
Age: 0  
Via: 1.1 varnish  
Connection: keep-alive  
X-Cache: MISS from ***.***.***.***  #这里的“MISS”表示此次访问没有从缓存读取
[root@test-varnish ~]# curl -I http://***.***.***.***/test.html 
HTTP/1.1 200 OK  
Server: Apache/2.2.27 (Unix) PHP/5.3.18 mod_perl/2.0.4 Perl/v5.10.1  
Last-Modified: Sat, 10 Jul 2010 11:25:15 GMT  
ETag: "55dh9-233f-33d23c3758dg2"  
Content-Type: text/html  
Content-Length: 23423
Date: Fri, 18 May 2016 21:40:23 GMT  
X-Varnish: 1364398612 1364285597  
Age: 79  
Via: 1.1 varnish  
Connection: keep-alive  
X-Cache: HIT from ***.***.***.***     #由“HIT”可知,第二次访问此页面时,从缓存中读取内容,也就是缓存命中

最后,我们可以通过varnishadm命令来清理缓存,也可以通过varnishstat命令来查看varnish系统缓存状态。

四、Nginx的内存缓存

以上主要以Varnish为例,介绍了内存缓存静态资源的方法。其实nginx也有内存缓存,相比squid、varnish而言,nginx的内存缓存需要通过编码实现。如下配置:

location /images/ {
                set $memcached_key $request_uri;
                add_header X-mem-key  $memcached_key;
                memcached_pass  127.0.0.1:11211;
                default_type text/html;
                error_page 404 502 504 = @app;
}

memcached_pass指定服务器地址,使用变量$memcache_key为key查询值,去memcache查询对应value值。

如我们访问:http://.../image/test.jpg ,则nginx去memcache中查询key为“test.jpg”的value值并返回。如果没有相应的值,则返回error_page 404。介绍到这里,关键在于存储在memcache中的静态文件,需要通过代码写入memcache中。怎么样通过php/java等代码把静态资源的数据写入memcache中,关于这块的示例就不再过多介绍。

Nginx的内存缓存因为需要通过编码实现,所以灵活性特别高。这块可以结合自身业务系统的特点,让静态缓存的灵活性和效率都能得到保障。可能唯一的缺陷就是,通过编码实现的方式,给我们维护管理带来了负担。在之前我曾参与的一个电商系统,就是把客户的订单照片通过php代码写入memcache,客户访问取图的时候,从memcache中获取,速度效率特别高。Nginx作为一款在七层无所不能且轻量级高性能的中间件,能够直接去memcache中取数据,来实现静态缓存的效果,这块相应的功能是其他软件无法相媲美的。

五、CDN

说起CDN,大家都不陌生,它是静态缓存加速最典型的代表。CDN技术并不是一门新的技术,它是基于传统nginx、squid、varnish等web 缓存技术,结合DNS智能解析的静态缓存加速技术。值得注意的是,他对动态链接访问并没有加速效果。架构原理图如下图5:


图5

所以CDN的静态缓存技术核心主要在于两点:
节点缓存:对需要加速的网站应用,相应的静态资源通过内存缓存+磁盘缓存的方式缓存在服务器端。

精准调度:对访问的用户ip进行智能解析调度,实现就近缓存节点访问。比如以上图例中,北京用户访问www.a.com。通过dns解析的时候,分析用户ip,发现是北京用户。则dns返回对应北京缓存节点的ip地址给到用户,则用户www.a.com,则默认访问北京服务器上面的缓存数据,实现就近访问的策略,大大提升了访问速度。

我为自己带盐,原创作者:乔锐杰

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容

  • 【转】缓存在分布式系统中的应用 缓存在分布式系统中的应用 摘要 缓存是分布式系统中的重要组件,主要解决高并发,大数...
    武汉苏乞儿阅读 839评论 0 10
  • 一、MemCache简介 session MemCache是一个自由、源码开放、高性能、分布式的分布式内存对象缓存...
    李伟铭MIng阅读 3,761评论 2 13
  • 缓存在分布式系统中的应用 摘要 缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题...
    garyond阅读 1,592评论 0 12
  • 缓存的基础知识 1、程序本身具有局部性 时间局部性过去访问到的数据,也有可能被两次访问 空间局部性一个数据被访问到...
    魏镇坪阅读 2,000评论 1 3
  • 第一章 Nginx简介 Nginx是什么 没有听过Nginx?那么一定听过它的“同行”Apache吧!Ngi...
    JokerW阅读 32,608评论 24 1,002