PageCache
PageCache的使用是通过在控制器的过滤器,针对限定的action使用组件
public function behaviors() { return [ [ 'class' => 'yii\filters\PageCache', 'only' => ['index'], 'duration' => 60, 'variations' => [ \Yii::$app->language, ], 'dependency' => [ 'class' => 'yii\caching\DbDependency', 'sql' => 'SELECT COUNT(*) FROM post', ], ], ]; }
简单操作可以参考地址 https://www.yiichina.com/doc/api/2.0/yii-filters-pagecache
Cache
PageCache使用的缓存是配置的缓存,参考源码
public function beforeAction($action) { if (!$this->enabled) { return true; } $this->cache = Instance::ensure($this->cache, 'yii\caching\CacheInterface'); //这里调用cache接口 if (is_array($this->dependency)) { $this->dependency = Yii::createObject($this->dependency); } $response = Yii::$app->getResponse(); $data = $this->cache->get($this->calculateCacheKey()); if (!is_array($data) || !isset($data['cacheVersion']) || $data['cacheVersion'] !== static::PAGE_CACHE_VERSION) { $this->view->pushDynamicContent($this); ob_start(); ob_implicit_flush(false); $response->on(Response::EVENT_AFTER_SEND, [$this, 'cacheResponse']); Yii::debug('Valid page content is not found in the cache.', __METHOD__); return true; } $this->restoreResponse($response, $data); Yii::debug('Valid page content is found in the cache.', __METHOD__); return false; }
那cache在哪里定义的呢?
在main.php
的组件里
'cache' => [ 'class' => 'yii\caching\FileCache', ],
这里看到,缓存使用的是文件缓存,当然也可以替换为memcache或者redis,由于都是实现的cache接口,所以pagecache那一层调用的get set这类方法是不需要改动的,能做到无痛切换
FileCache
文件缓存的本质操作是把内容通过序列化的方式存到文件中,并设定文件的修改时间作为缓存的过期时间。
/** * 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; }
每次设定缓存之前,都会有概率触发垃圾回收(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); } }
垃圾回收的触发概率,根据配置的gcProbability,默认是10,所以触发垃圾回收的概率是一百万分之10。
可以通过修改gcProbability的方式提高垃圾回收的概率,在配置文件中定义gcProbability
'cache' => [ 'class' => 'yii\caching\FileCache', 'gcProbability'=>10000 ],
一般不改变这个值去做垃圾回收,而是手动触发cache的gc
Yii::$app->cache->gc(true);