快取是高效能 Web 應用核心。Yii2 提供統一 yii\caching\Cache 介面,支援檔案、資料庫、Memcached、Redis、APC、WinCache、XCache、Zend Data Cache 等多種驅動。本文系統講解配置、基本操作、依賴關係、標籤失效、多級快取、分片策略。
// common/config/main.php
'components' => [
// 檔案快取 (開發/小型專案)
'cache' => [
'class' => 'yii\caching\FileCache',
'cachePath' => '@runtime/cache', // 預設
'keyPrefix' => 'myapp_',
'gcProbability' => 10, // GC 機率
],
// Redis 快取 (生產推薦)
'cache' => [
'class' => 'yii\redis\Cache',
'redis' => 'redis', // 參考 redis 組件
'keyPrefix' => 'myapp:cache:',
'defaultDuration' => 3600,
'serializer' => [ // 自定義序列化
'serialize' => 'igbinary_serialize',
'unserialize' => 'igbinary_unserialize',
],
],
// 多級快取 (L1: APCu 記憶體, L2: Redis 分散式)
'cache' => [
'class' => 'yii\caching\MultiCache',
'caches' => [
'l1' => ['class' => 'yii\caching\ApcCache'],
'l2' => ['class' => 'yii\redis\Cache', 'redis' => 'redis'],
],
// 讀取: L1 → L2,寫入: 同時寫入 L1+L2
],
],
// Redis 連線配置
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => '127.0.0.1',
'port' => 6379,
'database' => 0,
'password' => env('REDIS_PASSWORD'),
'retries' => 3,
'retryInterval' => 100,
],
$cache = Yii::$app->cache;
// 設定 (自動序列化)
$cache->set('key', $data, 3600); // 1小時
$cache->set('key', $data, 0); // 永久 (視驅動)
// 獲取
$data = $cache->get('key'); // false = 不存在/過期
// 多鍵獲取
$values = $cache->getMultiple(['key1', 'key2', 'key3']);
// 存在檢查
$exists = $cache->exists('key');
// 刪除
$cache->delete('key');
$cache->deleteMultiple(['key1', 'key2']);
// 清空
$cache->flush(); // 謹慎使用
// 原子操作 (Redis/APCu 支援)
$cache->add('key', $value, 3600); // 僅不存在時設定
$cache->increment('counter', 1); // 原子遞增
$cache->decrement('counter', 1); // 原子遞減
use yii\caching\DbDependency;
use yii\caching\ExpressionDependency;
use yii\caching\FileDependency;
use yii\caching\TagDependency;
// 1. DB 依賴:查詢結果變化時失效
$dependency = new DbDependency([
'sql' => 'SELECT MAX(updated_at) FROM post WHERE status=1',
]);
$cache->set('posts_list', $posts, 3600, $dependency);
// 2. 表達式依賴:任意 PHP 表達式
$dependency = new ExpressionDependency([
'expression' => 'return Yii::$app->params["site_version"];',
]);
$cache->set('config', $config, 0, $dependency);
// 3. 檔案依賴:檔案修改時間變化
$dependency = new FileDependency([
'fileName' => '@app/config/params.php',
]);
$cache->set('settings', $settings, 0, $dependency);
// 4. 標籤依賴:批量失效 (需驅動支援 TagDependency)
TagDependency::invalidate(Yii::$app->cache, 'user_profile'); // 使所有 'user_profile' 標籤失效
$cache->set('user_123', $profile, 3600, new TagDependency(['tags' => ['user_profile', 'user_123']]));
$cache->set('user_123_posts', $posts, 3600, new TagDependency(['tags' => ['user_123']]));
// Service 層封裝
class PostService {
private $cache;
public function getPostList(array $params): array {
$key = 'post_list_' . md5(json_encode($params));
return $this->cache->getOrSet($key, function() use ($params) {
return Post::find()->where($params)->all();
}, 3600, new TagDependency(['tags' => ['post_list', 'post']]));
}
public function updatePost(int $id, array $data): bool {
$result = Post::updateAll($data, ['id' => $id]);
if ($result) {
// 使相關快取失效
TagDependency::invalidate($this->cache, 'post');
TagDependency::invalidate($this->cache, 'post_list');
TagDependency::invalidate($this->cache, "post_$id");
}
return $result;
}
}
<?php if ($this->beginCache('sidebar_' . $user->id, [
'duration' => 3600,
'dependency' => new TagDependency(['tags' => ['user_sidebar', "user_{$user->id}"]]),
'variations' => [Yii::$app->language], // 按語言區分
])): ?>
<div class="sidebar">
<h3>用戶面板</h3>
<?= $this->render('_profile', ['user' => $user]) ?>
<?= $this->render('_recent_posts', ['user' => $user]) ?>
</div>
<?php $this->endCache(); endif; ?>
// 控制器行為
public function behaviors() {
return [
'httpCache' => [
'class' => 'yii\filters\HttpCache',
'only' => ['index', 'view'],
'lastModified' => function ($action, $params) {
return Post::find()->max('updated_at');
},
'etagSeed' => function ($action, $params) {
return Post::find()->select('id,updated_at')->asArray()->all();
},
'cacheControlHeader' => 'public, max-age=3600',
],
];
}
| 驅動 | 儲存介質 | 分散式 | TTL 支援 | 標籤支援 | 適用場景 |
|---|---|---|---|---|---|
| FileCache | 磁碟 | 否 | 是 | 否 | 開發、單機小型 |
| DbCache | 資料庫 | 是 | 是 | 否 | 已有 DB、無 Redis |
| ApcCache | 共享記憶體 | 否 | 是 | 否 | 單機高速 L1 |
| MemCache | 記憶體 | 是 | 是 | 否 | 傳統分散式 |
| Redis Cache | 記憶體+持久化 | 是 | 是 | 是 (yii\redis\Cache) | 生產首選 |
| MultiCache | 混合 | 視 L2 | 是 | 視 L2 | 多級架構 |
serialize:通用但慢、體積大'serializer' => ['serialize' => 'igbinary_serialize', 'unserialize' => 'igbinary_unserialize']| 陷阱 | 後果 | 解決 |
|---|---|---|
| 快取 Key 衝突 | 資料錯亂 | keyPrefix + 業務前綴 + 參數雜湊 |
| 永久快取無失效機制 | 髒資料永存 | 必加 Dependency 或 TagDependency |
| 大物件未分片 | 網路/記憶體壓力 | 拆分小 Key、或壓縮 (gzip/lz4) |
| 熱 Key 未保護 | 穿透/雪崩 | 互斥鎖重建、隨機過期時間、熔斷 |
| 開發環境未關閉快取 | 改代碼不生效 | ENV 區分、或 force_compile 模式 |
善用 Yii2 統一快取介面、依賴關係自動失效、標籤批量清理、多級架構,能將資料庫查詢降低 80%+,回應時間壓縮至 50ms 以內。