Linux运维 第三阶段 (十八) varnish
Linux運(yùn)維 第三階段 (十八) varnish
?
數(shù)據(jù):
結(jié)構(gòu)化數(shù)據(jù),RDBMS;
非結(jié)構(gòu)化數(shù)據(jù),FS,存海量小文件,NAS、SAN、DFS可提供較好的性能;
?
web cache:
程序具有局部性(時間局部性;空間局部性);
key-value,key(url訪問路徑,hash),value(web content);
hotpot熱點數(shù)據(jù);
命中率=hit/(hit+miss),文檔命中率(從文檔個數(shù)進(jìn)行衡量),字節(jié)命中率(從內(nèi)容大小進(jìn)行衡量);
緩存對象,有生命周期,定期清理;
緩存空間耗盡,LRU算法;
可緩存,不可緩存(用戶私有數(shù)據(jù));
cache is king;
?
緩存的處理步驟:
接收請求-->解析請求(提取請求的URL及各種首部)-->查詢緩存-->新鮮度檢測-->創(chuàng)建響應(yīng)報文-->發(fā)送響應(yīng)-->記錄日志;
?
新鮮度檢測機(jī)制:
過期日期:
http/1.0,Expires,時區(qū)不同則有問題;
http/1.1,Cache-Control: max-age=600,該網(wǎng)頁內(nèi)容最多存活時間,比Expires要好;
有效性再驗證,revalidate:
如果原始內(nèi)容未改變,則僅響應(yīng)首部(不附帶body部分),響應(yīng)碼304(Not Modified);
如果原始內(nèi)容發(fā)生改變,則正常響應(yīng),響應(yīng)碼200;
如果原始內(nèi)容消失,則響應(yīng)404,此時緩存中的cache object也應(yīng)被刪除;
?
條件式請求首部:
If-Modified-Since(基于請求內(nèi)容的時間戳作驗證);
If-Unmodified-Since;
If-Match;
If-None-Match(Etag);
?
Cache-Control:cache-directive?? #(更加靈活的緩存控制機(jī)制)
cache-request-directive請求:
no-cache(不要緩存的實體,要求現(xiàn)在從web server上取);
max-age(只接受Age值小于max-age值,并且沒有過期的對象);
max-stale(可以接受過去的對象,但過期時間必須小于max-stale值);
min-fresh(接受其新鮮生命期大于其當(dāng)前Age跟min-fresh值之和的緩存對象);
no-store;
no-transform;
only-if-cached;
cache-extension;
cache-response-directive響應(yīng):
public(可以用cached內(nèi)容回應(yīng)任何用戶);
private(只能用緩存內(nèi)容回應(yīng)先前請求該內(nèi)容的那個用戶);
no-cache(可以緩存,但只有在跟web server驗證其有效后,才能返回給client);
max-age(本響應(yīng)包含的對象的過期時間);
ALL:no-store(不允許緩存);
no-transform;
must-revalidate;
proxy-revalidate;
s-maxage;
cache-extenion;
?
?
HTTP Expiration:
緩存過期,則一定會到原始server上去取,但原始server上的內(nèi)容未必發(fā)生改變;
?
HTTP validation:
Last-Modified/If-Modified-Since;
Etag/If-None-Match;
?
兩者結(jié)合:
you can combie HTTP headers the way you want,Expiration wins over Validation;
?
常見的緩存服務(wù)器開源解決方案:
varnish VS squid(類似nginx VS httpd);
?
CDN(GSLB,緩存路由協(xié)議;大公司,全國各機(jī)房自建CDN;中小公司租用 第三方CDN,帝聯(lián)、藍(lán)訊等);
?
http://www.varnish-cache.org/
?
varnish architecture:
?
DSL,domain specific language;
VCL,varnish configuration language,緩存策略配置接口,基于域的簡單編程語言;
管理進(jìn)程(編譯vcl并應(yīng)用新配置,監(jiān)控varnish,初始化varnish;CLI接口);
child/cache(acceptor(接收新的連接請求);worker threads(處理用戶請求);Expiry(清理緩存中的過期對象));
單進(jìn)程多線程;
日志(shared memory log,默認(rèn)90M,分為兩部分,前一部分是計數(shù)器,后一部分是請求相關(guān)的數(shù)據(jù));
?
內(nèi)存分配和回收:
malloc()、free()?? #(這兩種效率不高);
jemalloc?? #(General-purpose scalable concurrent malloc(3) implementation,更高效)
?
varnish如何存儲緩存對象:
方式一:file(單個文件;不支持持久機(jī)制;適用于大量文件,最好用pci-e disk;與nginx緩存不同,varnish將所有緩存對象存放在單個文件中,varnish自己管理這個文件,varnish在這個文件內(nèi)部組織出專用的FS,varnish自己識別每一個緩存對象從哪開始到哪結(jié)束,名字等元數(shù)據(jù),varnish用于緩存的這一單個文件是獨立自治的王國;varnish服務(wù)在運(yùn)行過程中不能隨便重啟,否則緩存全部失效);
注:
nginx將緩存對象放在disk中,key在內(nèi)存里,nginx緩存在定義時有多級緩存目錄,levels=1:2:2,目錄下放緩存對象,每一個緩存對象用一個文件來存,因此會有很多文件描述符inode;
方式二:malloc(在內(nèi)存中存放緩存對象,時間久了有內(nèi)存碎片);
方式三:persistent(基于文件的持久存儲,實驗階段,有io問題,最好用SSD disk);
?
配置varnish的三種接口:
1、varnishd應(yīng)用程序的命令行參數(shù):
監(jiān)聽的socket,使用的存儲類型等額外的配置參數(shù);
-p param=value
-r param,param,……?? #(設(shè)定只讀參數(shù)列表)
2、-p選項指明的參數(shù),run-time運(yùn)行時參數(shù),可在程序運(yùn)行時,通過其CLI進(jìn)行配置;
3、vcl,配置緩存系統(tǒng)的緩存機(jī)制,通過vcl配置文件進(jìn)行配置,先編譯(依賴c compile,gcc),后應(yīng)用,/etc/varnish/default.vcl;
?
?
?
]#yum -y install varnish?? #(2 version-->3的配置不兼容,3-->4兼容)
Package(s)data still to download: 455 k
(1/3):jemalloc-3.6.0-1.el6.x86_64.rpm??????????????????????????????????????????????????| 100 kB???? 00:00????
(2/3):varnish-2.1.5-6.el6.x86_64.rpm???????????????????????????????????????????????????| 264 kB???? 00:00????
(3/3):varnish-libs-2.1.5-6.el6.x86_64.rpm??????????????????????????????????????????????|? 90 kB???? 00:00???
?
]#varnishd -V
varnishd(varnish-2.1.5 SVN )
Copyright(c) 2006-2009 Linpro AS / Verdens Gang AS
?
]#varnishd -h?? #(默認(rèn)listen 6081/6082,6081服務(wù)端口,6082admin端口,haproxy默認(rèn)5000)
??? -a address:port????????????? # HTTP listen address and port
??? -b address:port????????????? # backend address and port
???????????????????????????????? #??? -b <hostname_or_IP>
???????????????????????????? ????#???-b '<hostname_or_IP>:<port_or_service>'
??? -f file????????????????????? # VCL script
??? -s kind[,storageoptions]???? # Backend storage specification
???????????????????????????????? #?? -s malloc
???????????????????????????????? #?? -s file?[default: use /tmp]
???????????????????????????????? #?? -s file,<dir_or_file>
???????????????????????????????? #?? -s file,<dir_or_file>,<size>
???????????????????????????????? #?? -sfile,<dir_or_file>,<size>,<granularity>
??? -S secret-file?????????????? # Secret file for CLIauthentication
??? -T address:port????????????? # Telnet listen address and port
?
]#rpm -ql varnish??
/etc/rc.d/init.d/varnish
/etc/rc.d/init.d/varnishlog
/etc/rc.d/init.d/varnishncsa
/etc/sysconfig/varnish
/etc/varnish
/etc/varnish/default.vcl
/usr/bin/varnishadm
/usr/bin/varnishhist
/usr/bin/varnishlog
/usr/bin/varnishncsa
/usr/bin/varnishreplay
/usr/bin/varnishsizes
/usr/bin/varnishstat
/usr/bin/varnishtest
/usr/bin/varnishtop
/usr/sbin/varnish_reload_vcl
/usr/sbin/varnishd
/usr/share/doc/varnish-2.1.5
……
?
注:
centos7中:
epel源的varnish是4.0.3;
通過systemctl控制應(yīng)用啟動和關(guān)閉;
/etc/varnish/varnish.params,用于在啟動varnish時傳遞運(yùn)行的參數(shù),不通過此文件則要在命令行中指定;
/usr/lib/systemd/system/varnish.service中定義EnvironmentFile=/etc/varnish/varnish.params,通過定義EnvironmentFile方式加載參數(shù),沒有腳本了;
ExecStart=/usr/sbin/varnishd;
centos6中:
epel源的varnish是2.1.5:
/etc/sysconfig/varnish,大多數(shù)程序是通過腳本傳遞參數(shù);
?
]#yum -y install httpd
]#for i in {1..10} ; do echo "page $i on web" > /var/www/html/test$i.html ; done
]#chkconfig --list httpd?? #(centos7,#systemctl start httpd.service,#systemctl enable httpd.service,#systemctl is-enabled httpd.service)
]#/etc/init.d/httpd start
]#ss -tnl | grep :80
LISTEN???? 0?????511?????????????????????:::80????????????????????? :::*??
?
]#vim /etc/sysconfig/varnish?? #(或/etc/sysconfig/varnish不動,更改/etc/varnish/default.vcl中的backend_default {
backenddefault {
? .host = "127.0.0.1";
? .port = "80";
}
);
VARNISH_TTL=120?? #(varnish連接backend server的timeout)
DAEMON_OPTS="-a:6081 \
???????????? -T localhost:6082 \
????? ???????-b localhost:80 \
???????????? -u varnish -g varnish \
???????????? -sfile,/var/lib/varnish/varnish_storage.bin,1G"
#DAEMON_OPTS="-a${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
#???????????? -f ${VARNISH_VCL_CONF} \
#???????????? -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT}\
#???????????? -t ${VARNISH_TTL} \
#???????????? -w${VARNISH_MIN_THREADS},${VARNISH_MAX_THREADS},${VARNISH_THREAD_TIMEOUT} \
#???????????? -u varnish -g varnish \
#???????????? -S ${VARNISH_SECRET_FILE} \
#???????????? -s ${VARNISH_STORAGE}"
?
]#/etc/init.d/varnish restart
Stoppingvarnish HTTP accelerator:???????????????????????? [? OK? ]
Startingvarnish HTTP accelerator:???????????????????????? [? OK? ]
]#ss -tnl | egrep "6081|6082"
LISTEN???? 0?????1024???????????????????? :::6081??????????????????? :::*????
LISTEN???? 0?????1024?????????????????????*:6081???????????????????? *:*????
LISTEN???? 0?????10???????????????127.0.0.1:6082????????????????????*:*????
LISTEN???? 0?????10??????????? ??????????::1:6082??????????????????? :::*??
?
?
]#varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082?? #(管理接口)
help
200377????
help[command]
ping[timestamp]?? #(查看主機(jī)狀態(tài))
authresponse
quit
banner
status?? #(查看child進(jìn)程狀態(tài))
start?? #(start,stop用于啟停child進(jìn)程)
stop
stats
vcl.load <configname> <filename>?? #(裝載vcl文件并編譯,configname是自定義的)
vcl.inline <configname> <quoted_VCLstring>
vcl.use <configname>
vcl.discard <configname>
vcl.list
vcl.show <configname>
param.show [-l] [<param>]
param.set <param> <value>
purge.url <regexp>
purge<field> <operator> <arg> [&& <field><oper> <arg>]...
purge.list
?
ping
20019?????
PONG1497921153 1.0
?
status
20022?????
Childin state running
?
vcl.list?? #(active為當(dāng)前在用)
20023?????
active????????? 2 boot
?
vcl.load test /etc/varnish/default.vcl
20013?????
VCLcompiled.
?
vcl.use test
2000??????
?
vcl.list
20046?????
available?????? 1 boot
active????????? 1 test
?
vcl.useboot
2000??????
?
vcl.list
20046?????
active????????? 2 boot
available?????? 0 test
?
vcl.discard test
2000??????
?
vcl.list
20023?????
active????????? 2 boot
?
param.show?? #(顯示運(yùn)行時參數(shù),常用的有:thread_pool_min,thread_pool_max,thread_pools,該server的并發(fā)連接數(shù)為thread_pools*thread_pool_max;若不想讓這些運(yùn)行時參數(shù)被更改,可在啟動時用-r指明是只讀,
2002413???
acceptor_sleep_decay?????? 0.900000 []
acceptor_sleep_incr??????? 0.001000 [s]
acceptor_sleep_max???????? 0.050000 [s]
auto_restart?????????????? on [bool]
ban_lurker_sleep?????????? 0.000000 [s]
between_bytes_timeout????? 60.000000 [s]
cache_vbe_conns??????????? off [bool]
cc_command???????????????? "exec cc -fpic -shared-Wl,-x -o %o %s"
cli_buffer?????????????? ??8192 [bytes]
cli_timeout??????????????? 10 [seconds]
clock_skew???????????????? 10 [s]
connect_timeout??????????? 0.400000 [s]
critbit_cooloff??????????? 180.000000 [s]
default_grace????????????? 10 [seconds]
default_ttl??????????????? 120 [seconds]
diag_bitmap??????????????? 0x0 [bitmap]
err_ttl??????????????????? 0 [seconds]
esi_syntax???????????????? 0 [bitmap]
expiry_sleep?????????????? 1.000000 [seconds]
fetch_chunksize??????????? 128 [kilobytes]
first_byte_timeout???????? 60.000000 [s]
group??????? ??????????????varnish (498)
http_headers?????????????? 64 [header lines]
http_range_support???????? off [bool]
listen_address???????????? :6081
listen_depth?????????????? 1024 [connections]
log_hashstring???????????? off [bool]
log_local_address????????? off [bool]
lru_interval?????????????? 2 [seconds]
max_esi_includes?????????? 5 [includes]
max_restarts?????????????? 4 [restarts]
overflow_max?????????????? 100 [%]
ping_interval????????????? 3 [seconds]
pipe_timeout?????????????? 60 [seconds]
prefer_ipv6? ??????????????off [bool]
purge_dups???????????????? on [bool]
rush_exponent????????????? 3 [requests per request]
saintmode_threshold??????? 10 [objects]
send_timeout?????????????? 600 [seconds]
sess_timeout?????????????? 5 [seconds]
sess_workspace??????? ?????65536 [bytes]
session_linger???????????? 50 [ms]
session_max??????????????? 100000 [sessions]
shm_reclen???????????????? 255 [bytes]
shm_workspace????????????? 8192 [bytes]
syslog_cli_traffic???????? on [bool]
thread_pool_add_delay????? 20 [milliseconds]
thread_pool_add_threshold? 2 [requests]
thread_pool_fail_delay???? 200 [milliseconds]
thread_pool_max??????????? 1000 [threads]
thread_pool_min??????????? 1 [threads]
thread_pool_purge_delay??? 1000 [milliseconds]
thread_pool_stack????????? unlimited [bytes]
thread_pool_timeout??????? 120 [seconds]
thread_pools?????????????? 2 [pools]
thread_stats_rate????????? 10 [requests]
user?????????????????????? varnish (498)
vcl_trace????????????????? off [bool]
waiter???????????????????? default (epoll, poll)
?
param.show -l?? #(顯示更詳細(xì)的信息)
……
?
param.show thread_pools
2001111???
thread_pools?????????????? 2 [pools]
?????????????????????????? Default is 2
?????????????????????????? Number of workerthread pools.
??????????????????????????
?????????????????????????? Increasing number ofworker pools decreases lock
?????????????????????????? contention.
??????????????????????????
?????????????????????????? Too many pools wasteCPU and RAM resources, and
?????????????????????????? more than one poolfor each CPU is probably
??? ???????????????????????detrimal to performance.
??????????????????????????
?????????????????????????? Can be increased onthe fly, but decreases require
?????????????????????????? a restart to takeeffect.
??????????????????????????
???????????????????? ??????NB: This parameter may take quite sometime to
?????????????????????????? take (full) effect.
??????????????????????????
?????????????????????????? NB: We do not knowyet if it is a good idea to
?????????????????????????? change thisparameter, or if the default value is
?????????????????????????? even sensible.? Caution is advised, and feedback
?????????????????????????? is most welcome.
?
vcl.show boot?? #(顯示vcl文件編譯前的內(nèi)容)
?
注:
4版本的管理命令行下還有:
panic.show;
storage.list;
backend.list;
backend.set_health(backend server從離線-->上線);
ban.list(清理緩存中的緩存對象,根據(jù)表達(dá)式清理某一類緩存對象,默認(rèn)緩存對象過期則會清理);
?
?
]#varnishlog?? #(log有關(guān),在宿主機(jī)上訪問http://10.230.32.208:6081/test6.html,[-i tag] [-I regexp] (include regular express); [-X regexp](exclude regular express) [-x tag])
?? 13 SessionOpen? c 192.168.2.14 2665 :6081
?? 13 ReqStart???? c 192.168.2.14 2665 1994176375
?? 13 RxRequest??? c GET
?? 13 RxURL??????? c /test6.html
?? 13 RxProtocol?? c HTTP/1.1
?? 13 RxHeader???? c Host: 10.230.32.208:6081
?? 13 RxHeader???? c Connection: keep-alive
?? 13 RxHeader???? c Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
?? 13 RxHeader???? c User-Agent: Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
?? 13 RxHeader???? c Accept-Encoding: gzip,deflate,sdch
?? 13 RxHeader???? c Accept-Language: zh-CN,zh;q=0.8
?? 13 VCL_call???? c recv
?? 13 VCL_return?? c lookup
?? 13 VCL_call???? c hash
?? 13 VCL_return?? c hash
?? 13 VCL_call???? c miss
?? 13 VCL_return?? c fetch
?? 14 BackendOpen? b default 127.0.0.1 45242 127.0.0.1 80
?? 13 Backend????? c 14 default default
?? 14 TxRequest??? b GET
?? 14 TxURL??????? b /test6.html
?? 14 TxProtocol?? b HTTP/1.1
?? 14 TxHeader???? b Host: 10.230.32.208:6081
?? 14 TxHeader???? b Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
?? 14 TxHeader???? b User-Agent: Mozilla/5.0 (Windows NT 6.1;WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36
……
?
]#varnishncsa?? #(log有關(guān),與combined接近,訪問http://10.230.32.208:6081/test8.html)
192.168.2.14- - [07/Jul/2017:10:01:19 +0800] "GEThttp://10.230.32.208:6081/favicon.ico HTTP/1.1" 404 290 "-""Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/28.0.1500.72 Safari/537.36"
192.168.2.14- - [07/Jul/2017:10:01:19 +0800] "GEThttp://10.230.32.208:6081/favicon.ico HTTP/1.1" 404 290 "-""Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/28.0.1500.72 Safari/537.36"
?
]#varnishtop?? #(top)
?
]#varnishstat?? #(statistics,)
]#varnishstat -l?? #(-l ?# Lists the available fields to use with the-f option)
Varnishstat-f option fields:
Fieldname?????????? Description
----------?????????? -----------
client_conn????????? Client connections accepted
client_drop????????? Connection dropped, no sess/wrk
client_req?????????? Client requests received
cache_hit??????????? Cachehits
cache_hitpass??????? Cache hits for pass
cache_miss?????????? Cache misses
backend_conn???????? Backend conn. success
backend_unhealthy??? Backend conn. not attempted
backend_busy???????? Backend conn. too many
backend_fail???????? Backend conn. failures
backend_reuse??????? Backend conn. reuses
backend_toolate????? Backend conn. was closed
backend_recycle????? Backend conn. recycles
backend_unused??????Backend conn. unused
fetch_head?????????? Fetch head
fetch_length???????? Fetch with Length
fetch_chunked??????? Fetch chunked
fetch_eof??????????? Fetch EOF
fetch_bad??????????? Fetch had bad headers
fetch_close????????? Fetch wanted close
fetch_oldhttp??????? Fetch pre HTTP/1.1 closed
fetch_zero?????????? Fetch zero len
fetch_failed???????? Fetch failed
n_sess_mem?????????? N struct sess_mem
n_sess?????????????? N struct sess
n_object???????????? N struct object
n_vampireobject????? N unresurrected objects
n_objectcore???????? N struct objectcore
n_objecthead???????? N struct objecthead
n_smf??????????????? N struct smf
n_smf_frag?????????? N small free smf
n_smf_large????????? N large free smf
n_vbe_conn?????????? N struct vbe_conn
n_wrk?? ?????????????N worker threads
n_wrk_create???????? N worker threads created
n_wrk_failed???????? N worker threads not created
n_wrk_max??????????? N worker threads limited
n_wrk_queue????????? N queued work requests
n_wrk_overflow?????? N overflowed work requests
n_wrk_drop?????????? N dropped work requests
n_backend??????????? N backends
n_expired??????????? N expired objects
n_lru_nuked????????? N LRU nuked objects
n_lru_saved????????? N LRU saved objects
n_lru_moved????????? N LRU moved objects
n_deathrow?????????? N objects on deathrow
losthdr????????????? HTTP header overflows
n_objsendfile??????? Objects sent with sendfile
n_objwrite?????????? Objects sent with write
n_objoverflow??????? Objects overflowing workspace
s_sess?????????????? Total Sessions
s_req??????????????? Total Requests
s_pipe?????????????? Total pipe
s_pass?????????????? Total pass
s_fetch????????????? Total fetch
s_hdrbytes?????????? Total header bytes
s_bodybytes????????? Total body bytes
sess_closed????????? Session Closed
sess_pipeline??????? Session Pipeline
sess_readahead?????? Session Read Ahead
sess_linger????????? Session Linger
sess_herd??????????? Session herd
shm_records????????? SHM records
shm_writes?????????? SHM writes
shm_flushes???? ?????SHM flushes due to overflow
shm_cont???????????? SHM MTX contention
shm_cycles?????????? SHM cycles through buffer
sm_nreq????????????? allocator requests
sm_nobj????????????? outstanding allocations
sm_balloc??????????? bytes allocated
sm_bfree????? ???????bytes free
sma_nreq???????????? SMA allocator requests
sma_nobj???????????? SMA outstanding allocations
sma_nbytes?????????? SMA outstanding bytes
sma_balloc?????????? SMA bytes allocated
sma_bfree??????????? SMA bytes free
sms_nreq???????????? SMS allocator requests
sms_nobj???????????? SMS outstanding allocations
sms_nbytes?????????? SMS outstanding bytes
sms_balloc?????????? SMS bytes allocated
sms_bfree??????????? SMS bytes freed
backend_req????????? Backend requests made
n_vcl??????????????? N vcl total
n_vcl_avail????????? N vcl available
n_vcl_discard??????? N vcl discarded
n_purge????????????? N total active purges
n_purge_add????????? N new purges added
n_purge_retire?????? N old purges deleted
n_purge_obj_test???? N objects tested
n_purge_re_test????? N regexps tested against
n_purge_dups???????? N duplicate purges removed
hcb_nolock?????????? HCB Lookups without lock
hcb_lock???????????? HCB Lookups with lock
hcb_insert?????????? HCB Inserts
esi_parse??????????? Objects ESI parsed (unlock)
esi_errors?????????? ESI parse errors (unlock)
accept_fail????????? Accept failures
client_drop_late???? Connection dropped late
uptime?????????????? Client uptime
backend_retry??????? Backend conn. retry
dir_dns_lookups????? DNS director lookups
dir_dns_failed?????? DNS director failed lookups
dir_dns_hit????????? DNS director cached lookups hit
dir_dns_cache_full?? DNS director full dnscache
fetch_1xx??????????? Fetch no body (1xx)
fetch_204??????????? Fetch no body (204)
fetch_304??????????? Fetch no body (304)
]#varnishstat -f cache_hit?? #(-f field_list # Comma separatedlist of fields to display.)
?
?
vcl state engine:
?
vcl_recv;
vcl_hash;
vcl_hit,vcl_miss;
vcl_fetch;
vcl_deliver;
vcl_pipe?? #當(dāng)檢測到client請求不是get、head時,也不是正常http的方法,用vcl_pipe直接扔給backend server,一手托兩家;
vcl_pass;
vcl_error?? # varnish在前端生成錯誤頁面信息,用于refuse request或其它異常狀態(tài)由varnish合成錯誤頁面);
另Verion4還有:
vcl_purge;
vcl_backend_fetch;
vcl_backend_response;
vcl_synth;
vcl_backend_error;
?
注:
iptables:
prerouting-->input-->forwar-->postrouting;
output-->postrouting;
?
各引擎間有一定程度的相關(guān)性,前一個engine若有多個下游engine,則上游engine需用return指明要轉(zhuǎn)移的下游engine;
?
the vcl finite state machine:
1、comment,//,#,/*……*/,這些注釋信息可被編譯器忽略;
2、sub $NAME { },用于定義子例程;
3、不支持循環(huán);
4、有眾多內(nèi)置的變量,變量的可調(diào)用位置與state engine有密切相關(guān)性;
5、支持終止語句,return (action),沒有返回值;
6、“域”專用;
7、操作符,=,==,~,!,&&,||;
?
條件判斷語句:
if (CONDITION) {
} else {
}
?
變量賦值:
set name=value
unset name=value
?
?
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;
???????? }
}
if (req.request != "GET" && req.request != "HEAD" && req.request != "PUT" && req.request != "POST" && req.request != "TRACE" && req.request != "OPTIONS" && req.request != "DELETE") {
???????? return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") {
???????? return (pass);
}
if (req.http.Authorization || req.http.Cookie) {
???????? return (pass);
}
return (lookup);
?
hash_data (req.url);
if (req.http.host) {
???????? hash_data(req.http.host);
} else {
???????? hash_data(server.ip);
}
return (hash);
?
return (deliver);
?
return (fetch);
?
if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
???????? set beresp.ttl = 120 s;
???????? return (hit_for_pass);
}
return (deliver);
?
state engine workflow(V3):
workflow1:
vcl_recv-->vcl_hash-->vcl_hit->vcl_deliver
?
workflow2:
vcl_recv-->vcl_hash-->vcl_miss-->vcl_fetch-->vcl_deliver
?
workflow3:
vcl_recv-->vcl_pass-->vcl_fetch-->vcl_deliver
?
workflow4:
vcl_recv-->vcl_pipe
?
variable availability in VCL:
varnish中的內(nèi)置變量:
req?? #req.http.HEADER;req.method;req.proto;req.url;req.ttl;
resp?? #resp.http.HEADER;resp.proto;resp.reason;resp.status;
bereq?? #backend;bereq.http.HEADERS由varnish發(fā)往backend server請求報文的指定首部;bereq.request請求方法;bereq.url;bereq.proto;bereq.backend指明要調(diào)用的后端主機(jī);
beresp?? #beresp.prot,backendserver響應(yīng)時的協(xié)議版本;beresp.status響應(yīng)狀態(tài)碼;beresp.reason原因短語;beresp.backend.ip;beresp.backend.name;beresp.http.HEADER從backend server響應(yīng)的報文首部;beresp.ttl,backend server響應(yīng)的內(nèi)容余下的生存時長;
client
now
obj?? #obj.ttl,對象的ttl值;obj.hits,此對象從緩存中命中的次數(shù);
server?? #server.hostname;server.ip;
storage?? #storage.<name>.free_space;storage.<name>.used_space;storage.<name>.happy(health status);
functions
?
?
default.vcl中backend server定義:
backend NAME {
???????? .ATTRIBUTE = "VALUE";
???????? .host = "IP_ADDRESS";
???????? .port = "PORT";
???????? .probe = {
?????????????????? .url ="/test1.html";
???????? }
}
?
注:
.probe對be作健康狀態(tài)檢測:
probe NAME {
???????? .ATTRIBUTE = "VALUE";
???????? .url = "/test.html";
???????? .expected_response = 200;?? #期望的響應(yīng)狀態(tài)碼,默認(rèn)200
}
舉例:
backend websrv1 {
???????? .host = "192.168.239.20";
???????? .port = "80";
???????? .probe = {
?????????????????? .url = "/test.html";
???????? }
}
backend websrv2 {
???????? .host = "192.168.239.21";
???????? .port = "80";
???????? .probe = {
?????????????????? .url = "/test.html";
???????? }
}
sub vcl_recv{
???????? if (req.url ~ "(?i)\.(jpg|png|gif)$") {
?????????????????? set req.backend_hint = websrv1;
???????? } else {
?????????????????? set req.backend_hint = websrv2;
???????? }
}
?
LB算法:
fallback;
random;
round_robin?? #是對整個資源輪循,如依次請求/test1.html,/test2.html,/test3.html,若始終訪問/test1.html,則始終從一個backend server返回;
hash;
舉例:
backend websrv1 {
……
}
backend websrv2 {
……
}
import directors;
sub vcl_init {
???????? new mycluster = directors.round_robin();
???????? mycluster.add_backend(websrv1);
???????? mycluster.add_backend(websrv2);
}
subvcl_recv {
???????? set req.backend_hint = mycluster.backend();
}
?
注:
#man vmod_directors
#curl http://VARNISH_SERVER:6082/test{1,2,3}.html
?
?
?
例:
給響應(yīng)給client的報文添加自定義首部X-Cache,在vcl_deliver中定義:
subvcl_deliver {
??????? if (obj.hits > 0) {
??????????????? set resp.http.X-Cache = "HIT from + server.ip";
??????? } else {
??????????????? set resp.http.X-Cache = "MISS";
??????? }
}
?
vcl.list
20023?????
active????????? 1 boot
?
vcl.load test /etc/varnish/test.vcl
20013?????
VCLcompiled.
vcl.usetest
2000??????
?
?
例:
讓varnish支持后端多個虛擬主機(jī):
sub vcl_recv {
???????? if (req.http.host ~ "www.magedu.com" {
???????? }
}
?
例:
強(qiáng)制對某資源(或后臺登錄)的請求,不檢查緩存,直接找backend server:
sub vcl_recv {
???????? if (req.url ~ "^/test2.html$"{
?????????????????? return (pass);
???????? if (req.url ~ "(?i)^/login" || req.url ~ "(?i)^/admin") {
?????????????????? return (pass);
}
?
例:
對特定類型的資源取消其私有的cookie標(biāo)識,并強(qiáng)行設(shè)定其可以varnish緩存時長:
sub vcl_babckend_response {
???????? if (beresp.http.cache-control !~ "s-maxage") {
?????????????????? if (bereq.url ~ "(?i)\.jpg$") {
??????????????????????????? set beresp.ttl = 3600s;
???????? ?????????????????? unset beresp.http.Set-Cookie;
?????????????????? }
???????? if (bereq.url ~ "(?i)\.css$"){
?????????????????? set beresp.ttl = 600s;
?????????????????? unset beresp.http.Set-Cookie;
???????? }
}
?
?
?
?
一、相關(guān)概念:
http/1.0-->http/1.1(重大改進(jìn):對緩存功能實現(xiàn)了更精細(xì)化的設(shè)計)
RFC(request file comment,每一種協(xié)議都有請求注解文檔,講協(xié)議規(guī)范)
http頁面由眾多的web object組成,有些是靜態(tài),有些是通過程序執(zhí)行后生成的;為加速web的訪問,browser中引入了緩存機(jī)制,能將訪問的靜態(tài)內(nèi)容或可緩存的動態(tài)內(nèi)容緩存到本地,而后client再次到原始server上請求之前相同的內(nèi)容時,如果原始server上的內(nèi)容沒發(fā)生改變,就直接使用本地已緩存的數(shù)據(jù),而非從原始server上再次下載,這整個過程是如何完成的,http是如何支持緩存機(jī)制的(server上的緩存,并非所有內(nèi)容都能緩存,如登錄時的賬號密碼、向用戶返回的cookie,緩存有失效時間)
?
緩存的類型:
public cache(如nginx,varnish)
private cache(用戶browser的本地緩存,一般用戶本地的緩存是安全的,但若這個電腦是公共部門的,很多人使用,相對來說也不安全)
?
一般能緩存的前提是原始server上的內(nèi)容沒發(fā)生改變的,client怎么知道他請求的內(nèi)容在自己本地緩存中有沒失效,從而不用去原始server上獲取數(shù)據(jù),解決方案:
(1)服務(wù)器在第一次響應(yīng)用戶的請求時,在http首部中明確告訴client此資源可以緩存的有效時長為10min,使用expires指明過期時間,如Expires: Fri , 12 May 2006 18:53:33 GMT;
(2)server將數(shù)據(jù)響應(yīng)給client時沒設(shè)置緩存期限,但client覺得這是個靜態(tài)內(nèi)容可以緩存(client自己設(shè)置了一些緩存策略,如只要是靜態(tài)內(nèi)容我就緩存),緩存下來之后并不知道遠(yuǎn)程server中是否改變,當(dāng)再次請求之前請求的內(nèi)容時,告訴server我這存的有一份它的上一次修改時間是什么時候,server一對比發(fā)現(xiàn)同一對象的修改時間一致,由此可知server上的內(nèi)容沒改變,于是server給client響應(yīng)碼304(Not Modified),告訴client此前內(nèi)容沒改變你可以繼續(xù)使用,于是client的browser直接整合本地緩存的資源得以顯示
?
以上是基于時間來實現(xiàn)緩存機(jī)制控制的(http/1.0的緩存機(jī)制是靠prog來標(biāo)記能否緩存,并使用Expires定義某資源到什么時候過期);http/1.1?對緩存機(jī)制引入了很多首部,有些首部專用于client,有些首部專用于server,讓雙方基于某種功能進(jìn)行協(xié)商,判定緩存對象是否能進(jìn)一步使用的機(jī)制)
?
緩存相關(guān)的http首部:
(1)Expires(絕對時間計時法,絕對日期時間,GMT格式,如Expires: Fri , 12 May 2006 18:53:33 GMT,它返回給client的時間是明確的時間,client的browser緩存了這個資源后,若再次發(fā)起請求同樣內(nèi)容時,只要在這個時間內(nèi)就不去server請求了直接從本地取,Expires的缺陷(若client和server上的時間不一致就無法比較了),這種機(jī)制在http/1.0上常用,而在http/1.1上使用時長來定義max-age)
(2)cache-control中的max-age(max-age在http/1.1中使用,用于定義時長,明確告訴client某個資源可緩存多長時間,從server發(fā)送這個資源開始倒計時,只要倒計時結(jié)束,緩存資源立即失效,如Cache-Control:max-age=600)
注:如果既指定Expires又在cache-control中指定max-age,那Expires的設(shè)定將被忽略
注:cache-control是http中重要的首部,用于定義所有的緩存機(jī)制都必須遵循緩存指示,無論時間有無過期或有沒有給最長緩存時間都要接受cache-control的控制,就算某個資源定義可緩存兩天,但同時又使用了cache-control指令告訴你不能進(jìn)行緩存,那結(jié)果就是不能緩存,指令包括有:public、private、no-cache、no-store、max-age、s-maxage、must-reval-idate
public(放在public cache上,所有人都能獲取,不涉及隱私泄露)
private(只能緩存在用戶的私有緩存區(qū)域,像nginx、varnish這樣的public cache server是不能緩存的)
no-cache(表示可以緩存,但每次都要向server發(fā)起原始資源驗證,沒有標(biāo)記no-cache時只要在過期時間內(nèi),直接從本地獲取不用向server驗證這個資源能否用,而標(biāo)記了no-cache不論在不在過期時間內(nèi)都要向server驗證)
s-maxage(主要控制私有緩存的過期期限)
(3)Etag(響應(yīng)首部,某些站點,數(shù)據(jù)變化頻率很高,如client在1s里發(fā)起好幾次請求index.html這個資源(Expires: Fri , 12 May2006 18:53:33 GMT),但在server上1s內(nèi)更新了好幾次頁面(主頁動態(tài)生成),對于這個對象client和server時間的比較結(jié)果還是之前的時間,但實際server上的資源已經(jīng)改變了,所以時間戳這種方法過于粗糙,這種按秒計時不足以描述頁面文件的變化頻率,有可能讓已失效的緩存繼續(xù)使用,因此引入Etag,extended tag擴(kuò)展標(biāo)記,給頁面定義版本號(版本號是隨機(jī)生成的,每次生成一個頁面都會自動加版本號),Etag是個響應(yīng)首部,用于在響應(yīng)報文中為某web資源定義版本標(biāo)識符,這樣client過來驗證不是基于時間戳而是對比Etag,就算更新頻率在秒級以下也能驗證資源是否發(fā)生改變)
注:(1)(2)都是絕對判定法,http/1.1引入條件判斷,每次驗證資源時是向server發(fā)起詢問條件,如Last-Modified、If-Modified-Since
(4)Last-Modified(響應(yīng)首部,某資源在server上最后修改的時間,當(dāng)client第一次請求某資源時,server返回狀態(tài)200,內(nèi)容是client請求的內(nèi)容,同時有Last-Modified屬性標(biāo)記此文件在server上最后被修改的時間,如Last-Modified : Fri , 12 May 2006 18:53:33 GMT)
(5)If-Modified-Since(條件式請求首部,當(dāng)client第二次請求相同的內(nèi)容時詢問server此對象Last-Modified是否發(fā)生了改變,若沒改變server響應(yīng)給client304(Not Modified),若改變了則響應(yīng)改變的內(nèi)容與第一次請求類似,從而保證不向client重復(fù)發(fā)出資源,也保證當(dāng)server有變化時client能得到最新的資源)
(6)If-None-Match(條件式請求首部,這是個否定請求,clinet第二次請求相同內(nèi)容時會詢問server之前發(fā)的某個資源的Etag是否不匹配,server若回答是則不匹配,響應(yīng)新資源,若server回答否則client使用之前的緩存)
注:If-Modified-Since與Last-Modified有關(guān),If-None-Match與Etag有關(guān),這整個過程:
client請求一個頁面A;
server返回頁面A,并給A加上Last-Modified、Etag;
client展示頁面A,并將頁面和Last-Modified、Etag一同緩存;
client再次請求頁面A,將Last-Modified、Etag一同傳給server(在首部使用If-Modified-Since、If-None-Match分別詢問Last-Modified、Etag是否修改);
server檢查Last-Modified、Etag判斷出是否修改,若未修改則響應(yīng)304和一個空的響應(yīng)體
(7)Vary(響應(yīng)首部,原始server根據(jù)請求來源的不同響應(yīng)不同的首部,Vary通知緩存機(jī)制client獲取頁面是如何得到頁面的,常用的有:Vary:Accept-Encoding,client若支持壓縮功能在請求時將請求報文壓縮,那server在響應(yīng)時也使用壓縮返回,Vary根據(jù)client的編碼機(jī)制(文本或gzip壓縮或deflate壓縮)server采用相應(yīng)的機(jī)制返回)
(8)Age(緩存server可發(fā)送一個額外的響應(yīng)首部,用于指定響應(yīng)的有效期限,browser通常根據(jù)此首部決定內(nèi)容的緩存時長,如果響應(yīng)報文首部還使用了max-age指令,那緩存的有效時長為max-age減去Age的結(jié)果)
?
假設(shè)我們的reverse proxy上提供緩存,后端是RS(原始server),client向reverse proxy請求某頁面,reverse proxy中有該頁面的緩存則直接響應(yīng)給client(client于是在本地緩存),若reverse proxy中沒該頁面的緩存,則reverse proxy向原始server發(fā)起請求,原始server響應(yīng)資源給reverse proxy,同時一并給一個首部,如Cache-Control:max-age=600,reverse proxy將資源緩存下來在600s內(nèi)都有效,reverse proxy于是重新構(gòu)建首部并響應(yīng)給client(reverse proxy構(gòu)建首部時可以自定義告訴client什么時候過期,如告訴client可以緩存1年,也可告訴client緩存1min),假設(shè)reverse proxy給client的過期時長是1min,當(dāng)同一client再次請求同樣內(nèi)容時(若在緩存過期時間內(nèi)(1min內(nèi))則從本地緩存中直接取;若過了過期時間(1min)client不會立即清除緩存,而是使用條件式請求首部請求,reverse proxy比較兩次時間,若時間一樣則向client返回304,reverse proxy于是再給client一個緩存過期時間(1min),所以就算過了過期時間也不一定從reverse proxy上重復(fù)獲取數(shù)據(jù);若是強(qiáng)制刷新ctrl+F5則仍會到reverse proxy上請求)
若client在第11min時向reverse proxy請求同一頁面,reverse proxy發(fā)現(xiàn)本地緩存已失效(reverse proxy不會使用已失效內(nèi)容響應(yīng)的),它向原始server發(fā)起條件式請求(If-Modified-Since、If-None-Match),若原始server發(fā)現(xiàn)沒修改則返回304(Not Modified),這樣reverse proxy的本地緩存時間就更新了,于是使用本地緩存響應(yīng)給client
?
舉例:
第一次請求時:
再次刷新后:
?
?
cache server并不是緩存任意數(shù)據(jù)(不允許緩存某些數(shù)據(jù)),如不能緩存用戶的cookie信息,如果用戶請求的內(nèi)容中有變化的cookie信息的話,緩存是命中不了的,緩存中是key:value,若key中包含經(jīng)常變化的內(nèi)容,命中率是很低的,很多時候緩存時都把cookie信息去掉,以提高命中率;不能緩存某些動態(tài)生成的資源,如表單中填入的賬號密碼;若請求方法是PUT或POST寫操作,也不能緩存,一般緩存的都是GET操作的數(shù)據(jù)(就算是GET操作若包含用戶的認(rèn)證授權(quán)類信息也不能緩存)
?
可在cache server上自定義緩存策略(把某些資源根據(jù)我們自己的理解從原始server上剝離出來自己定義這些資源的緩存時間),如cache server到原始server上請求數(shù)據(jù),若請求的是站點的LOGO圖片,雖原始server告訴cache server可緩存10min,但cache server(管理者)覺得該內(nèi)容是靜態(tài)的而且很長時間都不會變,于是cache server響應(yīng)時告訴client可緩存半年,client在自己本地私有緩存中保存的內(nèi)容越多,那向server發(fā)起請求的或獲取的數(shù)據(jù)就越少,資源發(fā)送少了,帶寬占用率就小了,client從本地緩存直接拿數(shù)據(jù)會很快,這樣用戶體驗度就好
?
?cache server放到離client越近越好(最好放在家門口),盡量將資源丟到用戶的緩存中,我們電腦上或手機(jī)上使用時間長了會緩存一些數(shù)據(jù),這樣使得上網(wǎng)速度更快并節(jié)省流量,某些軟件會提示清理垃圾,若清理了下次請求將占用帶寬重新獲取
?
緩存擴(kuò)展結(jié)構(gòu):CDN(cache delivery network,內(nèi)容分發(fā)網(wǎng)絡(luò)),如圖:
client到server這之間可定義N層緩存(n個cache server,cache server之間是分層次的),client請求到cache server1,1號發(fā)現(xiàn)自己沒有要響應(yīng)的內(nèi)容時它不會去找原始server,它會先找它的兄弟服務(wù)器(cache server2)2若沒有再去找它的父cache server3,3沒有找它的父cache server4,父cache server中沒有,由父緩存找原始server(1和2是兄弟服務(wù)器(sibling),3是1的父(parent),4是3的父),這些cache server之間通過內(nèi)容緩存協(xié)議且能共享緩存對象共同組成的網(wǎng)絡(luò)叫CDN,由此client請求時在中間這個網(wǎng)絡(luò)上就可取得所有內(nèi)容,同時這些cache server可定義一些策略,如定期到原始server上獲取數(shù)據(jù)無論client有無請求
為使用戶體驗好同時又減輕server壓力使用CDN,如下圖四個區(qū)域組成的CDN
未用CDN前,DNS解析:www.magedu.com? in?A? 1.1.1.1
使用CDN,DNS要解析成別名,指向cache server上的某一個,如指向杭州CDN節(jié)點(www.magedu.com? in?CNAME? hz.cdn.com),這樣杭州用戶訪問會很快,其它區(qū)域的用戶訪問還是很慢,用智能DNS解決(根據(jù)client來源判定它屬于哪個區(qū)域網(wǎng)絡(luò),于是DNS解析時不是四個都返回,而是僅返回離它最近最快的那個cache server的域名)
智能DNS+CDN這才是真正意義的CDN,當(dāng)client請求時由該區(qū)域的CDN節(jié)點響應(yīng)內(nèi)容,若該節(jié)點沒相應(yīng)內(nèi)容,它不去找源站而是找離它近的節(jié)點,兄弟服務(wù)器和父服務(wù)器都沒有才找源站
?
這些cache server能根據(jù)內(nèi)容緩存協(xié)議來實現(xiàn)緩存對象共享,高級CDN還能實現(xiàn)內(nèi)容路由(某個cache server上沒有內(nèi)容時自動找有內(nèi)容的cache server),使得盡可能不去找原始server,這并不能完全避免找原始server(如動態(tài)內(nèi)容),就算緩存的內(nèi)容是靜態(tài)的,也不會把整站的內(nèi)容都緩存上去,只能緩存一部分,若緩存策略定義的好,將站點的熱區(qū)數(shù)據(jù)都拉到cache server上實現(xiàn)盡可能多的在cache server上緩存
CDN通常是按流量收費(fèi),視頻站點和圖片站點都要用CDN否則流量大了很容易垮掉
對于中小型電子商務(wù)站點可自建CDN,前提要使用智能DNS(可自建智能DNS,也可使用公共的智能DNS server如dnspod)
注:dnspod在防DDOS方面很強(qiáng),每秒解析達(dá)到數(shù)百萬,還可達(dá)到秒級的更新,更新后隨時生效,還有監(jiān)控原始server的功能,原始server還可通過它做LB完成health check
DNS本身也要分區(qū)域(如北方電信、南方聯(lián)通等),訪問網(wǎng)站不只是獲取網(wǎng)頁的時間還有DNS解析返回,再請求資源,若DNS很慢也影響用戶體驗
bind dlz+{mysql,pgsql,oracke,DB4},http://bind-dlz.sourceforge.net/,將用戶的資源放到數(shù)據(jù)庫中會很慢,如果不是做公共dns server僅為自己公司解析可放在file中,dns啟動時會直接加載至內(nèi)存中;一般使用bind即可(bind本身就提供了智能解析(view))
注:DB4,基于hash編碼的數(shù)據(jù)庫
?
varnish(https://www.varnish-cache.org/):
互聯(lián)網(wǎng)早期的cache server是squid(烏賊,章魚,八爪魚)
varnish本身是reverse proxy server同時又提供cache功能,配置簡單、接口簡單、監(jiān)控接口豐富,由于采用新架構(gòu)設(shè)計,之后擴(kuò)展要比squid容易,功能與nginx近似,但varnish在創(chuàng)建連接、維持連接的能力比nginx差遠(yuǎn)了,通常使用nginx+varnish(nginx處理連接,varnish專門負(fù)責(zé)緩存),也可nginx+squid(squid功能很強(qiáng)大,支持正向代理、反向代理、ACL、支持內(nèi)容分發(fā)協(xié)議,特性非常豐富,配置復(fù)雜)
varnish盡可能利用時下最新的技術(shù),時下最好的軟件設(shè)計結(jié)構(gòu),時下安全體系的諸多經(jīng)驗,站在前人的基礎(chǔ)上設(shè)計的,但squid也寶刀未老,早期淘寶在前端的cache server就使用100多臺server創(chuàng)建的squid cache cluster,優(yōu)化后的命中率達(dá)到97%(純靜態(tài)內(nèi)容),做到這地步要對站點的靜態(tài)資源做好篩選(要將哪些內(nèi)容放到cache server上)
squid?VS? varnish(同httpd? VS?nginx)
?
?
varnish architecture(與nginx類似,是master/slave架構(gòu)):
主進(jìn)程(管理進(jìn)程management,負(fù)責(zé)配置文件分析、裝載新配置文件、啟動子進(jìn)程;Management進(jìn)程主要實現(xiàn)應(yīng)用新的配置(若檢測到VCL配置文件有語法錯誤則拒絕編譯,避免子進(jìn)程加載錯誤配置導(dǎo)致緩存崩潰)、編譯VCL、監(jiān)控varnish、初始化varnish以及提供一個命令行接口等。Management進(jìn)程會每隔幾秒鐘探測一下Child進(jìn)程以判斷其是否正常運(yùn)行,如果在指定的時長內(nèi)未得到Child進(jìn)程的回應(yīng),Management將會重啟此Child進(jìn)程):
CLI interface(通過命令行接口與命令行的控制指令進(jìn)行交互)
telnet interface(為安全這種方式已很少用,可用專用的client工具varnishadm連到管理進(jìn)程完成啟動停止等)
web interface(GUI接口)
?
子進(jìn)程(child|cache進(jìn)程,child提供服務(wù)、發(fā)送至后端并響應(yīng)用戶請求;cache緩存管理的進(jìn)程,緩存清理、緩存有效期限檢查等):
command line
storage/hashing(存儲緩存,用key定義查找標(biāo)準(zhǔn),將key放在某個backet中實現(xiàn)O(1)的查找,查找到的內(nèi)容即是value)
log/stats(varnish的日志不是保存在file中,有磁盤IO,而是在內(nèi)存中,啟動服務(wù)時就明確說明用多大空間保存日志,空間占完后將覆蓋之前的文件繼續(xù)使用,一圈圈輪著使用,日志記錄有client的請求數(shù)、client請求命中數(shù)、沒命中數(shù)、server運(yùn)行多長時間等;可用工具將日志導(dǎo)出查看,如varnishlog等)
accept(接收用戶請求并將請求轉(zhuǎn)至workerthreads上)
backend communication(后端主機(jī)通信)
worker threads(一個線程響應(yīng)多個請求,child進(jìn)程會為每個會話啟動一個worker線程,因此,在高并發(fā)的場景中可能會出現(xiàn)數(shù)百個worker線程甚至更多)
object expiry(從緩存中清理過期內(nèi)容)
?
varnish的主進(jìn)程management只有一個,child進(jìn)程由多個不同的線程組成,varnish總體連接數(shù)在大于5000時性能會下降,一般不會讓工作線程接受太多連接,性能有上限,假設(shè)有10個varnish server每個平均接受5000個連接,那10個就能接受5W個了,前端nignx已處理一些請求再將多個請求轉(zhuǎn)到varnish server上,這種架構(gòu)已達(dá)到億級或十億級PV
?
VCL(varnish configuration language),底層用C開發(fā),完全兼容C語言,提供編程接口,要寫程序提供配置文件,用VCL開發(fā)程序時指明varnish怎么工作(哪些內(nèi)容緩存、哪些內(nèi)容不緩存、哪些內(nèi)容不通過緩存來取等),為使VCL開發(fā)出的程序更加高效,要將其編譯為二進(jìn)制格式(使用VCL編寫好配置文件后,使用gcc編譯)
配置文件編譯完后生成共享模塊,child/cache如何工作就取決于共享模塊中的定義,二進(jìn)制格式的配置文件被子進(jìn)程child/cache讀取,child從后端server取得內(nèi)容后要緩存在本地,由storage/hashing子模塊將緩存內(nèi)容存下來
?
VCL工作在varnish的狀態(tài)引擎state engine上,在varnish內(nèi)部有多個state engine(同iptables的netfilter框架中的幾個接口類似(勾子函數(shù)),若某個報文不經(jīng)過這幾個勾子函數(shù)將檢測不到,所以這幾個勾子要放在報文必經(jīng)的路口,使得報文必須要經(jīng)過這其中1個或幾個勾子,在這些勾子上就能實現(xiàn)管理)
如圖:橢圓表示state engine(又叫domain),菱形表示檢查機(jī)制(條件判斷)
vcl_recv(第一個入口的state engine,請求報文接進(jìn)來)
vcl_recv-->vcl_pass(例如是動態(tài)內(nèi)容或用戶的私有內(nèi)容直接到后端去取)
vcl_recv-->vcl_hash(根據(jù)key來查找本地緩存)
vcl_recv-->vcl_pipe(不對client進(jìn)行檢查或做出任何操作,而是在client和后端server之間建立專用pipe,并直接將數(shù)據(jù)在二者之間傳送;keep-alive連接中后續(xù)傳送的數(shù)據(jù)也都通過此管道進(jìn)行直接傳送,并不會出現(xiàn)在任何日志中)
vcl_hit-->vcl_deliver(命中后交給vcl_deliver再投遞給client)
vcl_hit-->vcl_pass(在管理的CLI下,命中后將緩存清除)
vcl_pass(可對三個state engine(domain)過來的報文統(tǒng)一處理(vcl_recv、vcl_hit、vcl_miss),統(tǒng)一到一個反向操作上(例如命中后不去找緩存而是找vcl_fetch繼而找后端server))
vcl_fetch(到這個domain上就要聯(lián)系后端server,這個域上會定義一些語句來判定哪些內(nèi)容緩存哪些不緩存(如auth或cookie有關(guān)的字串就不緩存))
路線:
vcl_recv-->vcl_hash-->vcl_hit-->vcl_deliver
vcl_recv-->vcl_hash-->vcl_miss-->vcl_fetch-->vcl_deliver
vcl_recv-->vcl_pass-->vcl_fetch-->vcl_vcl_deliver
?
每個state engine中定義一堆條件判斷(如定義vcl_recv在什么情況下去找vcl_hash,在什么情況下找vcl_pass,例如某些client不允許訪問、某些client查找哪些資源、哪些資源不允許緩存等,通過定義各種條件判斷指揮著到下一個數(shù)據(jù)流或state engine)
每個state engine又被叫作domain,每個domain都有可執(zhí)行的指令(如netfilter上各種鏈上的規(guī)則,每個鏈所接受的規(guī)則是不一樣的,處理完成有可能還要經(jīng)過下個鏈,有可能直接返回),而對varnish的每個state engine都要走向下一步(除vcl_deliver)
VCL編程,所寫的代碼,只對當(dāng)前state engine生效(可理解為函數(shù),函數(shù)執(zhí)行完有返回值),返回的是什么就決定下一步怎么走,若return返回hash就找vcl_hash,若return pass則找vcl_pass,到底返回哪個要做寫一大堆的if語句做出判斷
以上涉及到編程,程序中策略寫的好,緩存命中率就高
?
VCL語法:
(1)注釋://和/*(單選注釋);*/(多行注釋)
(2)sub $name(定義函數(shù),subroutine子例程)
(3)不支持循環(huán),有內(nèi)置變量(內(nèi)置變量應(yīng)用位置獨特,有的變量應(yīng)用在前半段(請求報文首部),有的變量應(yīng)用在后半段(響應(yīng)報文首部))
(4)使用終止語句,沒有返回值
(5)域?qū)S?#xff08;每個state engine定義自己的程序)
(6)操作符(=賦值、==等值比較、~模式匹配、!、&&、||)
VCL的函數(shù)不接受參數(shù)且沒有返回值,因此并非真正意義的函數(shù),這也限定了VCL內(nèi)部的數(shù)據(jù)傳遞只能隱藏在http首部內(nèi)部進(jìn)行,VCL的return語句用于將控制權(quán)從VCL狀態(tài)引擎返回給varnish,而非默認(rèn)函數(shù),這就是VCL只有終止語句沒有返回值的原因;同時對于每個域來說,可定義一個或多個終止語句,告訴varnish下一步采取何種操作(如查詢緩存或不查詢緩存等)
?
VCL的內(nèi)置函數(shù):
regsub(str,regex,sub)
regsuball(str,regex,sub)
以上兩項實現(xiàn)替換(substituend,用于將regexp匹配到的str替換為sub,相當(dāng)于nginx的rewrite,而regsuball相當(dāng)于加了修飾符/g的替換)
ban(expression)
ban_url(regex)
purge
以上三項實現(xiàn)緩存清理,給某個緩存對象設(shè)置柵欄,阻止對其使用,先放到禁止列表中再禁止使用,purge僅允許有權(quán)限經(jīng)過認(rèn)證的管理員使用
hash_data(str)(取得一個字符串的hash值,若這個字符串是緩存中的某個key,則可判定緩存中是否有)
return()(當(dāng)某個域運(yùn)行結(jié)束時將控制權(quán)返回給varnish,并指示下一步的動作,可以返回的指令有:lookup,pass,pipe,hit_for_pass,fetch,deliver,hash等),特定域只能返回特定的指令)
return(restart)(重新運(yùn)行整個VCL,即從vcl_recv開始進(jìn)行處理,每一次重啟都會增加req.restarts變量中的值,而max_restarts參數(shù)則用于限定最大重啟次數(shù),例如vcl_recv-->vcl_hash-->vcl_miss-->vcl_pass-->restart-->vcl_recv……,未命中可不讓去vcl_fetch,讓重啟,在vcl_pass中寫入regsub(……)將url重寫rewrite,再在vcl_recv上跑一遍,有可能就命中了,若寫了錯誤的rewrite將導(dǎo)致死循環(huán),restart判定若超過5次就退出直接向client返回error)
注:vcl_deliver要能在client請求內(nèi)容不存在時或restart超過5次退出時,返回錯誤頁面,varnish-server要能生成錯誤響應(yīng)頁(如404,502等)
?
?
?
?
?
以上是學(xué)習(xí)《馬哥運(yùn)維課程》做的筆記。
轉(zhuǎn)載于:https://blog.51cto.com/jowin/1739282
總結(jié)
以上是生活随笔為你收集整理的Linux运维 第三阶段 (十八) varnish的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 中this、getCon
- 下一篇: Linux下Oracle数据库的搭建(新