第五周负载及缓存

1、运用haproxy实现nginx服务负载均衡

http://cbonte.github.io/haproxy-dconv/1.5/configuration.html #github之上的文档手持地址

docker pull nginx:alpine #使用docker拉取nginx镜像

[root@centos7 ~]# docker run --name web1 -d --network bridge nginx:alpine #启动容器

WARNING: IPv4 forwarding is disabled. Networking will not work.

4055e0d579ff7f0ef999322ab6d698ce7f7d15f1e049231b848e9704a390545a

[root@centos7 ~]# docker run --name web2 -d --network bridge nginx:alpine#启动容器

exec -it web1 /bin/sh #连接容器

/  # cd /usr/share/nginx/html

/usr/share/nginx/html # echo hello world 1 > /usr/share/nginx/index.html #修改一下测试页

[root@centos7 ~]# docker exec -it web2 /bin/sh

/ # echo hello world 2 > /usr/share/nginx/html/index.html

 

vim /etc/haproxy/haproxy.cfg

修改配置文件在frontend 字段中指定前段调度监听的端口为80,调度到后端websrvs组。定义后端backend组 组名为websrvs ,组内服务器172.17.0.2|0.3这两台主机。

frontend myweb *:80

        default_backend websrvs

backend websrvs

        server web1 172.17.0.2:80 check

        server web1 172.17.0.3:80 check

 


测试调度成功

listen http_proxy #也可以使用listen将前端和后端定义在一起,定义多端口,

        bind :80,:8080 #也可以使用bind绑定端口

#      default_backend websrvs

#backend websrvs

        server web1 172.17.0.2:80 check

        server web2 172.17.0.3:80 check

 

 

balance:后端服务器组内的服务器调度算法只能定义在backend和listen中

balance <algorithm> [ <arguments> ]

balance url_param <param> [check_post]

算法:

roundrobin:Each server is used in turns, according to their weights.

server options: weight #

动态算法:支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个server;

static-rr:

静态算法:不支持权重的运行时调整及慢启动;后端主机数量无上限;

leastconn:

推荐使用在具有较长会话的场景中,例如MySQL、LDAP等;

first:

根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务;

source:源地址hash;

除权取余法:

一致性哈希:

uri:

对URI的左半部分做hash计算,并由服务器总权重相除以后派发至某挑出的服务器;

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

左半部分:/<path>;<params>

整个uri:/<path>;<params>?<query>#<frag>

username=jerry

 

url_param:对用户请求的uri的<params>部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server;

                            username=tom

hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度;

hdr(Cookie)

rdp-cookie

rdp-cookie(<name>)

hash-type:哈希算法

hash-type <method> <function> <modifier>

map-based:除权取余法,哈希数据结构是静态的数组;

consistent:一致性哈希,哈希数据结构是一个树;

<function> is the hash function to be used : 哈希函数

sdbm

djb2

wt6

示例

balance roundrobin

balance url_param userid

balance url_param session_id check_post 64

balance hdr(User-Agent)

balance hdr(host)

balance hdr(Host) use_domain_only

 

server <name> <address>[:[port]] [param*]

定义后端主机的各服务器及其选项;

server <name> <address>[:port] [settings ...]

default-server [settings ...]

<name>:服务器在haproxy上的内部名称;出现在日志及警告信息中;

<address>:服务器地址,支持使用主机名;

[:[port]]:端口映射;省略时,表示同bind中绑定的端口;

[param*]:参数

maxconn <maxconn>:当前server的最大并发连接数;

backlog <backlog>:当前server的连接数达到上限后的后援队列长度;

backup:设定当前server为备用服务器;

check:对当前server做健康状态检测;

addr :检测时使用的IP地址;

port :针对此端口进行检测;

inter <delay>:连续两次检测之间的时间间隔,默认为2000ms;

rise <count>:连续多少次检测结果为“成功”才标记服务器为可用;默认为2;

fall <count>:连续多少次检测结果为“失败”才标记服务器为不可用;默认为3;

 

注意:option httpchk,"smtpchk", "mysql-check", "pgsql-check" and "ssl-hello-chk" 用于定义应用层检测方法;

cookie <value>:为当前server指定其cookie值,用于实现基于cookie的会话黏性;

disabled:标记为不可用;

on-error <mode>:后端服务故障时的行动策略;

                                - fastinter: force fastinter

                                - fail-check: simulate a failed check, also forces fastinter (default)

                                - sudden-death: simulate a pre-fatal failed health check, one more failed

                                check will mark a server down, forces fastinter

                                - mark-down: mark the server immediately down and force fastinter

redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL;

server web2 172.17.0.3:80 redir http://www.baidu.com #示例

weight <weight>:权重,默认为1;

                        OK --> PROBLEM

                            OK --> PROBLEM --> PROBLEM --> PROBLEM

                        PROBLEM --> OK

 

统计接口启用相关的参数:

stats enable

启用统计页;基于默认的参数启用stats page;

- stats uri  : /haproxy?stats

- stats realm : "HAProxy Statistics"

- stats auth  : no authentication

- stats scope : no restriction

stats auth <user>:<passwd>

认证时的账号和密码,可使用多次;

stats realm <realm>

认证时的realm;

stats uri <prefix>

自定义stats page uri

stats refresh <delay>

设定自动刷新时间间隔;

stats admin { if | unless } <cond>

启用stats page中的管理功能

配置示例:

listen stats

bind :9099

stats enable

stats realm HAPorxy\ Stats\ Page #登录时验证提示信息

stats auth admin:admin

stats admin if TRUE

 

#############在frontend 加入stats enable 即可访问

frontend myweb

       bind :80,:8080

        default_backend websrvs

backend websrvs

        server web1 172.17.0.2:80 check

        server web2 172.17.0.3:80 check

listen stats :9090

        stats enable

        stats uri /admin ?stats #自定义修改页面路径

 

 


 

mode { tcp|http|health }

定义haproxy的工作模式;

tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议;

http:仅当代理的协议为http时使用;

health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接;

 

cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]

<name>:is the name of the cookie which will be monitored, modified or inserted in order to bring persistence.

rewirte:重写;

insert:插入;

prefix:前缀;

基于cookie的session sticky的实现:

backend websrvs

cookie WEBSRV insert nocache indirect #定义cookie的名称和插入cookie报文的信息,这里的名称并不重要

server srv1 172.16.100.6:80 weight 2 check rise 1 fall 2 maxconn 3000 cookie srv1 #定义cookie名

server srv2 172.16.100.7:80 weight 1 check rise 1 fall 2 maxconn 3000 cookie srv2

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

Enable insertion of the X-Forwarded-For header to requests sent to servers

在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,其值前端客户端的地址;用于向后端主发送真实的客户端IP;

 

reqadd <string> [{if | unless} <cond>]

Add a header at the end of the HTTP request

rspadd <string> [{if | unless} <cond>]

Add a header at the end of the HTTP response

rspadd X-Via:\ HAPorxy

reqdel  <search> [{if | unless} <cond>]

reqidel <search> [{if | unless} <cond>]  (ignore case)

Delete all headers matching a regular expression in an HTTP request

rspdel  <search> [{if | unless} <cond>]

rspidel <search> [{if | unless} <cond>]  (ignore case)

Delete all headers matching a regular expression in an HTTP response

rspidel  Server.*

日志系统:

log:

log global

log <address> [len <length>] <facility> [<level> [<minlevel>]]

no log

注意:

默认发往本机的日志服务器;

(1) local2.*      /var/log/local2.log

(2) $ModLoad imudp

$UDPServerRun 514

log-format <string>:

 

对后端服务器做http协议的健康状态检测:

option httpchk

option httpchk <uri>

option httpchk <method> <uri>

option httpchk <method> <uri> <version>

定义基于http协议的7层健康状态检测机制;

http-check expect [!] <match> <pattern>

Make HTTP health checks consider response contents or specific status codes.

 

配置HAProxy支持https协议:

1 支持ssl会话;

bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE

crt后的证书文件要求PEM格式,且同时包含证书和与之匹配的所有私钥;

cat  demo.crt demo.key > demo.pem

2 把80端口的请求重向定443;

bind *:80

redirect scheme https if !{ ssl_fc }

另一种配置:对非ssl的任何url的访问统统定向至https主机的主页;

            redirect location https://172.16.0.67/ if !{ ssl_fc }

3 如何向后端传递用户请求的协议和端口

http_request set-header X-Forwarded-Port %[dst_port]

http_request add-header X-Forwared-Proto https if { ssl_fc }

    配置时常用的功能:

        http --> https

 

        mode http

        压缩、条件式转发、算法、stats page、自定义错误页、访问控制、日志功能

        最大并发连接;

            global, defaults, frontend, listen, server

        基于cookie的session粘滞

        后端主机的健康状态检测

        请求和响应报文首部的操纵

 

acl:

访问控制列表(ACL)的使用提供了一种灵活的解决方案来执行内容切换,并且通常基于从请求,响应或任何环境状态中提取的内容来做出决策

acl <aclname> <criterion> [flags] [operator] [<value>] ...

<aclname>:ACL names must be formed from upper and lower case letters, digits, '-' (dash), '_' (underscore) , '.' (dot) and ':' (colon).ACL names are case-sensitive.

<value>的类型:

- boolean

- integer or integer range

- IP address / network

- string (exact, substring, suffix, prefix, subdir, domain)

- regular expression

- hex block

匹配字符串:

- exact match    (-m str) : the extracted string must exactly match the patterns ;

- substring match (-m sub) : the patterns are looked up inside the extracted string, and the ACL matches if any of them is found inside ;

- prefix match    (-m beg) : the patterns are compared with the beginning of the extracted string, and the ACL matches if any of them matches.

- suffix match    (-m end) : the patterns are compared with the end of the extracted string, and the ACL matches if any of them matches.

- subdir match    (-m dir) : the patterns are looked up inside the extracted string, delimited with slashes ("/"), and the ACL matches if any of them matches.

- domain match    (-m dom) : the patterns are looked up inside the extracted string, delimited with dots ("."), and the ACL matches if any of them matches.

acl作为条件时的逻辑关系:

- AND (implicit)

- OR  (explicit with the "or" keyword or the "||" operator)

- Negation with the exclamation mark ("!")

if invalid_src invalid_port #与

if invalid_src || invalid_port #或

if ! invalid_src invalid_port#非

 

基于ACL的动静分离示例:

frontend  web *:80

acl url_static      path_beg      -i  /static /images /javascript /stylesheets

acl url_static      path_end      -i  .jpg .gif .png .css .js .html .txt .htm

use_backend staticsrvs          if url_static

default_backend            appsrvs

backend staticsrvs

balance    roundrobin

server      stcsrv1 172.16.100.6:80 check

backend appsrvs

balance    roundrobin

server  app1 172.16.100.7:80 check

server  app1 172.16.100.7:8080 check

listen stats

bind :9091

stats enable

stats auth admin:admin

stats admin if TRUE

 

 

 

 

 

 

global配置参数:

进程及安全管理:chroot, daemon,user, group, uid, gid

log:定义全局的syslog服务器;最多可以定义两个;

log <address> [len <length>] <facility> [max level [min level]]

nbproc <number>:要启动的haproxy的进程数量;

ulimit-n <number>:每个haproxy进程可打开的最大文件数;

性能调整:

maxconn <number>:设定每个haproxy进程所能接受的最大并发连接数;Sets the maximum per-process number of concurrent connections to <number>.

                        总体的并发连接数:nbproc * maxconn

maxconnrate <number>:Sets the maximum per-process number of connections per second to <number>. 每个进程每秒种所能创建的最大连接数量;

maxsessrate <number>:设定会话常见速率

maxsslconn <number>: Sets the maximum per-process number of concurrent SSL connections to <number>.

                        设定每个haproxy进程所能接受的ssl的最大并发连接数;

spread-checks <0..50, in percent>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2、搭建haproxy实现mysql负载均衡

docker pull mysql:5.7 #拉取镜像

[root@centos7 haproxy]# docker run --name db1 -d e "MYSQL_ROOT_PASSWORD=123456" mysql:5.7 #启动容器1

[root@centos7 haproxy]# docker run --name db2 -d e "MYSQL_ROOT_PASSWORD=123456" mysql:5.7 #启动容器2

 

docker exec -it db1 /bin/sh #连接容器创建账号

mysql> GRANT ALL ON *.* to 'myuser'@'%' identified by '123456';

docker exec -it db1 /bin/sh 

mysql> GRANT ALL ON *.* to 'myuser'@'%' identified by '123456';

yum install haproxy

 

修改配置

vi/etc/haproxy/haproxy.cfg

 

配置如下

global

daemon

nbproc 1

pidfile /var/run/haproxy.pid

defaults

mode tcp               #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK

retries 3               #两次连接失败就认为是服务器不可用,也可以通过后面设置

option redispatch       #当serverId对应的服务器挂掉后,强制定向到其他健康的服务器

option abortonclose     #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接

maxconn 4096            #默认的最大连接数

timeout connect 5000ms  #连接超时

timeout client 30000ms  #客户端超时

timeout server 30000ms  #服务器超时

timeout check 2000      #=心跳检测超时

log 127.0.0.1 local0 err #[err warning info debug]

listen configMysql

bind :3306

mode tcp

maxconn 4086

server s1 172.17.0.2:3306

server s2 172.17.0.3:3306

启动

在解压目录下执行haproxy -f /etc/haproxy/haproxy.cfg

或者使用

 

 

 

 

 

3、搭建tomcat服务器, 并通过nginx反向代理访问

Tomcat安装

tomcat下载

进入官网,在左侧download中选择对应tomcat主版本,然后点击右侧的Archives,找到对应的具体版本后进入到bin目录下载tar.gz包,点击Which version查看Tomcat版本对应的JDK版本要求。

这里我们下载的版本是7.0.73


 

安装步骤

首先确保已经安装好了jdk,并且jdk版本能够满足当前Tomcat的版本要求。

解压缩:tar -zxvf apache-tomcat-7.0.73.tar.gz

将tomcat移到安装软件位置:mv apache-tomcat-7.0.73 /usr/local/

环境变量配置

编辑环境变量配置文件:vim /etc/profile

在文件末尾位置添加如下内容(CATALINA_HOME为安装tomcat的路径)

export CATALINA_HOME=/usr/local/apache-tomcat-7.0.73

通过vim的 ":wq" 命令进行保存退出

使配置生效:source /etc/profile

字符集配置

进入tomcat安装目录的conf目录,编辑server.xml文件

cd /usr/local/apache-tomcat-7.0.73/

vim server.xml

找到配置8080端口的位置,在节点末尾添加URIEncoding="UTF-8"


 

tomcat验证

进入tomcat安装目录的bin目录,执行./startup.sh,看到如图提示代表启动成功。


 

可以通过主机的ip地址+8080端口访问tomcat主页,比如:http://192.168.0.110:8080/

需要注意检查防火墙是否关闭,如果未关闭需要配置iptables规则开放8080端口。

关闭iptables规则:iptables -F & iptables -t nat -F

Tomcat启动与关闭

Tomcat启动:${CATALINA_HOME}/bin/startup.sh

Tomcat关闭:${CATALINA_HOME}/bin/shutdown.sh

${CATALINA_HOME}代表tomcat的安装路径

这里将nginx和tomcat都安装在/usr/local目录下,tomcat目录分别命名为tomcat1和tomcat2。

配置环境变量

vim /etc/profile# 在文件末尾添加如下内容

export CATALINA_BASE=/usr/local/tomcat1export CATALINA_HOME=/usr/local/tomcat1export

TOMCAT_HOME=/usr/local/tomcat1export 

CATALINA_2_BASE=/usr/local/tomcat2export 

CATALINA_2_HOME=/usr/local/tomcat2export 

TOMCAT_2_HOME=/usr/local/tomcat2# 通过vim的 ":wq" 命令进行保存退出# 使配置生效source /etc/profile

修改两个tomcat的编码

vim ${tomcat}/conf/server.xml

进入tomcat安装目录,编辑conf目录下的server.xml文件,找到如下节点添加编码配置:URIEncoding="UTF-8"

<Connectorport="8080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"URIEncoding="UTF-8"/>

修改第二个tomcat的配置

修改第二个tomcat的bin目录下的catalina.sh文件,找到# OS注释内容,在其下面新增配置

vim/usr/local/tomcat2/bin/catalina.sh# 新增如下配置# OS specific support.  $var _must_ be set to either true or false.export CATALINA_BASE=$CATALINA_2_BASEexport CATALINA_HOME=$CATALINA_2_HOME

修改第二个tomcat的conf目录下的server.xml文件,,修改3个端口配置

vim /usr/local/tomcat2/conf/server.xml# 修改以下3个端口,修改为9005,9080,9009<Serverport="9005"shutdown="SHUTDOWN"><ListenerclassName="org.apache.catalina.startup.VersionLoggerListener"/><Connectorport="9080"protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443"URIEncoding="UTF-8"/><Connectorport="9009"protocol="AJP/1.3"redirectPort="8443"/>

为了方便对两个tomcat进行区分,我们修改第二个tomcat的主页logo图片,即替换/usr/local/tomcat2/webapps/ROOT/tomcat.png,图片名保持一致。

防火墙配置

如果开启了防火墙,需要配置防火墙规则,先将两个tomcat的端口进行开放,主要是为了测试,在配置了Nginx负载均衡后就可以关闭端口了。

vim /etc/sysconfig/iptables# 添加如下规则-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT-A INPUT -p tcp -m tcp --dport 9080 -j ACCEPT# 重启iptablesservice iptables restart

tomcat验证

分别启动两个tomcat,即执行命令:${tomcat}/bin/startup.sh

注意检查两个tomcat启动使用的环境变量是否正确。


 

分别访问两个tomcat,这里是在windows下访问虚拟机的IP + 端口。


 

修改nginx主配置文件nginx.conf

vim /usr/local/nginx/conf/nginx.conf# 在注释内容上面添加如下内容include vhost/*.conf;# another virtual host

在Nginx安装目录的conf目录下新建一个vhost目录,然后在vhost目录下新建配置文件,文件名需要以.conf结尾

cd /usr/local/nginx/conf/mkdir vhostcd vhost/vim www.silly.com.conf

配置文件添加如下内容,这里server_name配置的是主机对应的域名,proxy_pass是反向代理配置,upstream是负载均衡配置。

upstream www.silly.com{

        server 127.0.0.1:8080 weight=1;

        server 127.0.0.1:9080 weight=2;

}

server {

    listen 80;

    autoindex on;

    server_name silly.com www.silly.com;

    access_log /usr/local/nginx/logs/access.log combined;

    index index.html index.htm index.jsp index.php;

    location / {

        proxy_pass http://www.silly.com;

        add_header Access-Control-Allow-Origin *;

    }

}

 

4、采用varnish为nginx实现缓存加速

使用epel中仓库自带varnish安装包

yum install epel-release varnish

varnish中配置文件

/etc/varnish/default.vcl #用来定义缓存策略的配置文件

/etc/varnish/varnish.params #用来定义进程状态端口等,本身没有配置参数,这个配置文件会把自身定义的变量传递给unitfile文件,启动时通过配置文件定义的参数来启动

[root@centos7 ~]# cat /etc/varnish/varnish.params

 


 

cat /usr/lib/systemd/system/varnish.service#服务单元启动时都调用了param文件中的变量


 

修改varnish.params配置文件

 

RELOAD_VCL=1

VARNISH_VCL_CONF=/etc/varnish/default.vcl #加载默认vcl配置文件,可修改

VARNISH_LISTEN_PORT=80 #监听的端口默认为6081,客户端监听端口

VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 #监听在本机地址

VARNISH_ADMIN_LISTEN_PORT=6082#管理端口

VARNISH_SECRET_FILE=/etc/varnish/secret #秘钥文件

VARNISH_STORAGE="file,/var/cache/varnish/,2G" #缓存的类型,大小,可用内存缓存,文件缓存等。。malloc基于内存缓存。file表示为磁盘缓存,需要varnish用户对此目录拥有权限

VARNISH_USER=varnish #运行varnish进程的用户

VARNISH_GROUP=varnish

mkdir /var/cache/varnish/ #创建缓存目录

chown -R varnish.varnish /var/cache/varnish/ #修改缓存目录所属用户及组

systemctl start varnish 启动varnish

 

docker pull nginx:1.14-alpine #使用容器拉取镜像,使用varnish作为前端

docker run --name web1 -d nginx:1.14-alpine #启动容器

 

查看容器地址


 

 

 


修改配置文件监听后端的地址及端口

 

[root@centos7 varnish]# varnish_reload_vcl  #重新加载新vcl文件

Loading vcl from /etc/varnish/default.vcl 加载配置文件

Current running config name is

Using new config name reload_2019-09-16T04:42:42

VCL compiled. 编译

VCL 'reload_2019-09-16T04:42:42' now active

available      0 boot #随系统启动的vcl文件。未启动

active          0 reload_2019-09-16T04:42:42#当前正在使用的vcl版本即我们修改后的版本

Done

 


缓存成功

命令端接口varnishadm管理varnish

[root@centos7 varnish]# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 #-S指定秘钥文件 -T 指定主机(本机)及端口

200       

-----------------------------

Varnish Cache CLI 1.0

-----------------------------

Linux,3.10.0-693.el7.x86_64,x86_64,-sfile,-smalloc,-hcritbit

varnish-4.0.5 revision 07eff4c29

Type 'help' for command list.

Type 'quit' to close CLI session.

 


 

help [<command>]

ping [<timestamp>]

auth <response> #认证

quit

banner #欢迎信息

status#状态信息

start#开启varnish进程

stop#关闭

vcl.load <configname> <filename> #与vcl相关,加载vcl文件进来

vcl.inline <configname> <quoted_VCLstring>

vcl.use <configname>#切换vcl文件

vcl.discard <configname>

vcl.list #显示vcl文件

param.show [-l] [<param>] #定义进程工作特性,即使生效,重启失效

param.set <param> <value>

panic.show

panic.clear

storage.list#存储相关

vcl.show [-v] <configname>

backend.list [<backend_expression>] #后端服务器相关

backend.set_health <backend_expression> <state>

ban <field> <operator> <arg> [&& <field> <oper> <arg>]...

ban.list #缓存清理相关

vcl.show -v boot #查看默认的vcl规则

varnish的vcl文件常用变量

变量类型:

内建变量:

req.*:request,表示由客户端发来的请求报文相关;

req.http.*

req.http.User-Agent, req.http.Referer, ...

bereq.*:由varnish发往BE主机的httpd请求相关;Backend 后端主机

bereq.http.*

beresp.*:由BE主机响应给varnish的响应报文相关;

beresp.http.*

resp.*:由varnish响应给client相关;

obj.*:存储在缓存空间中的缓存对象的属性;只读;

举例:obj.hits是内建变量,用于保存某缓存项的从缓存中命中的次数;

vim /etc/varnish/default.vcl 

sub vcl_deliver{ #定义在deliver阶段,不能定义在recv(接受客户端请求阶段)和backend_response(后端服务器响应阶段)

if (obj.hits>0) {

set resp.http.X-Cache = "HIT via" + " " + server.ip;

} else {

set resp.http.X-Cache = "MISS from " + server.ip;

}

}

varnish> vcl.load test1 default.vcl  加载配置文件进来,并且改名为test1

200       

VCL compiled.

vcl.use test1 切换到test1 vcl文件 

200       

VCL 'test1' now active

vcl.list

200       

available      0 boot

available      0 reload_2019-09-16T04:42:42

active          0 test1

varnish_reload_vcl #也可以使用此命令重新加载配置文件


1

curl -I http://172.17.0.1 访问本机请求的头部值,查看,第一次为miss第二次为hit


 

 

VCL有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离;每个状态引擎可使用return(action)指明关联至哪个下一级引擎;每个状态引擎对应于vcl文件中的一个配置段,即为subroutine

                vcl_init

                vcl_recv,

                    vcl_synth

                    vcl_pipe

                    vcl_pass

                    vcl_hash

                        vcl_hit

                            vcl_deliver

                        vcl_miss

                        vcl_pass

                            vcl_backend_fetch

                                vcl_backend_error

                                vcl_backend_response

                                    vcl_deliver

vcl的语法格式:

(1) VCL files start with “vcl 4.0;”

(2) //, # and /* foo */ for comments; #注释

(3) Subroutines are declared with the sub keyword; 例如sub vcl_recv { ...};#每一个子例程都要用sub 加上关键词之内,

(4) No loops, state-limited variables(受限于引擎的内建变量);#不支持循环

(5) Terminating statements with a keyword for next action as argument of the return() function, i.e.: return(action);用于实现状态引擎转换;#指定吓一跳是谁

(6) Domain-specific;

流程示意图

 


 

定义哪些能缓存,哪些不能缓存的项

sub vcl_recv {  #在recv阶段调整访问login界面时不能被缓存,直接发往后端。

        if(req.url ~ "^/login") {

                return(pass);

}

docker exec -it web1 /bin/sh #进入容器创建页面

echo hello index nginx >> /usr/share/nginx/html/login

####访问login界面便不会再名字缓存,访问普通首页即会缓存

 


 

vcl变量

变量类型:

内建变量:

req.*:request,表示由客户端发来的请求报文相关;

req.http.*

req.http.User-Agent, req.http.Referer, ...

bereq.*:由varnish发往BE主机的httpd请求相关;

bereq.http.*

beresp.*:由BE主机响应给varnish的响应报文相关;

beresp.http.*

resp.*:由varnish响应给client相关;

obj.*:存储在缓存空间中的缓存对象的属性;只读;

常用变量:

bereq.*, req.*:

bereq.http.HEADERS

bereq.request, req.request:请求方法;

bereq.url, req.url:请求的url;

bereq.proto,req.proto:请求的协议版本;

bereq.backend:指明要调用的后端主机;

req.http.Cookie:客户端的请求报文中Cookie首部的值;

req.http.User-Agent ~ "chrome"

beresp.*, resp.*:

beresp.http.HEADERS

beresp.status, resp.status:响应的状态码;

reresp.proto, resp.proto:协议版本;

beresp.backend.name:BE主机的主机名;

beresp.ttl:BE主机响应的内容的余下的可缓存时长;

obj.*

obj.hits:此对象从缓存中命中的次数;

obj.ttl:对象的ttl值

server.*

server.ip:varnish主机的IP;

server.hostname:varnish主机的Hostname;

client.*

client.ip:发请求至varnish主机的客户端IP;

 

缓存对象的修剪:purge, ban

            配置purge操作:

                (1) 能执行purge操作

                    sub vcl_purge { #定义purge方法。

                        return (synth(200,"Purged")); #返回200 清理成功

                    }

 

                (2) 何时执行purge操作

                    sub vcl_recv { #这个配置项是接收请求时,发现是purge则会掉上面定义好的purge方法清理缓存

                        if (req.method == "PURGE") {

                            return(purge);  

                        }

                        ...

                    }

 

curl -X PURGE http://172.17.0.1 #模拟purge方法清理缓存

添加此类请求的访问控制法则:

acl purgers {

"127.0.0.0"/8;

"10.1.0.0"/16;

}

sub vcl_recv {

if (req.method == "PURGE") {

if (!client.ip ~ purgers) {

return(synth(405,"Purging not allowed for " + client.ip));

}

return(purge);

}

...

}

Banning: #使用ban命令清理指定页面的缓存

(1) varnishadm:

ban <field> <operator> <arg> #在命令行中使用ban命令清理指定缓存

示例:

ban req.url ~ (?i)^/javascripts

(2) 在配置文件中定义,使用ban()函数;

示例:

if (req.method == "BAN") {

ban("req.http.host == " + req.http.host + " && req.url == " + req.url);

# Throw a synthetic page so the request won't go to the backend.

return(synth(200, "Ban added"));

}

curl -X BAN http://www.ilinux.io/test1.html

ban req.http.host==www.ilinux.io && req.url==/test1.html

 

如何设定使用多个后端主机:

backend default {

.host = "172.16.100.6";

.port = "80";

}

backend appsrv {

.host = "172.16.100.7";

.port = "80";

}

sub vcl_recv {

if (req.url ~ "(?i)\.php$") {

set req.backend_hint = appsrv;

} else {

set req.backend_hint = default;

}

...

}

nginx: proxy_pass

haproxy: use_backend

 

BE Health Check:#健康状态检测

backend BE_NAME {

.host = 

.port =

.probe = {

.url=

.timeout=

.interval=

.window=

.threshold=

}

}

.probe:定义健康状态检测方法;

.url:检测时要请求的URL,默认为”/";

.request:发出的具体请求;

.request =

"GET /.healthtest.html HTTP/1.1"

"Host: www.magedu.com"

"Connection: close"

.window:基于最近的多少次检查来判断其健康状态;

.threshold:最近.window中定义的这么次检查中至有.threshhold定义的次数是成功的;成功阈值;

.interval:检测频度;

.timeout:超时时长;

.expected_response:期望的响应码,默认为200;

健康状态检测的配置方式:

probe check {

.url = "/.healthcheck.html";

.window = 5;

.threshold = 4;

.interval = 2s;

.timeout = 1s;

}

backend default {

.host = "10.1.0.68";

.port = "80";

.probe = check;

}

backend appsrv {

.host = "10.1.0.69";

.port = "80";

.probe = check;

}

            手动设定BE主机的状态:

                sick:管理down;

                healthy:管理up;

                auto:probe auto;

 

varnish做负载均衡配置示例

Director:#需要导入此模块来做负载均衡

varnish module;

使用前需要导入:

import directors;

示例:

import directors;    # load the directors

示例: 1定义后端机器。2将后端服务器分组加入GROUP中,并指定其调度算法

backend imgsrv1 {

.host = "192.168.10.11";

.port = "80";

}

backend imgsrv2 {

.host = "192.168.10.12";

.port = "80";

}

backend appsrv1 {

.host = "192.168.10.21";

.port = "80";

}

backend appsrv2 {

.host = "192.168.10.22";

.port = "80";

}

sub vcl_init {

new imgsrvs = directors.random();

imgsrvs.add_backend(imgsrv1,10);

imgsrvs.add_backend(imgsrv2,20);

new staticsrvs = directors.round_robin();

appsrvs.add_backend(appsrv1);

appsrvs.add_backend(appsrv2);

new appsrvs = directors.hash();

appsrvs.add_backend(appsrv1,1);

appsrvs.add_backend(appsrv2,1);

}

sub vcl_recv {

if (req.url ~ "(?i)\.(css|js)$" {

set req.backend_hint = staticsrvs.backend();

}

if (req.url ~ "(?i)\.(jpg|jpeg|png|gif)$" {

set req.backend_hint = imgsrvs.backend();

} else {

set req.backend_hint = appsrvs.backend(req.http.cookie);

}

}

基于cookie的session sticky:

sub vcl_init {

new h = directors.hash();

h.add_backend(one, 1);  // backend 'one' with weight '1'

h.add_backend(two, 1);  // backend 'two' with weight '1'

}

sub vcl_recv {

// pick a backend based on the cookie header of the client

set req.backend_hint = h.backend(req.http.cookie);

}

设置后端的主机属性:

backend BE_NAME {

...

.connect_timeout = 0.5s; #超时时长

.first_byte_timeout = 20s; #发送报文时第一字节传输时长

.between_bytes_timeout = 5s;#从后端服务器接收报文超时时长,字节和字节之间传输间隔时间

.max_connections = 50; #与后端服务器最大并非连接

}

varnish的运行时参数:

线程模型:

cache-worker

cache-main

ban lurker

acceptor:

epoll/kqueue:

...

线程相关的参数:使用线程池机制管理线程;

在线程池内部,其每一个请求由一个线程来处理; 其worker线程的最大数决定了varnish的并发响应能力;

thread_pools:Number of worker thread pools. 最好小于或等于CPU核心数量;

thread_pool_max:The maximum number of worker threads in each pool. 每线程池的最大线程数;

thread_pool_min:The minimum number of worker threads in each pool. 额外意义为“最大空闲线程数”;

最大并发连接数 = thread_pools  * thread_pool_max

thread_pool_timeout:Thread idle threshold.  Threads in excess of thread_pool_min, which have been idle for at least this long, will be destroyed.

thread_pool_add_delay:Wait at least this long after creating a thread.

thread_pool_destroy_delay:Wait this long after destroying a thread.

Timer相关的参数:

send_timeout:Send timeout for client connections. If the HTTP response hasn't been transmitted in this many seconds the session is closed.

timeout_idle:Idle timeout for client connections.

timeout_req: Max time to receive clients request headers, measured from first non-white-space character to double CRNL.

cli_timeout:Timeout for the childs replies to CLI requests from the mgt_param.

设置方式:

vcl.param

param.set

永久有效的方法:

varnish.params

DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"

varnish日志区域:

shared memory log

计数器

日志信息

1、varnishstat - Varnish Cache statistics

-1

-1 -f FILED_NAME

-l:可用于-f选项指定的字段名称列表;

MAIN.cache_hit

MAIN.cache_miss

# varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss

                    显示指定参数的当前统计数据;

# varnishstat -l -f MAIN -f MEMPOOL

                    列出指定配置段的每个参数的意义;

2、varnishtop - Varnish log entry ranking

-1    Instead of a continously updated display, print the statistics once and exit.

-i taglist,可以同时使用多个-i选项,也可以一个选项跟上多个标签;

-I <[taglist:]regex>:对指定的标签的值基于regex进行过滤;

-x taglist:排除列表

-X  <[taglist:]regex>:对指定的标签的值基于regex进行过滤,符合条件的予以排除;

3、varnishlog - Display Varnish logs

4、 varnishncsa - Display Varnish logs in Apache / NCSA combined log format #以ncsa(类似http协议日志)方式显示-D 以守护进程运行

varnishncsa -D -w /var/log/varnish_access.log #以守护进程方式启动varnish日志

systemctl start varnishncsa #以守护进程启动且剥离终端也不会被停止

内建函数:

hash_data():指明哈希计算的数据;减少差异,以提升命中率;

regsub(str,regex,sub):把str中被regex第一次匹配到字符串替换为sub;主要用于URL Rewrite

regsuball(str,regex,sub):把str中被regex每一次匹配到字符串均替换为sub;

return():

ban(expression)

ban_url(regex):Bans所有的其URL可以被此处的regex匹配到的缓存对象;

synth(status,"STRING"):生成响应报文;

 

 

 

5、LNMP结合varnish实现动静分离

docker pull duckll/lnmp #我这里拿一个做好的镜像提供lnmp架构

docker run -idt --name lnmp -p {port}:80 -v {diretory}:/home/wwwroot/default/{something} duckll/lnmp #启动容器,并指定端口及存储卷

vim /etc/varnish/default.vcl #修改配置文件添加后端主机并指定访问缓存规则

backend web {

        .host = "172.17.0.2";

        .port = "80";

}

backend lnmp {

        .host = "172.17.0.5";

        .port = "80";#

}

sub vcl_recv { #在recv 字段添加规则,将以php结尾请求的报文发送至web服务器,也就是上面我们定义好的后端服务器名称

        if(req.url ~ "(?i)\.php$") {

                set req.backend_hint = web; #设置backend_hint(后端服务器提示符)为backend名称即为web

        else{

                set req.backend_hint = default;

        }

 

6、实现varnish对静态资源的缓存

使用容器模拟动态和静态服务器

静态 nginx 172.17.0.2

动态 php+apache 172.17.0.3

docker pull nginx 

docker run --name web1 -d nginx

docker pull php:7.3-rc-apache

docker run --name web2 -d php:7.3-rc-apache #启动容器

docker exec -it web2 /bin/sh #连接容器

cd /var/www/html #进入目录

echo "<?php phpinfo(); ?>" >index.php

 

vim /etc/varnish/default.vcl #修改配置文件添加后端主机并指定访问缓存规则

backend web {

        .host = "172.17.0.3";

        .port = "80";

}

 

sub vcl_recv { #在recv 字段添加规则,将以php结尾请求的报文发送至web服务器,也就是上面我们定义好的后端服务器名称

        if(req.url ~ "(?i)\.php$") {

                set req.backend_hint = web; #设置backend_hint(后端服务器提示符)为backend名称即为web

        else{

                set req.backend_hint = default;

        }


 

vcl.load test3 default.vcl 在命令行中装载此配置文件命名为test3

vcl.use test3 #切换到test3配置

 


 

 


 

 

posted @ 2019-10-29 12:06  woaiyitiaochai  阅读(150)  评论(0编辑  收藏  举报