热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

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

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

 

动静分离是一种架构,就是把静态文件,比如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 {"
 "1.0" encoding="utf-8"?>
 "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
   <head>
     
   head>
   
     

Error "} + obj.status + " " + obj.response + {"

"} + obj.response + {"

Guru Meditation:

XID: "} + req.xid + {"


Varnish cache server

"}; 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',只要更换后面的版本号,缓存就会更新,当然了还有内部机制(有专门清理缓存的接口)。这样动态文件在规定的服务器集群,静态文件也在规定的服务器集群,相互分开,大大提升页面加载速度,提高网站吞吐量。

 

好了,笔者不才,希望上面这些对大家有所帮助!


推荐阅读
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文内容为asp.net微信公众平台开发的目录汇总,包括数据库设计、多层架构框架搭建和入口实现、微信消息封装及反射赋值、关注事件、用户记录、回复文本消息、图文消息、服务搭建(接入)、自定义菜单等。同时提供了示例代码和相关的后台管理功能。内容涵盖了多个方面,适合综合运用。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
author-avatar
94爱拍就是爱拍
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有