第五周負載及緩存

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配置



?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容