緩存
-
緩存之所以能夠生效是程序的運行具有局部性特征:
- 時間局部性:一個數據被訪問過之后,可能很快會被再次訪問到;
- 空間局部性:一個數據被訪問時,其周邊的數據也有可能被訪問到
-
緩存的是熱區數據
-
時效性:
- 緩存空間耗盡:LRU,最近最少使用;
- 過期:緩存清理
-
時效性:
-
緩存命中率:hit/(hit+miss)
- 頁面命中率:基于頁面數量進行衡量
- 字節命中率:基于頁面的體積進行衡量
-
緩存的數據類型
- 私有數據:private,private cache;
- 公共數據:public, public or private cache;
-
Cache-related Headers Fields
The most important caching header fields are: Expires:過期時間; Expires:Thu, 22 Oct 2026 06:34:30 GMT Cache-Control:max-age= Etag If-None-Match Last-Modified If-Modified-Since Vary Age
-
緩存有效性判斷機制:
-
過期時間:Expires
-
HTTP/1.0
Expires:過期時間 -
HTTP/1.1
Cache-Control: maxage= 控制公共和私有緩存
Cache-Control: s-maxage= 控制公共緩存
-
HTTP/1.0
-
條件式請求:
- Last-Modified/If-Modified-Since:基于文件的修改時間戳來判別;
- Etag/If-None-Match:基于文件的校驗碼來判別;
-
示例:
Expires:Thu, 13 Aug 2026 02:05:12 GMT Cache-Control:max-age=315360000 ETag:"1ec5-502264e2ae4c0" Last-Modified:Wed, 03 Sep 2014 10:00:27 GMT
-
-
緩存層級:
- 私有緩存:用戶代理附帶的本地緩存機制;
-
公共緩存:反向代理服務器的緩存功能;
User-Agent <–> private cache <–> public cache <–> public cache 2 <–> Original Server
-
-
請求報文用于通知緩存服務如何使用緩存響應請求:
cache-request-directive = "no-cache", | "no-store" | "max-age" "=" delta-seconds | "max-stale" [ "=" delta-seconds ] | "min-fresh" "=" delta-seconds | "no-transform" | "only-if-cached" | cache-extension
-
響應報文用于通知緩存服務器如何存儲上級服務器響應的內容:
cache-response-directive = "public" | "private" [ "=" <"> 1#field-name <"> ] ,僅私有緩存可以響應 | "no-cache" [ "=" <"> 1#field-name <"> ],可緩存,但響應給客戶端之前需要revalidation,即必須發出條件式請求進行緩存有效性驗正; | "no-store" ,不允許存儲響應內容于緩存中; | "no-transform" | "must-revalidate" | "proxy-revalidate" | "max-age" "=" delta-seconds | "s-maxage" "=" delta-seconds | cache-extension
-
開源解決方案:
-
squid
varnish
-
squid
varnish
-
varnish的配置:
- 定義進程配置
- 緩存系統的配置
-
程序架構:
- Manager進程
- Cacher進程,包含多種類型的線程:accept, worker, expiry, …
-
shared memory log:
- 統計數據:計數器;
-
日志區域:日志記錄;
varnishlog, varnishncsa, varnishstat…
-
配置接口:VCL:Varnish Configuration Language,
vcl complier –> c complier –> shared object
-
varnish的程序環境:
- /etc/varnish/varnish.params: 配置varnish服務進程的工作特性,例如監聽的地址和端口,緩存機制;
- /etc/varnish/default.vcl:配置各Child/Cache線程的緩存策略;
- 主程序:/usr/sbin/varnishd
- CLI interface:/usr/bin/varnishadm
-
Shared Memory Log交互工具:
-
/usr/bin/varnishhist
/usr/bin/varnishlog
/usr/bin/varnishncsa
/usr/bin/varnishstat
/usr/bin/varnishtop
-
/usr/bin/varnishhist
- 測試工具程序:/usr/bin/varnishtest
- VCL配置文件重載程序:/usr/sbin/varnish_reload_vcl
-
Systemd Unit File:
-
varnish服務:
/usr/lib/systemd/system/varnish.service -
日志持久的服務:
/usr/lib/systemd/system/varnishlog.service
/usr/lib/systemd/system/varnishncsa.service
-
varnish服務:
-
varnish的緩存存儲機制( Storage Types):
-s [name=]type[,options]· malloc[,size] 內存存儲,[,size]用于定義空間大?。恢貑⒑笏芯彺骓検?; · file[,path[,size[,granularity]]] 磁盤文件存儲,黑盒;重啟后所有緩存項失效; · persistent,path,size 文件存儲,黑盒;重啟后所有緩存項有效;實驗;
-
varnish程序的選項:
-
程序選項:/etc/varnish/varnish.params文件
-a address[:port][,address[:port][…],默認為6081端口;
-T address[:port],默認為6082端口;
-s [name=]type[,options],定義緩存存儲機制;
-u user
-g group
-f config:VCL配置文件;
-F:運行于前臺;
… -
運行時參數:/etc/varnish/varnish.params文件, DEAMON_OPTS
DAEMON_OPTS=”-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300″-p param=value:設定運行參數及其值; 可重復使用多次;
-r param[,param…]: 設定指定的參數為只讀狀態;
-
程序選項:/etc/varnish/varnish.params文件
-
重載vcl配置文件:
~ ]# varnish_reload_vcl -
varnish的命令行:varnishadm
~]# varnishadm -S /etc/varnish/secret -T [ADDRESS:]PORT help [<command>] ping [<timestamp>] auth <response> quit banner status start stop vcl.load <configname> <filename> vcl.inline <configname> <quoted_VCLstring> vcl.use <configname> vcl.discard <configname> vcl.list 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.list :列出配置文件的版本 vcl.load:裝載,加載并編譯; vcl.use:激活;切換使用配置文件 vcl.discard:刪除; vcl.show [-v] <configname>:查看指定的配置文件的詳細信息;
-
運行時參數:
param.show -l:顯示內部可調的參數所有列表; param.show <PARAM> param.set <PARAM> <VALUE> 設置參數
-
緩存存儲:
storage.list:存儲類型
-
后端服務器:
backend.list :列出后端主機 backend.set_health <backend_expression> <state> #指定后端主機是健康還是不健康的
-
配置文件相關:
-
VCL
-
”域“專有類型的配置語言;
-
state engine:狀態引擎;
-
VCL有多個狀態引擎,狀態之間存在相關性,但狀態引擎彼此間互相隔離;每個狀態引擎可使用return(x)指明關聯至哪個下一級引擎;每個狀態引擎對應于vcl文件中的一個配置段,即為subroutine
-
Client Side
vcl_recv, vcl_pass, vcl_hit, vcl_miss, vcl_pipe, vcl_purge, vcl_synth, vcl_deliver vcl_recv: hash:vcl_hash pass: vcl_pass pipe: vcl_pipe synth: vcl_synth purge: vcl_hash --> vcl_purge vcl_hash: lookup: hit: vcl_hit miss: vcl_miss pass, hit_for_pass: vcl_pass purge: vcl_purge
-
Backend Side:
vcl_backend_fetch, vcl_backend_response, vcl_backend_error
-
兩個特殊的引擎:Housekeeping
vcl_init:在處理任何請求之前要執行的vcl代碼:主要用于初始化VMODs; vcl_fini:所有的請求都已經結束,在vcl配置被丟棄時調用;主要用于清理VMODs;
-
vcl_recv的默認配置:
sub vcl_recv { if (req.method == "PRI") { /* We do not support SPDY or HTTP/2.0 */ return (synth(405)); } if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "DELETE") { /* Non-RFC2616 or CONNECT which is weird. */ return (pipe); } if (req.method != "GET" && req.method != "HEAD") { /* We only deal with GET and HEAD by default */ return (pass); } if (req.http.Authorization || req.http.Cookie) { /* Not cacheable by default */ return (pass); } return (hash); } }
-
-
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 { ...}; (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;
-
The VCL Finite State Machine
(1) Each request is processed separately; (2) Each request is independent from others at any given time; (3) States are related, but isolated; (4) return(action); exits one state and instructs Varnish to proceed to the next state; (5) Built-in VCL code is always present and appended below your own VCL;
-
三類主要語法:
sub subroutine { ... }
if CONDITION { ... } else { ... }
return(), hash_data()
-
VCL Built-in Functions and Keywords
-
內建函數:
- 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”):purge操作;
-
Keywords:
- call subroutine, return(action),new,set,unset
-
操作符:
-
==, !=, ~, >, >=, <, <=
邏輯操作符:&&, ||, !
變量賦值:=
-
==, !=, ~, >, >=, <, <=
-
標志位:
- (?i):模式匹配時不區分字符大小寫
-
舉例:
obj.hits是內建變量,用于保存某緩存項的從緩存中命中的次數;發送響應報文的過程中,在sub vcl_deliver中定義;if (obj.hits>0) { set resp.http.X-Cache = "HIT via " + server.ip; } else { set resp.http.X-Cache = "MISS via " + server.ip; }
-
內建函數:
-
變量類型:
-
內建變量:
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相關; resp.http.* obj.*:存儲在緩存空間中的緩存對象的屬性;只讀;
-
常用變量:
bereq.*, req.*: bereq.http.HEADERS bereq.request:請求方法; bereq.url:請求的url; bereq.proto:請求的協議版本; bereq.backend:指明要調用的后端主機; req.http.Cookie:客戶端的請求報文中Cookie首部的值; req.http.User-Agent ~ "chrome" beresp.*, resp.*: beresp.http.HEADERS beresp.status:響應的狀態碼; reresp.proto:協議版本; beresp.backend.name:BE主機的主機名; beresp.ttl:BE主機響應的內容的余下的可緩存時長; obj.* obj.hits:此對象從緩存中命中的次數; obj.ttl:對象的ttl值 server.* server.ip server.hostname client.* client.ip
-
-
用戶自定義:
-
set
unset
-
set
-
-
示例1:強制對某類資源的請求不檢查緩存:
vcl_recv { if (req.url ~ "(?i)^/(login|admin)") { return(pass); } }
-
示例2:對于特定類型的資源,例如公開的圖片等,取消其私有標識,并強行設定其可以由varnish緩存的時長; 定義在vcl_backend_response中;
if (beresp.http.cache-control !~ "s-maxage") { if (bereq.url ~ "(?i)\.(jpg|jpeg|png|gif|css|js)$") { unset beresp.http.Set-Cookie; set beresp.ttl = 3600s; } }
-
示例3:將客戶端的IP地址傳遞到后端主機,定義在vcl_recv中;
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; } } 當只有一個變量 變量為字符串:非空為真,空則為假; 變量為數值型:非0為真,0則為假
-
緩存對象的修剪:purge, ban
-
purge
-
能執行purge操作
sub vcl_purge { return (synth(200,"Purged")); }
-
何時執行purge操作
sub vcl_recv { if (req.method == "PURGE") { return(purge); } ... }
-
添加此類請求的訪問控制法則:
acl purgers { "127.0.0.0"/8; "192.168.10.0"/24; } sub vcl_recv { if (req.method == "PURGE") { if (!client.ip ~ purgers) { return(synth(405,"Purging not allowed for " + client.ip)); } return(purge); } ... }
-
能執行purge操作
-
Banning:
-
varnishadm:
ban <field> <operator> <arg> 示例: ban req.url ~ ^/javascripts
-
在配置文件中定義,使用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")); }
-
-
-
-
如何設定使用多個后端主機:
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; } ... }
-
Director:
-
varnish module;
使用前需要導入:import directors; -
示例:
import directors; # load the directors backend server1 { .host = .port = } backend server2 { .host = .port = } sub vcl_init { new GROUP_NAME = directors.round_robin(); GROUP_NAME.add_backend(server1); GROUP_NAME.add_backend(server2); } sub vcl_recv { # send all traffic to the bar director: set req.backend_hint = GROUP_NAME.backend(); }
-
示例:
設置使用多個后端主機,采用動靜分離的方式,反代至backend serverbackend 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); }
-
-
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 PB_NAME { }
backend NAME = { .probe = PB_NAME; ... }
-
backend NAME {.probe = {}}
backend NAME { .probe = { ... } }
-
probe PB_NAME { }
-
示例(1):
probe check { .url = "/.healthcheck.html"; .window = 5; .threshold = 4; .interval = 2s; .timeout = 1s; } backend default { .host = "10.1.0.68"; .port = "80"; .probe = check; }
-
示例(2):
backend appsrv { .host = "10.1.0.69"; .port = "80"; .probe check { .url = "/.healthcheck.html"; .window = 5; .threshold = 4; .interval = 2s; .timeout = 1s; } }
-
設置后端的主機屬性:
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
-
vcl.param
-
永久有效的方法:
/etc/varnish/varnish.params DEAMON_OPTS="-p PARAM1=VALUE -p PARAM2=VALUE"
-
線程模型:
-
varnish日志區域:
-
shared memory log
-
計數器
日志信息
-
計數器
-
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
-
-
varnishtop – Varnish log entry ranking
-
-1 Instead of a continously updated display, print the statistics once and exit.
-i taglist,可以同時使用多個-i選項,也可以一個選項跟上多個標簽;
-I <[taglist:]regex>
-x taglist:排除列表
-X <[taglist:]regex>
-
-1 Instead of a continously updated display, print the statistics once and exit.
-
varnishlog – Display Varnish logs
-
varnishncsa – Display Varnish logs in Apache / NCSA combined log format
開啟varnish的日志記錄: systemctl start varnishncsa.service systemctl enable varnishncsa.service tail /var/log/varnish/varnishncsa.log
-
shared memory log
原創文章,作者:s,如若轉載,請注明出處:http://www.www58058.com/79368