Transparentní kešování
Máte běžící squid a chcete, aby jej uživatelé na vaší síti používali. To ale znamená, že musíte jít a každého klienta nastavit, aby proxy server používal.
Alternativou je nakonfigurovat síť tak, aby byl automaticky veškerý provoz ze sítě ven, směřující na port 80, přesměrován na vašeho nového squida. Aby to fungovalo, musí se speciálně nastavit jak váš router, tak squid.Pokud váš router je přímo počítač, na kterém běží squid, je situace nejjednodušší – stačí opravdu přesměrovat veškerý HTTP provoz ven ze sítě na port squida. Pomocí iptables by to vypadalo asi takhle:
iptables -t nat -A PREROUTING -p tcp --dport 80 -s vnitrni_sit -i ! vnejsi_interfejs -j REDIRECT --to-port squiduv_port
Pokud se o routing stará někdo jiný než počítač se squidem, nastavení bude podobné (DNAT s adresou namísto REDIRECT), akorát musíme ještě nějak ošetřit případný cyklus, který by vzniknul tím, že by se přesměrovávaly požadavky vycházející už ze squida. Podrobnosti hledejte v manuálu od svého routeru ;-)
Zvláštní nastavení je třeba i v konfiguračním souboru squida. To proto, že v HTTP protokolu není jméno serveru uvedeno jako součást adresy, ale jako zvláštní direktiva Host
, a to až v novějších verzích HTTP (dnes už se s jinými ani nesetkáme, protože by s nimi nefungovalo dnes časté hostování více domén na jedné adrese).
Chování, které pro režim transparentního proxy od squida potřebujeme, je podobné, jako když má squid fungovat coby akcelerátor pro (pomalý) lokální HTTP server. Proto nenajdeme v konfiguračním souboru nic o transparentnosti, ale změníme poněkud složitěji pár nastavení pro akcelerátor:
httpd_accel_host virtual httpd_accel_port 80 httpd_accel_with_proxy on httpd_accel_uses_host_header on
První a čtvrtý řádek znamenají, že se použije právě HTTP parametr Host
, druhý definuje, že WWW servery jsou na portu 80 (akcelerovaný lokální server by mohl být na jiném), a třetí říká, že proxy nemá být pouze akcelerátor, ale má stále fungovat jako kešovací proxy.
Jako po jakékoli jiné změně konfiguračního souboru, stačí jej znovu načíst příkazem squid -k reconfigure
a máte novou transparentní keš.
Redirector
Hned potom, co squid u nového požadavku zkontroluje přístupová práva (ACLs), může předat URL ke zpracování externímu redirectoru a pokračovat až se zpracovanou URL. Redirector je jednoduchý filtr, co na stdin
přečte URL, zpracuje ji a na stdout
vypíše novou verzi.
K zapnutí redirectoru slouží klauzule redirect_program
, kam se zadá cesta k programu. Squid si jich pár spustí do zásoby (viz redirect_children
) pro případ, že by jeden nestíhal požadavky vyřizovat.
Pomocí ACL operátoru redirector_access
můžeme nastavit, pro které požadavky se bude redirector používat.
Součástí squidu žádný redirector není. Existuje jich ale mnoho a není problém si podle příslušného návodu napsat vlastní. Já k naprosté spokojenosti používám squirm. Je malinký a jednoduchý. Do jednoho souboru se napíšou adresy sítí, pro které má fungovat. V hlavním konfiguračním souboru squirm.patterns
je pak na každé řádce jeden regulární výraz a nová URL. Pokud URL na vstupu matchuje s regulárním výrazem, je nahrazena novou.
I takovýto jednoduchý redirector se dá dobře použít na mnoho věcí, například na odfiltrování většiny reklamních bannerů. Myšlenka je jednoduchá: Vytvořte si obrázek velikosti běžného reklamního banneru. Uložte jej někam na web. No a pár takovýchto řádků váz zbaví většiny reklam a dalších zbytečných downloadů:
#univerzalni regexi .*/banners/.* http://nekde/banner.gif regexi .*/banner/.* http://nekde/banner.gif regexi .*/ads/.* http://nekde/banner.gif regexi .*/ad/.* http://nekde/banner.gif regexi .*/banner.cgi.* http://nekde/banner.gif regexi ^http://ad\..* http://nekde/banner.gif regexi ^http://ad.\..* http://nekde/banner.gif regexi ^http://ad..\..* http://nekde/banner.gif regexi ^http://[^/]*banner.* http://nekde/banner.gif #ceske bannery regexi ^http://zobraz\.banman\.cz/.* http://nekde/banner.gif regexi ^http://www\.toplist\.cz/count\.asp?.* http://nekde/banner.gif regexi ^http://www\.navrcholu\.cz/cgi-bin/4web/ nvhit\.pl?.* http://nekde/banner.gif regexi ^http://www\.monitor\.cz/cgi-bin/counter?.* http://nekde/banner.gif regexi ^http://img\.seznam\.cz/reklama/.* http://nekde/banner.gif #cizi bannery regexi ^http://ad.*\.doubleclick\.net/.* http://nekde/banner.gif regexi ^http://www\.linkexchange\.ru/.* http://nekde/banner.gif
Na jedné škole tak například přesměrováváme pornografii na jeden méně závadný obrázek. Příslušné regexpy si jistě domyslíte sami… ;-)
Nebo: vyšla nová verze mozilly? všichni si ji stahují, každý z jiného mirroru? Přesměrujte všechny URL obsahující dané jméno souboru na lokální server.
Refresh algorithm
Pokud kešování není úplně zakázáno direktivami HTTP jako Pragma: no-cache
nebo Cache-control: {Private,No-Cache,No-Store}
, může být objekt při průchodu proxy-serverem uložen do keše.
Refresh algorithm je algoritmus, podle kterého squid určuje, jestli objekt může ještě klientovi vrátit z keše (objekt je FRESH), nebo zda už je příliš zastaralý (STALE) a musí se obnovit z původního serveru.
Z HTTP headerů získaných k objektu se zjistí následující údaje (jsou uloženy v keši)
Date
(čas načtení z HTTP serveru),
Last-Modified
(čas poslední změny),
Expires
(čas vypršení)
Klient může pomocí Cache-Control
a Pragma
headerů určit, jak staré dokumenty chce přijmout, nebo serveru vracení kešovaných dokumentů úplně zakázat (například v reakci na uživatelův příkaz „reload“)
algoritmus vypadá asi tak:
1) pokud je definován header Expires
, určí se stav podle něj
2) Poslal-li klient Cache-Control: max-age
, určí se stav podle něj
3) Je-li objekt v keši déle než konstanta MAX
, je objekt STALE
4) Jsou-li v pořádku headery Date
a Last-Modified
, spočítá se podíl LM_FACTOR = doba_po_jakou_je_objekt_v_keši / (Date – Last_Modified). Je to zajímavá heuristika, která vychází z myšlenky, že se objekty mění s jistou pravidelností. Proto objekt, který jsme stáhli už jako velmi starý, se jen s malou pravděpodobností brzy změní. Naopak objekt, který jsme stáhli jen chvíli po jeho poslední změně, se dost možná bude měnit často. Je-li LM_FACTOR menší než konstanta PERCENT
, je objekt FRESH, jinak je STALE.
5) Je-li objekt v keši kratší dobu než konstanta MIN
, je objekt FRESH, jinak je STALE.
Důvod, proč se tímto algoritmem zabývat, je jednoduchý. Můžeme totiž nastavit konstanty MAX
, PERCENT
a MIN
. Navíc můžeme squidu poručit, aby například v bodě 4) ignoroval výsledek STALE a pokračoval k bodu 6) (opšna override_lastmod
).
K tomuto všemu slouží v konfiguračním souboru klauzule refresh_pattern
. Může jich tam být i víc – první parametr je totiž regexp, kterým se určuje, zda klauzule platí pro danou URL. Bere se v úvahu první matchující, tedy zde záleží na pořadí řádek. Další parametry jsou právě MIN, PERCENT a MAX, s volitelnými opšnami. Je jich několik, většina z nich porušuje standarty HTTP (takže s rozvahou!) a dají se použít například k vynucení ještě agresivnějšího kešování (například ignorování Expires
).
Pokud tedy squid vyhodnotí objekt jako FRESH, pošle jej klientovi. Takto splněnému požadavku se říká „a cache hit“. Pokud je objekt STALE, zjistí se tzv. „podmíněným GET“, nebo „IMS-GET“ (If Modified Since…") dotazem, jestli se od posledního stažení objekt na serveru změnil. Pokud ano, získá se aktuální kopie (a cache miss). Pokud ne, může se použít stávající a v keši se u ní updatují informace o čase.
Tady bych chtěl upozornit na malý problém s některými verzemi M$IE. Ten jako reakci na zmáčknutí „reload“ posílá právě IMS-GET, a ne GET s paramery zakazujícími přijmutí kešovaných dat, pokud v něm není nastaven proxy-server (tj. jede přes transparentní). Znamená to, že pokud máte agresivnější kešování (ne nutně v rozporu s HTTP), tak uživatel nemá možnost získat aktuální verzi dokumentu, až na špinavé triky jako připojení otazníku s nějakým nesmyslným parametrem za URL. Řešení je několik: nepoužívat M$IE ;-), nastavit v něm proxy-server a nevyužít tak transparentnosti, a nebo použít direktivu, která se objevila v nových verzích squidu: ie_refresh on
, která všechny IMS-GET od problémových verzí přepíše na GET/no-cache. Tím se zase bohužel sníží hit ratio.
Hierarchické kešování
Nakonec se trochu odpoutáme od reality malé sítě a povíme si něco málo o hierarchii keší.
Doposud, potřeboval-li squid pro klienta sehnat nějaký dokument, obrátil se přímo na server, na kterém se dokument nalézal. Mnohem efektivnější by ale bylo, kdyby se obrátil nejdříve na nějakou jinou keš poblíž, kde latence spojení bude mnohem menší.
Vztahy mezi kešemi jsou dvou druhů: „parent“ (rodič) a „sibling“ (sourozenec). Rozdíl mezi nimi je ten, že sibling server pro nás nikdy nebude shánět objekt mimo svou keš. Pokud jej má a je fresh, milerád nám jej předá. Pokud ale objekt nemá parent, zajistí ho.
Pro komunikaci mezi kešemi existuje speciální protokol (ICP). Je založen na UDP, protože zprávy jsou dostatečně malé. Squidův „peer/neighbour selection algorithm“, který rozhoduje o tom, odkud získat požadovaný dokument, je zhruba následující:
1) všem sibling i parent keším se pošle ICP žádost, obsahující URL
2) keše odpoví buď ICP_HIT, nebo ICP_MISS, podle toho, jestli objekt mají nakešován, nebo ne
3) Pokud v nějakém časovém limitu dostaneme odpověď ICP_HIT, vyžádáme si objekt od jejího odesílatele.
4) Pokud přišla odpověď ICP_MISS od nějakých parent keší, pošleme žádost té, od které přišla nejrychleji.
5) Jinak pošleme žádost přímo na cílový server
Algoritmus je možné různě pozměňovat, například přiřadit keším priority, nebo určit, jaká keš se vybere, v závislosti na URL. Keše si mezi sebou také můžou periodicky posílat tzv. „cache digest“ – zahashovaný seznam objektů, které mají nakešovány. Pak můžeme v hierarchii požadavky posílat najisto, přímo keši, která je může splnit.
Pro potřebu běžného malého proxy-serveru nic takového nepotřebujeme a často si vystačíme s jednoduchým nastavením keše našeho providera coby parent keše:
cache peer providerova_keš parent 3128 0 no-digest no-query
Protože máme v hierarchii jen jednoho souseda (neighbour), digesty ani ICP nepotřebujeme.
Další vychytávky
Squid toho umí opravdu spoustu. Alespoň za zmínku určitě stojí třeba „Delay pools“, pomocí kterých můžeme nastavit různým požadavkům různé priority (QoS).
Další skvěklá věc pro správu je „Cache manager“. Je to cgi program ( cachemgr.cgi
), pomocí kterého si můžeme přes www prohlížet spoustu různých statistik a informací, užitečných především pro jemné doladění. Stačí jej vzít a zkopírovat někam, odkud můžete spouštět cgi-skripty. Pamatujete se ještě na acl manager ...
? Tak přesně tam se definuje, odkud se k těmto statistikám smí přistupovat.
Opšen, které se dají upravovat, je skutečně dost. Například mnoho různých timeoutů. Nebo strategie výměny objektů v keši. Nápomocny vám budou komentáře ve squid.conf
a perfektní dokumentace na www.squid-cache.org.