Nginx+Varnish 实现动静分离,为服务器分流,降低服务器负载

相必大家在看加快网站响应速度方面的文章时,都提过这么一条:动静分离。那怎样实现动静分离呢,这里笔者就亲自搭建相关服务实现动静分离。

动静分离是一种架构,就是把静态文件,比如JS、CSS、图片甚至有些静态页面交给独立的服务器集群处理,从而进行分流,使服务器降低压力。

上面说把一些静态的文件分离出去,有读者就会笑了,静态文件能有多少,能消耗多少资源。

读者以实际经验告诉大家,千万不要小瞧这些静态文件,现在大部分网站都是以视频、图片为主,试想下天猫、淘宝、京东之类,文字能有多少,图片、视频又是多少,就知道这个量到底是多么的庞大,而动静分离从笔者公司实际使用经验来看,效果是杠杠的。

笔者这里的环境是: Centos6.4  Nginx Varnish , 其中Nginx响应请求,Varnish主要做缓存和反向代理(笔者这里说个题外话,很多人疑惑反向代理和正向代理,这两个概念说的都有些玄幻,笔者有个简单粗暴的解释. 反向代理:隐藏真实服务器信息, 正向代理:隐藏真实客户端信息)

笔者这里弄三台主机:192.168.138.10      192.168.138.3   192.168.138.4   (10安装Varnish,3、4安装Nginx)

第一步:先在92.168.138.3   192.168.138.4 两台机器上安装Nginx,这个安装相对容易,笔者就不做累赘了,只要你看到下面两个页面就OK了

第二步:在192.168.138.10上安装Varnish

这里笔者从官网上下载了比较新的 Varnish-3.0.7, 笔者准备使用源码编译安装,安装在/usr/local/varnish 目录下

tar -zxvf varnish-3.0.7.tar.gz 

安装之前还是老话,依赖先安装上,笔者在其官方网站上找到了其依赖的包

https://www.varnish-cache.org/docs/4.0/installation/install.html

yum install -y autoconf automake jemalloc-devel libedit-devel libtool ncurses-devel pcre-devel pkgconfig python-docutils python-sphinx

然后进行编译前检查

./configure \
--prefix=/usr/local/varnish/ \
--enable-dependency-tracking \
--enable-developer-warnings \
--enable-debugging-symbols

检查无误后开始编译安装

make && make install

第三步:开始配置varnish

其配置文件位于 /usr/local/varnish/etc/varnish/default.vcl  可以看到里面已经有些范例

笔者在这里先要对其架构及一些常用函数加以说明,不然后面都看不懂在配置写什么玩意

varnish使用了一种叫VCL的语言去对其进行配置,至于这语言啥玩意,就不用过多关心了,大致了解下就OK了,其语法可以看里面的相关范例,里面有些函数,下面一一列出

vcl_recv 函数: 接收和处理请求,当请求到达并成功接收后被调用,判断请求的数据并决定如何处理请求;该函数返回值有这么些关键字-》

        pass 表示进入pass模式,将请求交给vcl_pass 函数

        pipe 表示进入pipe模式,将请求交个vcl_pipe函数

        error code[reason]  表示返回'code'给客户端并放弃请求, 'code'是错误标示例如200 405等,'reason'是错误原因

vcl_pipe函数:该函数在进入pipe模式时被调用,用于将请求直接传递给后端主机,在请求和返回内容没有改变的情况下,将不变的内容返回给客户端,直到这个链接关闭;该函数有这么些返回值=>

        error code[reason]  同vcl_recv

        pipe

vcl_pass函数: 该函数进入pass模式被调用,用于直接将请求发送给后端主机,后端主机响应后发送给客户端,不进行任何缓存,每次都返回最新内容,该函数有几个返回值=>

        error code[reason] 同vcl_recv

        pass

lookup函数: 表示在缓存中查找到被请求的对象,并且根据查找的结果交给vcl_hit函数(命中)或vcl_miss(未命中)函数处理

vcl_hit函数:在执行lookup后,如果在缓存中找到对象,该函数将会被自动调用,该函数有以下几个返回值 =>

      deliver 表示找到内容发送给客户端,把控制权交给vcl_deliver函数

      error code[reason] 同vcl_recv

      pass

vcl_miss函数: 在执行lookup后,在缓存中没有找到对象,该函数被调用,该函数可用于判断是否从后端请求内容,该函数有以下几个返回值 =>

      fetch 表示从后端获取内容,并把控制权交给vcl_fetch函数

      error code[reason]  同vcl_recv

      pass

vcl_fetch函数:从后端主机更新缓存获取内容后调用该函数,接着判断获取的内容是放入缓存还是直接给客户端,该函数有以下几个返回值=》

      error code[reason]  同vcl_recv

      pass

      deliver

vcl_deliver函数:将在缓存中找到的内容发送给客户端调用的方法,该函数有以下几个返回值=》

      error code[reason]  同vcl_recv

      deliver

vcl_timeout函数:在缓存内容到期前调用该函数,该函数有以下几个返回值=》

      discard 表示中缓存中清除该内容

      fetch

vcl_discard函数:缓存内容到期后或者缓存空间不够时自动被调用,该函数有以下几个返回值=》

      keep 表示在内容中保留该缓存

      discard

VCL处理流程可以用下面这张图表示

Receive状态:请求处理的入口状态,根据VCL规则判断该请求应该在Pass或Pipe,还是进入Lookup(到本地缓存中查询)

Lookup状态:进入此状态后,会在hash表中查询数据,如果找到则进入Hit状态,否则进入Miss状态

Pass状态:在此状态下会进入后端获取内容,既进入Fetch状态

Fetch状态:从后端获取请求,发送请求,获得数据,并存储到本地

Deliver状态:将获取的数据发送给客户端,然后完成本次请求

VCL里面还有些变量,可以用在VCL函数中,用于逻辑处理

请求到达后可以使用的内置公用变量:

req.backend    =>    指定对应的后端主机

server.ip      =>    表示服务器端IP

client.ip      =>    表示客户端IP

req.request    =>    指定请求的类型,如GET POST PUT DELETE

req.url      =>    知道请求的URL

req.proto      =>    表示客户端发起请求的HTTP协议版本

req.http.header  =>    表示请求中的头部信息

req.restarts    =>    表示请求重启的次数,默认最大值为4

VCL向后端主机请求时使用的内置变量

beresp.request   =>    指定请求的类型,如GET POST

beresp.url      =>    指定请求的地址

beresp.proto    =>    指定请求的协议版本号

beresp.http.header =>    对应请求的HTTP头信息

beresp.ttl      =>    表示缓存的周期,单位秒

从cache或后端主机获取内容后可以使用的内置变量

obj.status     =>    表示返回的状态码,如200 404 500 等

obj.cacheable   =>    表示返回的内容是否可以缓存

obj.valid     =>    表示是否是有效的HTTP应答

obj.response   =>    表示应答的状态信息

obj.ttl      =>    表示返回内容的生存周期,单位秒

obj.lastuse    =>    表示上次请求到现在的间隔,单位秒

客户端应答时可以使用的变量

resp.status    =>    表示返回给客户端的状态码

resp.proto    =>    表示返回给客户端的HTTP协议版本

resp.http.header  =>        表示返回给客户端的头信息

resp.response   =>    表示返回给客户端的状态信息

上面可能不全,具体的可以到其官方网站上面查看

下面笔者有个配置例子,里面有注释,可以瞅瞅

#配置两台后端主机
backend myserver3 {
.host = "192.168.138.3";
.port = "80";
} #配置两台后端主机
backend myserver4 {
.host = "192.168.138.4";
.port = "80";
} #这里定义一个myserver的director
director myserver round-robin {
{.backend = myserver3;}
{.backend = myserver4;}
} acl purge {
"localhost";
"127.0.0.1";
} #recv状态
sub vcl_recv {
#如果访问 laiwojia.la 或者 www.laiwojia.la 就使用该varnish进行代理 前提是你要在你本地配置laiwojia.la这个虚拟主机奥
if (req.http.host ~ "(www.)?laiwojia.la") {
set req.backend = myserver;
} if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
#如果请求的类型不是GET HEAD PUT POST TRACE OPTIONS DELETE 进入pipe模式
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
} #如果不是GET或者HEAD类型的请求 进入到pass模式
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
} #有认证或者cookie存在 进入到pass模式
if (req.http.Authorization || req.http.Cookie) {
/* Not cacheable by default */
return (pass);
} #如果URL中含有.php .jsp .do 并且以此结尾或者后面还有?或者# 进入pass模式
if (req.url ~ "\.(php|jsp|do)($|\?|#)") {
return (pass)
} if (req.request == "PURGE") {
if (!client.ip ~ purge) {
error 405 "Not allowed.";
}
return (lookup);
} return (lookup);
} ub vcl_pipe {
# # Note that only the first request to the backend will have
# # X-Forwarded-For set. If you use X-Forwarded-For and want to
# # have it set for all requests, make sure to have:
# # set bereq.http.connection = "close";
# # here. It is not set by default as it might break some broken web
# # applications, like IIS with NTLM authentication.
return (pipe);
} #
sub vcl_pass {
return (pass);
}
#
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
} sub vcl_hit {
if (req.request == "PURGE") {
purge;
error 200 "Purged.";
} return (deliver);
}
#
sub vcl_miss {
if (req.request == "PURGE") {
purge;
error 200 "Purged.";
} return (fetch);
} sub vcl_fetch { #如果请求的类型是GET 请求url以 html png gif jpeg 等等结尾 进行缓存 缓存时间600s
if (req.request == "GET" && req.url ~ "\.(html|png|gif|jpeg|pdf|ppt|doc|docx|rar|zip|bmp|swf|mp3|mp4|rmvb|mov|avi|css|js|jpeg|htm)$") {
set beresp.ttl = 600s;
} return (deliver);
} sub vcl_deliver {
#给HTTP头上加上标示 用于区分是否命中缓存
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT from www.laiwojia.la";
} else {
set resp.http.X-Cache = "MISS from www.laiwojia.la";
}
return (deliver);
} #当发生错误后返回给客户端的页面
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>"} + obj.status + " " + obj.response + {"</title>
</head>
<body>
<h1>Error "} + obj.status + " " + obj.response + {"</h1>
<p>"} + obj.response + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"};
return (deliver);
} sub vcl_init {
return (ok);
}
#
sub vcl_fini {
return (ok);
}

好了,上面配置就是这样的,然后你要在本地加上   www.laiwojia.la  laiwojia.la 的解析

vim  /etc/hosts

#添加
127.0.0.1 www.laiwojia.la laiwojia.la

千万不要忘记在192.168.138.3  192.168.138.4 这两台机器的nginx上配置 laiwojia.la 这个虚拟机奥,这里笔者贴出配置文件(nginx.conf 部分)

server{
listen 80;
server_name laiwojia.la;
root /usr/website/html/www.laiwojia.la;
index index.html index.htm index.php;
access_log /usr/website/logs/www.laiwojia.la/access.log;
error_log /usr/website/logs/www.laiwojia.la/errors.log;
}

当然上面的 /usr/website/html/www.laiwojia.la 这个目录要有  然后在里面建一个 test.html 里面写上内容,然后做好本地解析

vim  /etc/hosts

#添加
127.0.0.1 www.laiwojia.la laiwojia.la

好,确保两台机器上虚拟机运行没有问题

最后一步:启动varnish

/usr/local/varnish/sbin/varnishd -f /usr/local/varnish/etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000 -a 0.0.0.0:80

这个是笔者在其官方网站上找到的启动方法 -f 就是配置文件  -a 就是IP地址加上端口  我们这里监听80端口

OK,一切完结,我们开始测试下

curl -I  www.laiwojia.la

激动人心的时刻来了

HTTP/1.1 200 OK
Server: nginx/1.6.2
Content-Type: text/html
Last-Modified: Thu, 28 Jan 2016 11:55:24 GMT
ETag: "56aa01ac-f"
Content-Length: 15
Accept-Ranges: bytes
Date: Thu, 28 Jan 2016 12:27:33 GMT
X-Varnish: 100516502
Age: 0
Via: 1.1 varnish
Connection: keep-alive
X-Cache: MISS from www.laiwojia.la

这下是不是要哭,怎么是  X-Cache: MISS from www.laiwojia.la  没有击中啊,不要担心,这是第一次,我们再来一次

HTTP/1.1 200 OK
Server: nginx/1.6.2
Content-Type: text/html
Last-Modified: Thu, 28 Jan 2016 11:55:24 GMT
ETag: "56aa01ac-f"
Content-Length: 15
Accept-Ranges: bytes
Date: Thu, 28 Jan 2016 12:27:45 GMT
X-Varnish: 100516503 100516502
Age: 12
Via: 1.1 varnish
Connection: keep-alive
X-Cache: HIT from www.laiwojia.la

这下终于是久违的 X-Cache: HIT from www.laiwojia.la

OK,这里,大体的配置就完了!

是不是有同学要问了,尼玛这怎么就叫做动静分离了?

想想上面的laiwojia.la 这个域名 ,如果是大家的,大家可以把它配置成 img.xxx.com  之类,文件都上传到这个域名下面(也可以将集群里面的静态文件目录定时复制到这个域名的主机下面),然后大家就可以通过  img.xxx.com 这样的域名访问了。笔者公司是这样做的,我们的静态文件都放在服务器 static 目录里,然后静态文件服务器集群每5分钟复制下这个目录,同时所有上传都上传到静态文件服务器,所有静态文件、图片引用都使用静态文件服务器前缀 img.xxx.com , 为了管理方便,笔者公司里面的静态文件后面都有后缀 '?v=2016012801',只要更换后面的版本号,缓存就会更新,当然了还有内部机制(有专门清理缓存的接口)。这样动态文件在规定的服务器集群,静态文件也在规定的服务器集群,相互分开,大大提升页面加载速度,提高网站吞吐量。

Nginx+Varnish的更多相关文章

  1. Nginx+Varnish 实现动静分离,为服务器分流,降低服务器负载

    相必大家在看加快网站响应速度方面的文章时,都提过这么一条:动静分离.那怎样实现动静分离呢,这里笔者就亲自搭建相关服务实现动静分离. 动静分离是一种架构,就是把静态文件,比如JS.CSS.图片甚至有些静 ...

  2. 如何用DNS+GeoIP+Nginx+Varnish做世界级的CDN

    如何用DNS+GeoIP+Nginx+Varnish做世界级的CDN     如何用BIND, GeoIP, Nginx, Varnish来创建你自己的高效的CDN网络?CDN,意思是Content ...

  3. Nginx+Varnish又开始新的征程了

    要自己多测试一下.总觉得机器不够用.

  4. 15套java架构师、集群、高可用、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩展. ...

  5. java架构师负载均衡、高并发、nginx优化、tomcat集群、异步性能优化、Dubbo分布式、Redis持久化、ActiveMQ中间件、Netty互联网、spring大型分布式项目实战视频教程百度网盘

    15套Java架构师详情 * { font-family: "Microsoft YaHei" !important } h1 { background-color: #006; ...

  6. 15套java架构师、集群、高可用、高可扩 展、高性能、高并发、性能优化Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...

  7. Java架构师系统培训高并发分布式电商实战activemq,netty,nginx,redis dubbo shiro jvm虚拟机视频教程下载

    15套java架构师.集群.高可用.高可扩 展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布 式项目实战视频教程 ...

  8. varnish应用

    Nginx+Varnish+基本业务 ngnix nginx.conf配置文件 user root; worker_processes ; error_log logs/error.log crit; ...

  9. 7.11 如何应用Varnish

    动态数据缓存 Step 1 修改devault.vcl文件 # This ) # man page for details on VCL syntax and semantics. # # Defau ...

随机推荐

  1. 部署到Linux使用VS Code 开发.NET Core 应用程序

    使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台 使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台. 前面讲解了VSCode开发调试 .NE ...

  2. Facial Landmark Detection

    源地址:http://www.learnopencv.com/facial-landmark-detection/#comment-2471797375 OCTOBER 18, 2015 BY SAT ...

  3. [Windows Phone学习笔记]页面之间传递对象

    在Windows Phone中,页面之间传递参数就类似Web开发中一样,通过QueryString的形式进行传递,但是如果需要传递对象,则无法通过QueryString形式了,其实也可以,把对象序列化 ...

  4. [Cocos2d-x]博客推荐

    推荐一下大神们的博客: JackyStudio: http://blog.csdn.net/jackyvincefu/article/category/1591201/3 老G的小屋: http:// ...

  5. MySQL JDBC事务处理、封装JDBC工具类

    MySQL数据库学习笔记(十)----JDBC事务处理.封装JDBC工具类 一.JDBC事务处理: 我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败.在MySQL中提供了Commit. ...

  6. android画笔错位问题的解决

    下面的画画板的代码: public class MainActivity extends Activity { private ImageView iv; private Bitmap baseBit ...

  7. 2013 吉林通化邀请赛 Play Game 记忆化搜索

    dp[ba][ta][bb][tb]表示a堆牌从下面拿了ba张,从上面拿了ta张.b堆牌从下面拿了bb张,从上面拿了tb张.当前玩家能得到的最大的分数. 扩展方式有4种,ba+1,ta+1,bb+1, ...

  8. Android-2手机应用程序,短信应用

    Activity生命周期   Android的核心组件 1.Viiew :界面 ,组织UI控件 2.Intent :意图,支持组件之间的通信 3.Activity:处理界面与UI互动 4.Conten ...

  9. hdu2063+hdu1083(最大匹配数)

    传送门:hdu2063过山车 #include <cstdio> #include <cstring> #include <string> #include < ...

  10. win 开机 Microsoft corparation 滚动栏

    在easybcd里设置  后保存!