Konteksti keša
Keširanje konteksta = (zahtevni) kontekstualni zavisnosti
Konteksti keša su analogni HTTP zaglavlju Vary.
Zašto?
Konteksti keširanja određuju način kreiranja varijanti nečega što treba keširati, a koje zavise od konteksta. Kod koji kreira kešove postaje lakši za čitanje, i nije potrebno da se ista logika ponavlja na svakom mestu gde su potrebne iste kontekstualne promene.
Primeri:
- Izlaz nekih podataka zavisi od aktivne teme i različiti rezultati se prikazuju za različite teme. Tada ćete koristiti keš koji zavisi od konteksta keša teme.
- Kada pravite niz za prikaz koji pokazuje personalizovanu poruku, prikaz niza zavisi od korisnika. Tada keš zavisi od konteksta keša korisnika.
- Obično: kada neka skupa za računanje informacija zavisi od okruženja servera, i za to se koristi keš kontekst.
Kako?
Kontekst keša je string koji se odnosi na jednu od dostupnih usluga konteksta keša (vidi dole).
Konteksti keša se prenose kao skupovi (redosled nije važan) stringova, tako da se štampaju kao string[]. To su skupovi jer jedan keš element može zavisiti (varirati) od više konteksta keša.
Obično kontekste keša dobijate iz objekta konteksta zahteva (tj. iz zahteva). Većina web aplikacionog okruženja se dobija iz konteksta zahteva. Na kraju krajeva, HTTP odgovori se generišu uglavnom zavisno od svojstava HTTP zahteva koji ih je inicirao.
Ali to ne znači da konteksti keša moraju poticati iz zahteva – oni takođe mogu zavisiti od implementiranog koda, na primer kontekst deployment_id.
Drugo, konteksti keša su predstavljeni kao hijerarhija. Najjednostavniji primer: kada nešto varira za svakog korisnika, više nije dovoljno koristiti samo pristupna prava, jer postoje razlike po korisniku. Za set pristupnih prava kešira se za svako pravo posebno. Ako jedan deo stranice varira po korisniku, a drugi po pristupnim pravima, Drupal treba da bude dovoljno pametan da koristi varijacije samo po korisniku. Tu Drupal može koristiti hijerarhijsku informaciju da ne pravi nepotrebne varijacije keša.
Sintaksa
- Tačke razdvajaju roditeljske elemente od potomaka
- Ime keša u množini ukazuje da može imati parametar: dodajte dvotačku i navedite željeni parametar (ako nije naveden, koristiće se svi mogući parametri, npr. svi argumenti zahteva)
Konteksti keša u Drupal 8 jezgru
Drupal 8 jezgro dolazi sa sledećom hijerarhijom keš konteksta:
cookies :name headers :name ip languages :type protocol_version // Dostupno u 8.9.x i novijim. request_format route .book_navigation .menu_active_trails :menu_name .name session .exists theme timezone url .path .is_front // Dostupno u 8.3.x i novijim. .parent .query_args :key .pagers :pager_id .site user .is_super_user .node_grants :operation .permissions .roles :role
Napomena. Da biste koristili kontekst keša url.path.is_front u ranijim verzijama, pogledajte zapis o promeni.
Svuda gde se koriste keš konteksti, navodi se cela hijerarhija, što ima tri prednosti:
- Nema dvosmislenosti: jasno je koji je roditeljski keš kontekst gde god da se koristi
- Upoređivanje (i sažimanje) keš konteksta je lakše: ako postoje i a.b.c i a.b, očigledno je da a.b uključuje a.b.c, pa je jasno zašto se a.b.c može izostaviti i "sažeti" u roditeljski objekat
- Nije potrebno brinuti da li je svaki nivo stabla jedinstven u celom stablu
Primeri keš konteksta iz ove hijerarhije:
- theme (zavisi od aktivne teme)
- user.roles (zavisi od kombinacije uloga)
- user.roles:anonymous (zavisi od toga da li trenutni korisnik ima ulogu "anoniman" ili ne, tj. "da li je anonimni korisnik")
- languages (različiti za sve tipove jezika: interfejs, sadržaj...)
- languages:language_interface (zavisi od jezika interfejsa - LanguageInterface::TYPE_INTERFACE)
- languages:language_content (zavisi od jezika sadržaja - LanguageInterface::TYPE_CONTENT)
- URL (zavisi od celog URL-a)
- url.query_args (zavisi od cele query string)
- url.query_args:foo (zavisi od query argumenta foo)
- protocol_version (zavisi od HTTP verzije 1 naspram 2)
Optimizacija/sažimanje/spajanje/pojednostavljenje keš konteksta
Drupal automatski koristi hijerarhijsku informaciju da maksimalno pojednostavi keš kontekste. Na primer, kada jedan deo stranice varira po korisniku (keš kontekst user), a drugi deo po dozvoli (keš kontekst user.permissions), nema smisla menjati krajnji rezultat na nivou dozvola jer se razlikuje po korisniku.
Drugim rečima: optimize([user, user.permissions]) = [user].
Čak i ako je user.permissions precizniji, ako se optimizuje user.permissions, promene u dozvolama neće prouzrokovati da se keš user.permissions osvežava za svaku stranicu. To znači da, ako se dozvole menjaju, i dalje se koristi ista keširana verzija, iako bi trebalo da se menja pri svakoj promeni dozvola.
Zato keš konteksti koji zavise od konfiguracije, koja se menja tokom vremena, mogu povezivati metapodatke keširanja: tagove keša i maksimalni vek (max-age). Kada se takav keš kontekst optimizuje, njegovi tagovi keša se povezuju sa keš stavkom. Dakle, kad se dodeljene dozvole promene, keš stavka postaje nevažeća.
(Zapamtite, "keširanje" u suštini znači "izbegavanje nepotrebnih izračunavanja". Dakle, optimizaciju konteksta možemo gledati kao keširanje rezultata metode getContext() usluge konteksta. U ovom slučaju to je implicitni keš (vrednost se odbacuje umesto da se skladišti), ali efekat je isti: ako je keš pogodjen, metoda getContext() se ne poziva, dakle se izračunavanja izbegavaju. A kad keširamo nešto, povezujemo kešabilnost te stvari, pa u slučaju keš konteksta povezujemo tagove i max-age.)
Sličan, ali složeniji primer su node grants. Node grants se primenjuju za konkretnog korisnika, pa keš kontekst node grants izgleda kao user.node_grants. Osim što node grants mogu biti izuzetno dinamični (mogu zavisiti, na primer, i od vremena i menjati se svakih nekoliko minuta). To zavisi od implementacija node grant hook-ova na sajtu. Zato je bolje koristiti keš kontekst node grants sa max-age = 0, što znači da se ne može keširati (nije optimizovan). Dakle, optimize([user, user.node_grants]) = [user, user.node_grants].
Neki sajtovi mogu predefinisati podrazumevanu implementaciju keš konteksta za node grants i umesto toga postaviti max-age = 3600, navodeći da svi njihovi hook-ovi za node grants dozvoljavaju keširanje rezultata pristupa najviše sat vremena. Na tim sajtovima optimize([user, user.node_grants]) = [user].
Kako prepoznati, definisati i kreirati?
Konteksti keša su servisi sa oznakom cache.context. Dakle, bilo koji modul može dodati keš kontekste. Oni implementiraju \Drupal\Core\Cache\Context\CacheContextInterface ili \Drupal\Core\Cache\Context\CalculatedCacheContextInterface (za keš kontekste koji prihvataju parametre, tj. keš kontekste sa sufiksom :parameter).
Dakle, sve što treba da uradite da biste pronašli sve keš kontekste koje možete koristiti jeste da pregledate implementacije CacheContextInterface i CalculatedCacheContextInterface pomoću vaše IDE. (U PHPStorm-u: Type Hierarchy → Subtype Hierarchy; u NetBeans-u: kliknite desnim klikom na ime interfejsa → Find Usages → Find All Subtypes.)
Alternativno, možete koristiti Drupal konzolu (drupal debug:cache:context) da prikažete sve aktivne keš kontekste na vašem sajtu ili aplikaciji:
$ drupal debug:cache:context Context ID Label Class path cookies HTTP-Cookies Drupal\Core\Cache\Context\CookiesCacheContext headers HTTP-Header Drupal\Core\Cache\Context\HeadersCacheContext ip IP-Adresse Drupal\Core\Cache\Context\IpCacheContext languages Language Drupal\Core\Cache\Context\LanguagesCacheContext request_format Anfrageformat Drupal\Core\Cache\Context\RequestFormatCacheContext route Route Drupal\Core\Cache\Context\RouteCacheContext route.book_navigation Buchnavigation Drupal\book\Cache\BookNavigationCacheContext route.menu_active_trails Aktiver Menüpfad Drupal\Core\Cache\Context\MenuActiveTrailsCacheContext
U svakom klasu koji pronađete, videćete komentar \Drupal\Core\Cache\Context\UserCacheContext:
Cache context ID: 'user'.
To znači da je 'user' stvarni keš kontekst koji možete koristiti u kodu. (Alternativno, pronađite gde se taj klasa koristi u *.services.yml fajlu i pogledajte ID servisa. Više o tome dole.)
Savet: Možete dobiti potpuni aktuelni spisak svih keš konteksta u Drupal jezgru tako što ćete pogledati servise označene sa cache_context!
ID servisa je standardizovan. Uvek počinje sa cache_context., zatim roditelji konteksta keša, i na kraju ime konteksta keša. Na primer: cache_context (obavezni prefiks) + route (roditelj) + book_navigation (ime konteksta keša):
cache_context.route.book_navigation: class: Drupal\book\Cache\BookNavigationCacheContext arguments: ['@request_stack'] tags: - { name: cache.context }
Ovo definiše keš kontekst route.book_navigation.
Debugovanje
Sve gore navedeno je korisno prilikom debugovanja nečega što se kešira. Ali postoji još jedna stvar: recimo da se nešto kešira sa keš ključevima ['foo', 'bar'] i keš kontekstima ['languages:language_interface', 'user.permissions', 'route']. Onda će odgovarajući keš element biti keširan u konkretnom keš kontejneru sa CID (Cache ID):
foo:bar:[languages:language_interface]=en:[user.permissions]=DUGAČAK_HASH:[route]=myroute.ROUTE_PARAMS_HASH
Drugim rečima:
- keš ključevi su navedeni prvi, u zadatom redosledu
- keš konteksti su navedeni drugi, po abecednom redu, i rezultuju delovima CID u formatu [<ime keš konteksta>]=<vrednost keš konteksta>
- sve ove CID delove povezuje dvotačka
To bi trebalo da olakša analizu i debugovanje keša!
Zaglavlja (debug)
Na kraju: lako je videti od kojih keš konteksta zavisi određeni odgovor (i samim tim se razlikuje) – dovoljno je da pogledate zaglavlje X-Drupal-Cache-Contexts!
Napomena: Ako ne vidite ova zaglavlja, morate podesiti vaš Drupal razvojni primerak.
Dinamčki keš stranica
Opširno korišćenje keš konteksta u Drupal 8 omogućava da Drupal 8 isporučuje dinamički keš stranica uključen po defaultu. (Ranije poznat kao "Smart Cache")
Interni keš stranice
Napomena da interni keš stranice pretpostavlja da će sve stranice koje se služe anonimnim korisnicima biti identične, bez obzira na implementaciju keš konteksta. Ako želite da koristite keš kontekste da menjate sadržaj za anonimne korisnike, ovaj modul treba isključiti, što može uticati na performanse.
Pogledajte i
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.