Programování

Vyvinout obecnou službu ukládání do mezipaměti pro zlepšení výkonu

Předpokládejme, že vás spolupracovník požádá o seznam všech zemí světa. Protože nejste žádný odborník na geografii, procházíte webovou stránku OSN, stáhněte si seznam a vytiskněte si ji pro ni. Chce však pouze prozkoumat seznam; ve skutečnosti to nebere s sebou. Protože poslední věcí, kterou potřebujete, je další kousek papíru na stole, dáváte seznam do skartovače.

O den později další spolupracovník požaduje totéž: seznam všech zemí na světě. Nadáváte si, že jste tento seznam neudrželi, a znovu procházíte zpět na web OSN. Při této návštěvě webových stránek si všimnete, že OSN aktualizuje svůj seznam zemí každých šest měsíců. Stáhnete a vytisknete seznam svých spolupracovníků. Dívá se na to, děkuje vám a znovu nechává seznam s vámi. Tentokrát seznam uložíte do zprávy na přiložené poznámce Post-it, která vám připomene, abyste ji po šesti měsících zahodili.

Jistě, během příštích několika týdnů vaši spolupracovníci budou seznam vyžadovat znovu a znovu. Blahopřejeme vám k podání dokumentu, protože dokument můžete extrahovat z registrační schránky rychleji, než jej můžete extrahovat z webu. Vaše koncepce kartotéky se uchytí; brzy každý začne dávat věci do vaší skříňky. Chcete-li zabránit neuspořádanému rozvržení skříně, nastavíte pokyny pro její používání. Ve vaší oficiální funkci jako vedoucí kartotéky, dáte pokyn svým spolupracovníkům, aby na všechny dokumenty umístili štítky a post-it poznámky, které identifikují dokumenty a jejich vyřazení / datum vypršení platnosti. Štítky pomáhají vašim spolupracovníkům najít dokument, který hledají, a post-it poznámky kvalifikují, zda jsou informace aktuální.

Registrační skříň je tak populární, že do ní brzy nebudete moci ukládat žádné nové dokumenty. Musíte se rozhodnout, co vyhodit a co ponechat. I když vyhodíte všechny dokumenty, jejichž platnost vypršela, skříň stále překypuje papírem. Jak se rozhodnete, které dokumenty, jejichž platnost nevypršela, zahodit? Zahodíte nejstarší dokument? Můžete zrušit nejméně často používané nebo nejméně nedávno použité; v obou případech budete potřebovat protokol, který bude uveden při přístupu ke každému dokumentu. Nebo byste se mohli rozhodnout, které dokumenty vyřadit, na základě nějakého jiného determinantu; rozhodnutí je čistě osobní.

Ve vztahu k výše uvedené analogii skutečného světa s počítačovým světem funguje kartotéka jako mezipaměti: vysokorychlostní paměť, která občas vyžaduje údržbu. Dokumenty v mezipaměti jsou objekty v mezipaměti, které všechny odpovídají vámi stanoveným normám, správce mezipaměti. Proces čištění mezipaměti se nazývá očištění. Protože položky v mezipaměti jsou vyčištěny po uplynutí určité doby, nazývá se mezipaměť a časovaná mezipaměť.

V tomto článku se naučíte, jak vytvořit 100% čistou mezipaměť Java, která používá anonymní podproces na pozadí k vyčištění položek, jejichž platnost vypršela. Uvidíte, jak vytvořit takovou mezipaměť a zároveň pochopit kompromisy spojené s různými vzory.

Vytvořte mezipaměť

Dost analogií kartotéky: pojďme přejít na webové stránky. Servery webových stránek se také musí vypořádat s ukládáním do mezipaměti. Servery opakovaně přijímají žádosti o informace, které jsou totožné s jinými požadavky. Pro svůj další úkol musíte vytvořit internetovou aplikaci pro jednu z největších světových společností. Po čtyřech měsících vývoje, včetně mnoha bezesných nocí a příliš mnoha kol Jolt, jde aplikace do testování vývoje s 1000 uživateli. Po testování vývoje následuje certifikační test pro 5 000 uživatelů a následné zavedení produkce pro 20 000 uživatelů. Poté, co obdržíte chyby z nedostatku paměti, zatímco aplikaci testuje pouze 200 uživatelů, se však testování vývoje zastaví.

Chcete-li rozeznat zdroj degradace výkonu, použijete produkt profilování a zjistíte, že server načte více kopií databáze ResultSets, z nichž každý má několik tisíc záznamů. Záznamy tvoří seznam produktů. Seznam produktů je navíc pro každého uživatele stejný. Seznam nezávisí na uživateli, jako by tomu bylo v případě, že by seznam produktů vycházel z parametrizovaného dotazu. Rychle se rozhodnete, že jedna kopie seznamu může sloužit všem souběžným uživatelům, takže ji uložíte do mezipaměti.

Vyvstává však řada otázek, které zahrnují takové složitosti jako:

  • Co když se seznam produktů změní? Jak může mezipaměť vypršet seznamům? Jak zjistím, jak dlouho by měl seznam produktů zůstat v mezipaměti, než vyprší jeho platnost?
  • Co když existují dva odlišné seznamy produktů a tyto dva seznamy se mění v různých intervalech? Mohu jednotlivě vypršet platnost každého seznamu, nebo musí mít všechny stejnou trvanlivost?
  • Co když je mezipaměť prázdná a dva žadatelé ji vyzkouší ve stejnou dobu? Když to oba najdou prázdné, vytvoří si vlastní seznamy a pak se oba pokusí vložit své kopie do mezipaměti?
  • Co když položky sedí v mezipaměti měsíce, aniž by k nim někdo přistupoval? Nezjedou paměť?

Chcete-li tyto výzvy řešit, musíte vytvořit službu ukládání do mezipaměti softwaru.

V analogii kartotéky lidé vždy nejprve zkontrolovali skříň při hledání dokumentů. Váš software musí implementovat stejný postup: před načtením nového seznamu z databáze musí požadavek zkontrolovat službu ukládání do mezipaměti. Jako vývojář softwaru je vaší odpovědností přístup do mezipaměti před přístupem k databázi. Pokud se seznam produktů již načetl do mezipaměti, použijete seznam uložený v mezipaměti za předpokladu, že jeho platnost nevypršela. Pokud seznam produktů není v mezipaměti, načtete jej z databáze a okamžitě jej uložíte do mezipaměti.

Poznámka: Než budete pokračovat v požadavcích a kódu služby ukládání do mezipaměti, možná budete chtít zkontrolovat níže uvedený postranní panel „Mezipaměť versus sdružování“. Vysvětluje to sdružování, související koncept.

Požadavky

V souladu s principy dobrého designu jsem definoval seznam požadavků pro službu ukládání do mezipaměti, kterou budeme v tomto článku vyvíjet:

  1. Ke službě ukládání do mezipaměti má přístup jakákoli aplikace Java.
  2. Objekty lze umístit do mezipaměti.
  3. Objekty lze extrahovat z mezipaměti.
  4. Objekty v mezipaměti mohou samy určit, kdy vyprší, což umožňuje maximální flexibilitu. Služby ukládání do mezipaměti, jejichž platnost vyprší u všech objektů pomocí stejného vzorce vypršení platnosti, neposkytují optimální využití objektů v mezipaměti. Tento přístup je ve velkých systémech nedostatečný, protože například seznam produktů se může denně měnit, zatímco seznam umístění obchodů se může měnit pouze jednou za měsíc.
  5. Vlákno na pozadí, které běží pod nízkou prioritou, odstraní prošlé objekty v mezipaměti.
  6. Službu ukládání do mezipaměti lze později vylepšit použitím nejméně nedávno používaného (LRU) nebo nejméně často používaného (LFU) čisticího mechanismu.

Implementace

Abychom splnili požadavek 1, přijali jsme 100% čisté prostředí Java. Poskytováním veřejnosti dostat a soubor metod ve službě ukládání do mezipaměti, splňujeme také požadavky 2 a 3.

Před pokračováním v diskusi o požadavku 4 krátce zmíním, že vyhovíme požadavku 5 vytvořením anonymního vlákna ve správci mezipaměti; toto vlákno začíná ve statickém bloku. Také uspokojujeme požadavek 6 identifikací bodů, kde by později byl přidán kód pro implementaci algoritmů LRU a LFU. O těchto požadavcích se budu podrobněji zabývat dále v článku.

Nyní zpět k požadavku 4, kde se věci stávají zajímavými. Pokud každý objekt v mezipaměti musí sám určit, zda jeho platnost vypršela, musíte mít způsob, jak se zeptat na objekt, pokud jeho platnost vypršela. To znamená, že všechny objekty v mezipaměti musí splňovat určitá pravidla; toho v Javě dosáhnete implementací rozhraní.

Začněme s pravidly, kterými se řídí objekty umístěné v mezipaměti.

  1. Všechny objekty musí mít veřejnou metodu nazvanou isExpired (), který vrací logickou hodnotu.
  2. Všechny objekty musí mít veřejnou metodu nazvanou getIdentifier (), který vrací objekt, který odlišuje objekt od všech ostatních v mezipaměti.

Poznámka: Než skočíte přímo do kódu, musíte pochopit, že mezipaměť můžete implementovat mnoha způsoby. Našel jsem více než tucet různých implementací. Enhydra a Caucho poskytují vynikající zdroje, které obsahují několik implementací mezipaměti.

Kód rozhraní pro službu ukládání do mezipaměti tohoto článku najdete v seznamu 1.

Výpis 1. Cacheable.java

/ ** * Název: Ukládání do mezipaměti Popis: Toto rozhraní definuje metody, které musí být implementovány všemi objekty, které si přejí být umístěny do mezipaměti. * * Copyright: Copyright (c) 2001 * Company: JavaWorld * FileName: Cacheable.java @author Jonathan Lurie @version 1.0 * / public interface Cacheable {/ * Vyžadováním, aby všechny objekty určovaly své vlastní expirace, je algoritmus abstrahován od služba ukládání do mezipaměti, čímž poskytuje maximální flexibilitu, protože každý objekt může přijmout jinou strategii vypršení platnosti. * / public boolean isExpired (); / * Tato metoda zajistí, že služba ukládání do mezipaměti není zodpovědná za jednoznačnou identifikaci objektů umístěných v mezipaměti. * / public Object getIdentifier (); } 

Jakýkoli objekt vložený do mezipaměti - a Tětivanapříklad - musí být zabaleno uvnitř objektu, který implementuje Ukládatelné do mezipaměti rozhraní. Výpis 2 je příkladem obecné třídy obálky s názvem CachedObject; může obsahovat jakýkoli objekt, který je třeba umístit do mezipaměti. Všimněte si, že tato obálka třídy implementuje Ukládatelné do mezipaměti rozhraní definované v seznamu 1.

Výpis 2. CachedManagerTestProgram.java

/ ** * Název: Ukládání do mezipaměti * Popis: Obal objektu Generic Cache Object. Implementuje mezipaměť rozhraní * používá TimeToLive strategii pro vypršení platnosti CacheObject. * Copyright: Copyright (c) 2001 * Company: JavaWorld * Filename: CacheManagerTestProgram.java * @author Jonathan Lurie * @version 1.0 * / public class CachedObject implements Cacheable {// +++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++ / * Tato proměnná se použije k určení, zda platnost objektu vypršela. * / private java.util.Date dateofExpiration = null; soukromý identifikátor objektu = null; / * Toto obsahuje skutečnou "hodnotu". Toto je objekt, který je třeba sdílet. * / public Object object = null; // ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++ public CachedObject (Object obj, Object id, int minutesToLive) {this.object = obj; this.identifier = id; // minutesToLive 0 znamená, že žije dál neomezeně. if (minutesToLive! = 0) {dateofExpiration = new java.util.Date (); java.util.Calendar cal = java.util.Calendar.getInstance (); cal.setTime (dateofExpiration); cal.add (cal.MINUTE, minutesToLive); dateofExpiration = cal.getTime (); }} // +++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++ public boolean isExpired () {// Pamatujte, že pokud počet minut života je nulový, pak to bude navždy! if (dateofExpiration! = null) {// datum vypršení platnosti je porovnáno. if (dateofExpiration.before (new java.util.Date ())) {System.out.println ("CachedResultSet.isExpired: Expired from Cache! EXPIRE TIME:" + dateofExpiration.toString () + "CURRENT TIME:" + ( new java.util.Date ()). toString ()); návrat true; } else {System.out.println ("CachedResultSet.isExpired: Expired not from Cache!"); návrat false; }} else // To znamená, že to žije věčně! návrat false; } // ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++ veřejný objekt getIdentifier () {návratový identifikátor; } // ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++} 

The CachedObject třída vystavuje metodu konstruktoru, která má tři parametry:

public CachedObject (Object obj, Object id, int minutesToLive) 

Tabulka níže popisuje tyto parametry.

Popisy parametrů konstruktoru CachedObject
názevTypPopis
ObjObjektObjekt, který je sdílen. Je definován jako objekt, který umožňuje maximální flexibilitu.
IdObjektId obsahuje jedinečný identifikátor, který odlišuje obj parametr ze všech ostatních objektů umístěných v mezipaměti. Služba ukládání do mezipaměti neodpovídá za zajištění jedinečnosti objektů v mezipaměti.
minutesToLiveIntPočet minut, které obj parametr je platný v mezipaměti. V této implementaci služba mezipaměti interpretuje hodnotu nula, což znamená, že objekt nikdy nevyprší. Možná budete chtít tento parametr změnit v případě, že potřebujete vypršet platnost objektů za méně než jednu minutu.

Metoda konstruktoru určuje datum vypršení platnosti objektu v mezipaměti pomocí a čas žít strategie. Jak jeho název napovídá, čas do života znamená, že určitý objekt má stanovený čas, na jehož konci je považován za mrtvý. Přidáváním minutesToLive, konstruktér int parametru, do aktuálního času se počítá datum vypršení platnosti. Toto vypršení platnosti je přiřazeno proměnné třídy datum spotřeby.

Nyní isExpired () metoda musí jednoduše určit, zda datum spotřeby je před nebo po aktuálním datu a čase. Pokud je datum před aktuálním časem a objekt v mezipaměti je považován za vypršel, isExpired () metoda vrací true; pokud je datum po aktuálním čase, platnost objektu v mezipaměti nevypršela a isExpired () vrátí false. Samozřejmě, pokud datum spotřeby je null, což by byl případ, kdyby minutesToLive byla nula, pak isExpired () metoda vždy vrátí hodnotu false, což znamená, že objekt v mezipaměti žije navždy.

$config[zx-auto] not found$config[zx-overlay] not found