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 #也可以使用此命令重新加載配置文件
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配置