作为缓存系列的最后一篇,也是我重点想要介绍的。
- 缓存随谈系列之一:数据库缓存
- 缓存随谈系列之二:静态缓存(使用静态缓存提升网站性能的五种方法)
- 缓存随谈系列之三:动态缓存
背景是这样的,在两会期间,我们参加了新华社新闻推送方面业务的运维保驾护航。在这方面我们遇到一个很棘手的问题,就是热点类新闻推送,是高并发应用场景,如同电商的秒杀应用。瞬时的热点新闻访问,高并发的场景给数据库缓存及数据库带来了极大的负荷。针对这种场景(采用nginx+php部署的后端应用,前端为手机app客户端),我们采用了动态缓存技术,单机处理能力从50tps提升到5000tps。所以对此技术场景进行了整理,就有了一种想要分享的冲动,本来主要针对动态缓存来进行分享。整理了一下相关的缓存技术,结合数据库缓存、静态缓存(使用静态缓存提升网站性能的五种方法)、动态缓存组成了缓存系列。
何为动态缓存?即对动态页面的缓存。如,对 .do、.jsp、.asp/.aspx、.php、.js(nodejs)等动态页面缓存。可以看出,动态页面一般都会涉及动态计算、数据库缓存、数据库操作,所以每一次访问同一个页面,所获得的数据可能都有所不同。所以如若对数据及时性要求较高的应用,可能不太适合动态缓存。比如,对一个动态页面缓存了半个小时,用户请求访问该动态页面,返回缓存中的数据。很有可能,缓存中的页面数据即半个小时前缓存的页面数据状态。所以,动态缓存,是牺牲数据的及时性换取性能的技术。具体缓存设置多长时间,这个根据业务情况而来。
一、 nginx动态缓存的原理概要
nginx的动态缓存主要通过反向代理(http的负载均衡)实现,所以基本上可以实现所有动态页面的缓存,当然静态页面也能缓存(在上一个系列中已分享过通过nginx实现静态缓存的方式)。
架构原理图如下图1:
如上图所示,nginx做负载均衡反向代理,将用户请求转发至后端服务器。我们可以在nginx这层根据规则设置动态/静态缓存,即每次客户请求,直接由nginx将缓存数据返回,而不用再到后端获取响应数据。
Nginx动态缓存核心配置(以缓存jsp为例):
#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 80;
server_name _;
location /{
proxy_pass http://10.117.39.67:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ .*\.jsp$
{
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.117.39.67:8080;
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而言,动态缓存和静态缓存的配置基本一致。唯一的区别就是,静态缓存的location配置中,正则匹配的是静态访问请求。而动态缓存的location配置中,正则匹配的是动态访问请求。
二、 案例一:nginx对jsp的动态缓存
在MyEclipse中,新建一个test的web项目,然后在默认的index.jsp中简单输出测试文字、当前日期 及一张图片。index.jsp测试代码明细:
<%@ page language="java" import="java.util.*,java.text.SimpleDateFormat,java.text.DateFormat" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>This is test page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
This is my JSP page. <br>
![](eg_tulip.jpg)<br>
<%
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
out.print("Now the time is :" + df.format(date));
%>
</body>
</html>
然后我们部署到tomcat中,且前端用nginx做反向代理,部署结构如下图2:
为了测试方便,在后端仅部署了一台test tomcat。Nginx反向代理的配置如下:
server {
listen 80;
server_name _;
location /{
proxy_pass http://10.117.39.67:8080;
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;
}
每次刷新浏览器我们可以看到显示的时间都是不一样的(如下图3):
然后我们对jsp进行动态缓存,核心配置如下图4:
这个时候我们通过浏览器访问对应jsp的页面,我们可以看到每次访问,页面显示的时间是一模一样的,由此可见我们nginx的动态缓存功能已经实现。
我们在nginx的服务器中缓存目录可以看到针对刚才访问jsp的缓存文件,直到缓存时间到期,nginx将会一直将存放本地缓存的磁盘文件内容,作为response返回给客户端请求(如下图5):
三、 案例二:nginx对php的动态缓存
Nginx 对php的动态缓存,和Nginx对jsp的动态缓存配置基本一致,唯一不同的是才location中匹配php类型即可。由于篇幅有限,nginx对php的缓存就不再细节性的介绍。
四、 php的动态缓存(fastcgi_cache)
除了nginx的动态缓存外,php也有自带缓存(如fastcgi缓存)来实现动态缓存。实现原理架构图如下图6:
Nginx的核心配置如下,值得注意的是,这里不需要通过反向代理来设置。是通过FastCGI自带的缓存来实现配置(如下图7):
Php的测试代码如下(输出文字、日期及一张图片):
通过浏览器多次访问我们的test.php页面,所以看到此页面的内容是不变的:
同时我们在服务器中可以看到存放在磁盘中的缓存文件:
直接缓存到期,或者我们手动清理缓存文件,则客户端才会收到最新的数据返回,否则将返回本地缓存的数据。
我为自己带盐,原创作者:乔锐杰