Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: System cache
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
eai
Chciałbym abyście podzielili się doświadczeniami pisania systemu cache.

Ja swój system rozwiązałem w ten sposób:
1. Podczas inicjowania klasy automatyczne skanowanie i usuwanie plikow ktorych czas wygasl.
2. Mozna tworzyc grupy i je konfigurowac(kodowanie,serializowanie,kompresja)
3. Dodawac mozna do grupy, lub trafia do grupy domyslnej
4. Usuwanie automatyczne lub manualne (calosc, grupa, kilka plikow, jeden plik)

I teraz mam dylemat jak zrobic usuwanie przy zmianie tresci. jak narazie przy robieniu jakiegos update elementu daje funkcje do usuwania pliku cache jesli istnieje. W jaki sposob zrobic ze podczas szukania czy istnieje cache sprawdzac czy zawartosc elemntu zrodlowego nie zmienila sie? Jest to mozliwe jesli sie wygeneruje element i porowna z cache ale to mija sie z celem bo cache jest po to zeby ponownie sie nie generowalo.

Druga sprawa to dane cache prywatne. Czy stosowac czy nie?
Np. user dodaje newsa do ktorego mozna dolaczyc kilka zdjec, i teraz czy generowac za pomoca tego samego systemu cache, czyli jako nazwa dac id_sesji_zdjecie1,2,3 itd.. czy robic base64 i trzymac obrazek w zmiennej sesyjnej a potem go odczytac.

Jak narazie moj system sprawuje sie dobrze.
Np 1 pobranie z mysql 40 000 rekordow trwa 4,2s a kolejne dzieki systemu cache trwa 0,9 s
Czyli w pliku cache trzyma 40 000 elementowa tablice i dla kazdego elementu dodatkowo po 3 wartosci (3 kolumny) i to wszystko odczytuje w 0,9 sec wiec chyba jest ok.

Nie wiem jak to bedzie przy np 100 lub wiecej plikach cache z 10 grupami, jesli za kazdym wywolaniem strony bedzie robil skana zeby usuwac stare itd...


Jak wy rozwiazaliscie ten problem? Pozdro
Ace
Mam do ciebie pytanie, czy w praktyce bedziesz uzywal tablic 40 000 rzędowych? Myślę że nie. Np 5 ostatnich newsow... będziesz to cachował? Opłaca się? Ile na tym zaoszczędzisz czasu? Do news'a masz powiedzmy 1000 zdjęć... To i tak myśle, że użytkownik docelowy zobaczy 10-20 zdjęć + link do następnej strony... winksmiley.jpg Sprawdź czy przy takich zapytaniach oszczędzisz czas, czy nie.

Poza tym popatrz jak to konkurenci rozwiązują. np spojz na eZ components, tam jest biblioteka z Cache - może ci coś podsunie na myśl.
nospor
To i ja sie wypowiem, wkoncu Cache napisalem smile.gif

ad1) niepotrzebna operacja. Lepszym rozwiązaniem jest sprawdzanie waznosci cache podczas pobierania obiektu
ad2) grupy to dobry pomysl. mam tak samo
ad3) No popatrz, mam tak samo
ad4) i usuwanie full, usuwanie grup, usuwanie konkretnych obiektow tez mam i to sa dobre metody. Choc pewnie usuwanie konkretnych obiektow (plikow) rzadko będzie sie zdazac

Co do czyszczenia cache przy zmianie tresci. Jesli jako admin zmieniasz tresc, to usuwasz danych obiekt z cache i juz. Nie widze problemu.

Pozatym jesli tworzysz cache z plikow, np. z xml, to czy sa zmiany mozesz sprawdzac po dacie utworzenia pliku. jego zawartosci nie trzeba sprawdzac.
eai
Co do zdjęć chodzilo mi dokladnie o formularz. Jest sytuacja że dodajemy newsa w panelu admina (w aplikacji jednoczesnie moze byc zalogowanych kilka adminow). Formularz ma pola: tytul,tresc itp + pole dodaj zdjecie, zdjecia dodaje sie kolejno ale newsa dodamy do bazy jak skonczymy wybierac zdjecia, i te zdjecia musze gdzies magazynowac a potem przy dodaniu dopiero je odczytuje i przenosze we wlasciwe miejsce. I chodzi o to czy uzywac do tego systemu cache czy trzymac w sesji zdjecia (zrobic bbase64) tylko ze nie wiem jaki jest limit mb dla sesji i czy to nie spowolni.

Hmm ale skanowanie i tak trzeba zrobic np zeby poszukac pliku cache,
ja zrobilem tak ze podczas skanowania usuwam wygasniete elementy i zapisuje do tablicy te ktore sa aktywne, a potem na tablicach robie szukanie, wczytywanie itp

Wiec jakies skanowanie w poszukiwaniu elementu musi byc a ja dodatkowo usuwam to co stare. Nie wiem jak ty to rozwiazales nospor
nospor
No ale nie musisz skanowac w poszukiwaniu czegokolwiek. Cache z zalozenia ma byc szybki, a ty przeszukujesz od razy wszystko, a moze sie okazac ze skrypt bedzie chcial pobrac tylko jeden obiekt z cache. Moim zdaniem jest to bez sensu i nieoptymalne.

Skrypt mowi: chce obiekt X, to ty lecisz i bierzesz obiekt X. Oczywiscie najpierw sprawdzasz czy ten obiekt istnieje i czy jest nadal wazny.

A jak ja to rozwiązalem to mozesz podejrzec. W mym podpisie masz wszystko co ci do tego potrzeba winksmiley.jpg
eai
fakt nie, nie widziałem co to glob()" title="Zobacz w manualu php" target="_manual teraz wszystko się usprawni smile.gif
nospor
ale poco ci glob? Glob moze byc przydatne, gdy dany obiekt zalezy od kilku plikow. W innych przypadkach jest zbedne.
eai
Ja wczesniej robilem opendir->readdir-> a pliki cache maja postrac nazwa,timeout.cache

przy szukaniu plikow znam jedynie nazwe a timeoutu nie znam.
dzieki glob robie 'nazwa,*.cache' i mam juz pliczek a wczesniej robilem na piechote.

Zastanawiam sie czy nie lepiej zrobic nazwa.cache pobierac czas utworzenia zpliku cache a timeout bezposrednio z grupy. Moze to jest lepsze rozwiazanie.... hmmm.
Przybek
Ja mam taka krotka uwage co do sprawdzania timeoutu i usuwania wygaslych plikow. Kiedy ja robilem u siebie (o wiele prostszy, bez grup etc) system cachowania, usuwanie zrobilem na zasadzie cron'a. Jesli na serwerze jest dostep do crona, zwyczajnie wylaczasz w systemie calkowicie to usuwanie, zeby system nie musial za kazdym uruchomieniem sprawdzac czy pliki mu juz wyglasly, czy nie - co jest oczywiscie czasochlonne. Raz na jakis czas automatycznie odpalal sie skrypt w cronie, ktory przeszukiwal cala baze cache w poszukiwaniu wygaslych plikow i je usuwal. Chyba, ze mamy do czynienia z plikami o na prawde krotkiej waznosci, ale wtedy jaki sens stosowania cache?
Natomiast, jesli nie ma sie dostepu do crona, mozna zrobic rowniez tak, ze sprawdzanie wygasania zostanie odpalone jedynie np. przy pierwszej wizycie danego dnia (zakladajac, ze twoje cache'owane pliki maja waznosc dluzsza, niz doba), czy w danej godzinie. Wtedy kasujesz wszystko co przestarzale (nie powinno zabierac wiele czasu), a kolejne zcache'owanie tych plikow nastapi przy kolejnej probie ich odczytu. Nie jestem pewny czy to optymalne rozwiazanie, ale tak to sobie swego czasu wymyslilem, wiec przedstawiam moj pomysl na to winksmiley.jpg
eai
Tak tylko ze tutaj operacje sa na sekundach wiec zeby wszystko bylo okej to co 1 sekunde musial byc uruchamiac Crona co przy duzej ilosci plikow cache moze obciazyc serwer, a tak jak nospor powiedzial cache ma byc szybki i ma odciazac serwer a nie go obciazac.
Neotion
Ale mnie dawno nie było... smile.gif

Grupy to bardzo dobra rzecz w cache, szczególnie jak przyjdzie nim zarządzać.
U mnie nie usuwam plików z cache, jako że jest on obiektem z metodą isValid(), potem sobie po prostu i ifie go uaktualniam. Mniejsze problemy dla systemów plików, w szczególności jeżeli system plików mamy inny niż reiserfs. Do usuwania etc. ogółem administracji są statyczne metody w CacheAdministrator.

A grupowanie też mam chyba egzotycznie: obiekt jest zestawem zmiennych, zaś te zestawy też sobie grupuję tzn. mam cache co całego artykułu czy co tam będę chciał sobie cache'ować, zaś te wszystkie zestawy są w grupie articles/group/ gdzie group będzie grupą artykułów.

Potem łatwo to się usuwa i administuje (CacheAdministrator::deleteGroup('articles'); albo CacheAdministrator::flushGroup()

Kiedyś zamieściłem tutaj na for jakąś wczesną wersję tego cache...
Athlan
Powiem szczeże że dziwnie to zrobiłeś... ja mam po prostu:

(użycie podam przy publikacji okumentacji mojego frameworka)

  1. <?php
  2.  
  3. final class Vcache
  4. {
  5. private static $_sCacheDirectory = NULL;
  6. private $_sCacheName = NULL;
  7. private $_sCachePrefix = 'cache_';
  8. private $_sCacheExtension = '.tmp';
  9. private $_iCacheExpire = 3600;
  10. private $_sCacheFilePatch = NULL;
  11.  
  12. public function __construct($sItemElement)
  13. {
  14. self::_runTemp();
  15. $this->_sCacheName = $sItemElement;
  16. $this->_sCacheFilePatch = self::$_sCacheDirectory . $this->_sCachePrefix . $this->_makeIdentyficator($this->_sCacheName) . $this->_sCacheExtension;
  17. }
  18.  
  19. public function save($mItemHandler)
  20. {
  21. if(is_array($mItemHandler))
  22. $mCachePreparing = serialize($mItemHandler);
  23.  
  24. elseif(is_object($mItemHandler))
  25. $mCachePreparing = serialize(get_class_vars($mmItemHandler));
  26.  
  27. else
  28. $mCachePreparing = $mItemHandler;
  29.  
  30. if(!@file_put_contents($this->_sCacheFilePatch, $mCachePreparing))
  31. throw new VcacheException('Caching "'.$this->_sCacheFilePatch.'" failed!');
  32. }
  33.  
  34. public function load($bUnserialize = FALSE)
  35. {
  36. if(!is_bool($bUnserialize))
  37. throw new VcacheException('Param $bUnserialize must be boolean!');
  38.  
  39. if(Vframe::isUsable($this->_sCacheFilePatch))
  40. {
  41. $sCacheContent = file_get_contents($this->_sCacheFilePatch);
  42.  
  43. if($bUnserialize)
  44. return unserialize($sCacheContent);
  45. else
  46. return $sCacheContent;
  47. }
  48. else
  49. return FALSE;
  50. }
  51.  
  52. public function clear()
  53. {
  54. if($this->ping())
  55. @file_put_contents($this->_sCacheFilePatch, NULL);
  56. }
  57.  
  58. public function delete()
  59. {
  60. if($this->ping())
  61. @unlink($this->_sCacheFilePatch);
  62. }
  63.  
  64. public function expired($iTime = NULL)
  65. {
  66. if(!is_int($iTime) && $iTime !== NULL)
  67. throw new VcacheException('Param $iTime must be integer!');
  68.  
  69. if($iTime === NULL || $iTime === 0)
  70. $iTime = $this->_iCacheExpire;
  71.  
  72. if(!$this->ping())
  73. return TRUE;
  74.  
  75. if((@filemtime($this->_sCacheFilePatch) + $iTime) > time())
  76. return FALSE;
  77. else
  78. return TRUE;
  79. }
  80.  
  81. public function ping()
  82. {
  83. return (bool) Vframe::isUsable($this->_sCacheFilePatch, TRUE, TRUE);
  84. }
  85.  
  86. public function start()
  87. {
  88. }
  89.  
  90. public function stop()
  91. {
  92. $this->save(ob_get_contents());
  93. }
  94.  
  95. public static function clearTemp()
  96. {
  97. $sDirectory = self::_runTemp();
  98.  
  99. if(!($rHandler = @opendir($sDirectory)))
  100. throw new VcacheException('Cannot open "'.$sDirectory.'" cache directory to clear!');
  101.  
  102. while($sCacheItem = @readdir($rHandler))
  103. {
  104. if($sCacheItem != "." && $sCacheItem != "..")
  105. @unlink($sDirectory . $sCacheItem);
  106. }
  107.  
  108. @closedir($rHandler);
  109. }
  110.  
  111. public function setTemp($sTempPatch)
  112. {
  113. if(!Vframe::isUsable($sTempPatch, TRUE, TRUE))
  114. throw new VcacheException('Specified directory "'.$sTempPatch.'" to caching does not exists or it have wrong chmod! Please create this dire
    ctory and set 777 chmod in it.'
    );
  115.  
  116. return self::$_sCacheDirectory = $sTempPatch;
  117. }
  118.  
  119. private static function _runTemp()
  120. {
  121. if(!defined('V_VAR_CACHE'))
  122. throw new VcacheException('Default patch to cache directory has no specified ar V_VAR_CACHE config! Please 
    repair this gap.'
    );
  123.  
  124. return self::setTemp(V_VAR_CACHE);
  125. }
  126.  
  127. private function _makeIdentyficator($sItemName)
  128. {
  129. return md5(base64_encode($sItemName));
  130. }
  131. }
  132.  
  133. ?>
Sh4dow
a mam pytanie czy ktos probował robic cache na sqlite albo na memcache ?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.