PHP之深入學(xué)習(xí)Yii2緩存Cache組件詳細講解
什么是緩存組件Cache
緩存是提升 Web 應(yīng)用性能簡便有效的方式。 通過將相對靜態(tài)的數(shù)據(jù)存儲到緩存并在收到請求時取回緩存, 應(yīng)用程序便節(jié)省了每次重新生成這些數(shù)據(jù)所需的時間。
定義緩存組件
Yii2的緩存是通過組件Component實現(xiàn)的,在項目的配置文件中,配置components->cache實現(xiàn)對緩存組件的定義。
項目配置文件的路徑為config/web.php。
頁面緩存PageCache
作為網(wǎng)站來講,Yii2的頁面緩存非常便捷地將已經(jīng)渲染完全的網(wǎng)頁結(jié)果保存起來,并在一個緩存周期內(nèi)不需要再次處理頁面內(nèi)部的控制器動作邏輯。
配置頁面緩存
頁面緩存的配置方式為,在控制器層Controller中配置行為behaviors,通過調(diào)用過濾器filters的方式,在進入具體頁面路徑action的之前,對當前key進行計算,并判斷緩存是否啟用enabled緩存有效期duration。
基礎(chǔ)配置代碼如下所示
return [ 'pageCache' => [ 'class' => 'yiifiltersPageCache', 'only' => ['index'], 'variations' => [ '/', Yii::$app->request->isAjax, ], 'enabled'=>true, 'duration' => Yii::$app->params['pageCacheDuration'], ], ];
過濾器是Yii2中的一個概念,他可以在控制器初始化的時候加載并執(zhí)行,我們可以用這個特點去做一些對控制器的數(shù)據(jù)的限制,比如控制緩存、用戶權(quán)限控制。
這里我們將行為名稱定義為pageCache,顯然名字不重要,因為有的案例中,因為不同的頁面緩存規(guī)則不一樣,我會定義兩個頁面緩存的行為。
其中only為過濾器調(diào)用action的參數(shù),用于限制哪些路徑是啟用action的。
頁面緩存PageCache是緩存組件Cache的一種應(yīng)用
頁面緩存的根本邏輯為
- 配置緩存組件的實現(xiàn)比如文件緩存yiicachingFileCache
- 頁面緩存封裝一層Cache組件,再去調(diào)用存取邏輯
我們可以通過查看頁面緩存源碼vendor/yiisoft/yii2/filters/PageCache.php,我們可以在文件的第162行發(fā)現(xiàn),這里調(diào)用的cache,就是對于緩存的實現(xiàn)。
$this->cache = Instance::ensure($this->cache, 'yiicachingCacheInterface');
自定義頁面緩存過濾器
為什么我們需要自定義緩存組件呢,我歸納原因存在以下幾種
- 緩存判斷邏輯過于簡單或復(fù)雜,不如自己重寫痛快地多
- 緩存key生成方式不滿足業(yè)務(wù)需求
那么如何自定義呢?我個人推薦最簡單粗暴的方式,繼承。
use yiifiltersPageCache; class PageCacheCtInfo extends PageCache { 這里是內(nèi)部邏輯,不需要重寫的方法可以不寫。 public $checkUser = true; //可以自定義變量 }
調(diào)用方式也是跟默認的頁面緩存一樣,只要換上對應(yīng)的類即可。
'pageCacheInfo' => [ 'class' => 'commoncomponentsPageCacheCtInfo', 'only' => ['info'], 'enabled'=>Yii::$app->params['pageCacheEnabled'], 'variations' => [ 'ct/'.Yii::$app->request->pathInfo, Yii::$app->request->isAjax ], 'duration' => Yii::$app->params['pageCacheInfo'], 'checkUser' = false, ],
頁面緩存key的計算
根據(jù)上一個步驟,我們可以重寫計算key的方式,那么之前的key計算方式是什么樣的呢?
文件位置vendor/yiisoft/yii2/filters/PageCache.php。
/** * @return array the key used to cache response properties. * @since 2.0.3 */ protected function calculateCacheKey() { $key = [__CLASS__]; if ($this->varyByRoute) { $key[] = Yii::$app->requestedRoute; } return array_merge($key, (array)$this->variations); }
這里的緩存key是一個數(shù)組,數(shù)組內(nèi)的元素依次是
- 當前類名
- varyByRoute 一般為true
- variations 驗證,這個也是配置中獲取的,根據(jù)上面的配置,則是頁面路徑和是否為ajax
如果是項目的首頁,緩存的key則為
['yiifiltersPageCache','','/‘,0]
如果是個詳情頁面,key為
['yiifiltersPageCach', 'xxx/info','xxx/xxx/3xxxx74.html',0 ]
那么,這個key到底有什么用,為什么要單獨拿出來說呢?
因為我們需要單獨刪除某個頁面緩存。
主動清理過期緩存
根據(jù)源碼vendor/yiisoft/yii2/caching/FileCache.php
/** * Stores a value identified by a key in cache. * This is the implementation of the method declared in the parent class. * * @param string $key the key identifying the value to be cached * @param string $value the value to be cached. Other types (If you have disabled [[serializer]]) unable to get is * correct in [[getValue()]]. * @param int $duration the number of seconds in which the cached value will expire. 0 means never expire. * @return bool true if the value is successfully stored into cache, false otherwise */ protected function setValue($key, $value, $duration) { $this->gc(); $cacheFile = $this->getCacheFile($key); if ($this->directoryLevel > 0) { @FileHelper::createDirectory(dirname($cacheFile), $this->dirMode, true); } // If ownership differs the touch call will fail, so we try to // rebuild the file from scratch by deleting it first // https://github.com/yiisoft/yii2/pull/16120 if (is_file($cacheFile) && function_exists('posix_geteuid') && fileowner($cacheFile) !== posix_geteuid()) { @unlink($cacheFile); } if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) { if ($this->fileMode !== null) { @chmod($cacheFile, $this->fileMode); } if ($duration <= 0) { $duration = 31536000; // 1 year } return @touch($cacheFile, $duration + time()); } $error = error_get_last(); Yii::warning("Unable to write cache file '{$cacheFile}': {$error['message']}", __METHOD__); return false; }
在設(shè)置緩存之前會主動調(diào)用清理緩存的方法gc()
/** * Removes expired cache files. * @param bool $force whether to enforce the garbage collection regardless of [[gcProbability]]. * Defaults to false, meaning the actual deletion happens with the probability as specified by [[gcProbability]]. * @param bool $expiredOnly whether to removed expired cache files only. * If false, all cache files under [[cachePath]] will be removed. */ public function gc($force = false, $expiredOnly = true) { if ($force || mt_rand(0, 1000000) < $this->gcProbability) { $this->gcRecursive($this->cachePath, $expiredOnly); } }
這里問題就出現(xiàn)了,$gcProbability的默認值是10,也就是說,只有0.001%的概率會在設(shè)置緩存的同時清理過期緩存。
這不就跟沒有一樣!
所以對于緩存來說,需要我們主動定期清理過期緩存,不然對應(yīng)的存儲空間就會被占滿。
Yii::$app->cache->gc(true);
優(yōu)化緩存配置
組件的cache在項目的配置文件中定義
'components' => ['cache' => [ 'class' => 'yiicachingFileCache', ],],
這里的自由度就出現(xiàn)了,現(xiàn)在這個配置,是文件緩存,也就是不管是數(shù)據(jù)緩存還是頁面緩存,都是保存在文件里的
根據(jù)源碼 public $cachePath = '@runtime/cache';
緩存的文件是放在runtime/cache文件夾的
那么問題就出現(xiàn)了,磁盤的性能是有瓶頸的,文件讀寫會影響緩存性能。
目前可選的緩存有
- yiicachingApcCache,APC擴展
- yiicachingDbCache,數(shù)據(jù)庫緩存
- yiicachingDummyCache,假的緩存,就是現(xiàn)在沒條件上緩存先把坑占上
- yiicachingFileCache,文件緩存
- yiicachingMemCache,使用 PHP memcache 和 memcached 擴展
- yiiredisCache,redis
- yiicachingWinCache,使用 PHP WinCache 擴展
- yiicachingXCache,使用 PHP XCache擴展
- yiicachingZendDataCache,使用Zend Data Cache
總結(jié)
我在本文中,通過漸進的方式,講了如何使用Yii2的緩存組件,對于一般的使用者來講,已經(jīng)涵蓋了超過九成的坑。
如果你正在學(xué)習(xí)PHP,希望你收藏這篇文章,這會對你以后有所幫助。
到此這篇關(guān)于PHP之深入學(xué)習(xí)Yii2緩存Cache組件詳細講解的文章就介紹到這了,更多相關(guān)PHP之深入學(xué)習(xí)Yii2緩存Cache組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
版權(quán)聲明:
本站所有文章和圖片均來自用戶分享和網(wǎng)絡(luò)收集,文章和圖片版權(quán)歸原作者及原出處所有,僅供學(xué)習(xí)與參考,請勿用于商業(yè)用途,如果損害了您的權(quán)利,請聯(lián)系網(wǎng)站客服處理。