varnish动静分离以及负载均衡实例

前言

在我的上一篇关于Nginx的动静分离实现博客中我提到了动静分离的意义,因为动静分离确实是一个有效又容易实现的解决问题的方案,那么这篇博客我再次演示动静分离的实战例子,不过这次的主角不是Nginx,而是varnish。

在下文中我会用varnish实现动静分离并且举例讲解varnish对后端服务器的调度功能以及服务器状态检查功能。


网络拓扑


操作

准备

如上面的网络拓扑图,这次使用到了四台CentOS7.3分别的角色:

1,varnish服务器,IP172.16.253.143,hostname:varnish
2,httpd服务器1,IP172.16.250.135,hostname:html1
3,httpd服务器2,IP172.16.254.235,hostname:html2
4,httpd+php服务器,IP172.16.250.39,hostname:php

整个实验过程中需要注意selinux和防火墙的限制。


第一步,配置httpd服务器和httpd+php服务器

配置httpd服务器是最简单的事了,就不做描述直接演示操作了。

#html1配置
[root@html1 ~]# yum install httpd -y
[root@html1 ~]# echo '<h1>Html1 server</h1>' > /var/www/html/index.html
[root@html1 ~]# systemctl start httpd

#html2配置
[root@html2 ~]# yum install httpd -y
[root@html2 ~]# echo '<h1>Html2 server</h1>' > /var/www/html/index.html
[root@html2 ~]# systemctl start httpd

#php配置
[root@php ~]# yum install php httpd -y
[root@php ~]# echo '<?php phpinfo(); ?>' > /var/www/html/index.php
[root@php ~]# systemctl start httpd

第二步,varnish服务器配置

在这一步中为了让整个配置过程思路更加清晰,我先实现后端只有一动一静服务器这样的拓扑,然后再在这个基础上实现两静一动这个拓扑,因为这样用到varnish的不同功能所以分开演示。

[root@varnish ~]# yum install varnish -y #安装包,varnish包在epel源里
[root@varnish ~]# vim /etc/varnish/default.vcl #打开配置文件
#更改配置文件为:
#注意:在这个配置文件中每一句结尾需要加上分号,不然要报错
backend html1 { #backend是定义后端服务器地址以及端口的,html1是给这个后端服务器命名后面调用
    .host = "172.16.250.135"; #指定IP地址
    .port = "80"; #指定端口号
}

backend php { #这里和上面是一样的,这个地方定义的是php服务器的
    .host = "172.16.250.39";
    .port = "80";
}

sub vcl_recv { #以下内容需写在vcl_recv下
    if (req.url ~ "(?i)\.html") { #这里的意思是如果请求的url和后面双引号中的格式匹配的话就将请求转到html1
        set req.backend_hint = html1;
    }

    if (req.url ~ "(?i)\.php") { #这里表示结尾匹配.php的请求都转到php服务器
        set req.backend_hint = php;
    }
}
[root@varnish ~]# vim /etc/varnish/varnish.params #打开配置文件
#更改默认监听端口6081为80

在正常的生产环境中varnish是不会直接作为前端的,在varnish前面还有诸如nginx的代理服务器,所以如果是完整的架构的话这里的端口改不改都没有什么影响,只是代理服务器在配置代理的时候需要注意一下而已,这里我只是做测试环境所以就直接把默认监听端口改成了80

那么现在就可以启动服务器了

[root@varnish ~]# systemctl start varnish
[root@varnish ~]# ss -ntl #检查端口是否监听
State       Recv-Q Send-Q               Local Address:Port                              Peer Address:Port              
LISTEN      0      128                              *:80                                           *:*                  
LISTEN      0      128                              *:22                                           *:*                  
LISTEN      0      100                      127.0.0.1:25                                           *:*                  
LISTEN      0      10                       127.0.0.1:6082                                         *:*                  
LISTEN      0      128                             :::80                                          :::*                  
LISTEN      0      128                             :::22                                          :::*                  
LISTEN      0      100                            ::1:25                                          :::*                  

第三步,测试

访问172.16.253.143/index.html

如图所示

访问172.16.253.143/index.php

如上图,一切正常


两个静态一个动态拓扑实现

实现方法

从上面的配置可以知道,要把请求代理至后端服务器只需要配置一个backend就行了,但是这样的话同样的后端只能存在一台,这样显然不符合实际,那么后端服务器要实现负载均衡又怎么做呢。

varnish在实现后端服务器负载均衡的方法上和nginx类似但是略有不同,都是将多台服务器定义为一个组然后再调用,那么具体配置方法请看下面的操作。

[root@varnish ~]# vim /etc/varnish/default.vcl #打开配置文件
#添加以下内容
backend html2 { #增加html2的配置
    .host = "172.16.254.235";
    .port = "80";
}
sub vcl_init { #这个要注意这是一个新的sub,是配置文件中的根配置,不能存在于其他任何sub中
    new htmls = directors.round_robin(); #命名服务器组为htmls,定义调度算法为轮询
    htmls.add_backend(html1); #添加组成员html1
    htmls.add_backend(html2); #添加组成员html2
}
#既然定义了静态服务器的组,那么在给后端服务器转发请求的时候就不能指定html1了需要指定htmls组
set req.backend_hint = htmls.backend(); #更改这一句中html1为htmls.backend()

写成这样基本上就已经完成了,下面可以测试一下


测试

其实在上面一步我留了一个坑,为了加深印象,我将需要注意的一个重要的问题写在测试这里。

那么配置文件我似乎已经配置完毕,现在重载一下配置文件然后测试结果

[root@varnish ~]# varnish_reload_vcl #重载配置文件
Loading vcl from /etc/varnish/default.vcl
Current running config name is 
Using new config name reload_2017-09-08T16:37:32
Message from VCC-compiler:
Symbol not found: 'directors.round_robin' at ('input' Line 32 Pos 17)
    new htmls = directors.round_robin();
----------------#####################---

Running VCC-compiler failed, exited with 2
VCL compilation failed
Command failed with error code 106
varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 vcl.load failed
[root@varnish ~]# 

如上所示,出现了报错信息,仔细一看错误提醒可以发现错误在directors.round_robin()上面,出现这个错误的原因是因为我没有加载directors模块,这个很重要千万不能忘了。那么现在我加上去然后再次重载配置文件

[root@varnish ~]# vim /etc/varnish/default.vcl #打开配置文件在vcl4.0下加上这么一句
import directors;
[root@varnish ~]# varnish_reload_vcl 
Loading vcl from /etc/varnish/default.vcl
Current running config name is 
Using new config name reload_2017-09-08T16:44:30
VCL compiled.
VCL 'reload_2017-09-08T16:44:30' now active
available       0 boot
active          0 reload_2017-09-08T16:44:30

Done
[root@varnish ~]#  #顺利加载

虽然现在配置文件已经配置完毕,服务也正常,可以测试却有点尴尬了。因为varnish是缓存服务,后端静态网页服务器虽然设置的是轮询但是只要第一次访问成功,varnish就会把页面缓存下来下次访问的时候就提供已经缓存了的页面,那么无论怎么刷新页面都是同一个网页,这就很尴尬了。

不过也是有办法的,我可以清理一次缓存然后访问一次,但是需要写配置文件。

[root@varnish ~]# vim /etc/varnish/default.vcl #打开配置文件添加以下内容:
sub vcl_purge {
    return (synth(200,"Purged"));
}
if (req.method == "PURGE") { #在sub vcl_recv下添加
    return(purge);
}
[root@varnish ~]# varnish_reload_vcl 
Loading vcl from /etc/varnish/default.vcl
Current running config name is 
Using new config name reload_2017-09-08T16:59:09
VCL compiled.
VCL 'reload_2017-09-08T16:59:09' now active
available       0 boot
available       0 reload_2017-09-08T16:44:30
active          0 reload_2017-09-08T16:59:09

Done
[root@varnish ~]#  #重载配置文件

现在我开启另外一台服务器利用crul -X PURGE便可以清理缓存,现在开始测试吧。

[root@client ~]# curl http://172.16.253.143/index.html
<h1>Html1 server</h1>
[root@client ~]# curl http://172.16.253.143/index.html
<h1>Html1 server</h1>
#我这里连续访问两次都是html1在相应,那么我清理一次缓存再访问
[root@client ~]# curl -X PURGE http://172.16.253.143/index.html #清理缓存
<!DOCTYPE html>
<html>
  <head>
    <title>200 Purged</title> #清理成功
  </head>
  <body>
    <h1>Error 200 Purged</h1>
    <p>Purged</p>
    <h3>Guru Meditation:</h3>
    <p>XID: 65593</p>
    <hr>
    <p>Varnish cache server</p>
  </body>
</html>
[root@client ~]# curl http://172.16.253.143/index.html #然后再次访问
<h1>Html2 server</h1> #成功!!
[root@client ~]# 

可以看到清理缓存之后顺利访问到了html2,如果现在再次清理一下缓存再访问的话又可以访问到hmtl1了,后面就不再演示了。


完结撒花,要转载的朋友请注明转载,谢谢。