ThinkPHP6/8 缓存系统深度优化:多驱动配置与性能调优实战
Orion K Lv6

ThinkPHP6/8的缓存系统支持多种驱动类型,遵循PSR-16规范,提供了强大的缓存功能。本文将深入探讨缓存系统的高级配置、性能优化技巧和实战应用场景,帮助开发者构建高性能的缓存架构。

缓存系统架构概述

支持的缓存驱动

ThinkPHP内置支持以下缓存类型:

  • File:文件缓存,适合小型应用
  • Redis:内存缓存,高性能,支持集群
  • Memcache:分布式内存缓存
  • Database:数据库缓存
  • Wincache:Windows平台缓存
  • SQLite:轻量级数据库缓存

缓存配置架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?php
// config/cache.php
return [
// 默认缓存驱动
'default' => env('cache.driver', 'redis'),

// 缓存存储配置
'stores' => [
// 文件缓存
'file' => [
'type' => 'file',
'path' => runtime_path() . 'cache/',
'prefix' => 'think_',
'expire' => 0,
'serialize' => ['serialize', 'unserialize'],
],

// Redis缓存
'redis' => [
'type' => 'redis',
'host' => env('redis.host', '127.0.0.1'),
'port' => env('redis.port', 6379),
'password' => env('redis.password', ''),
'select' => env('redis.select', 0),
'timeout' => 0,
'expire' => 0,
'persistent' => false,
'prefix' => 'think:',
'serialize' => ['serialize', 'unserialize'],
],

// Redis集群配置
'redis_cluster' => [
'type' => 'redis',
'host' => [
'192.168.1.100:7000',
'192.168.1.100:7001',
'192.168.1.100:7002',
],
'password' => env('redis.password', ''),
'timeout' => 0,
'expire' => 0,
'prefix' => 'cluster:',
'serialize' => ['serialize', 'unserialize'],
],

// 数据库缓存
'database' => [
'type' => 'database',
'connection' => 'mysql',
'table' => 'cache',
'prefix' => 'db_',
'expire' => 0,
],

// Memcache缓存
'memcache' => [
'type' => 'memcache',
'host' => '127.0.0.1',
'port' => 11211,
'username' => '',
'password' => '',
'timeout' => 0,
'expire' => 0,
'prefix' => 'mc_',
],
],
];

高级缓存操作

多驱动缓存管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php
namespace app\service;

use think\facade\Cache;
use think\facade\Log;

/**
* 高级缓存服务类
*/
class AdvancedCacheService
{
/**
* 多级缓存策略
* @param string $key 缓存键
* @param mixed $data 缓存数据
* @param int $expire 过期时间
* @return bool
*/
public function setMultiLevel(string $key, $data, int $expire = 3600): bool
{
try {
// L1缓存:Redis(快速访问)
Cache::store('redis')->set($key, $data, $expire);

// L2缓存:文件(备份存储)
Cache::store('file')->set($key, $data, $expire * 2);

// L3缓存:数据库(持久化)
if ($expire > 3600) {
Cache::store('database')->set($key, $data, $expire * 3);
}

return true;
} catch (\Exception $e) {
Log::error('多级缓存设置失败: ' . $e->getMessage());
return false;
}
}

/**
* 多级缓存获取
* @param string $key 缓存键
* @return mixed
*/
public function getMultiLevel(string $key)
{
// 优先从Redis获取
$data = Cache::store('redis')->get($key);
if ($data !== null) {
return $data;
}

// Redis失效,从文件缓存获取
$data = Cache::store('file')->get($key);
if ($data !== null) {
// 重新设置Redis缓存
Cache::store('redis')->set($key, $data, 1800);
return $data;
}

// 文件缓存也失效,从数据库缓存获取
$data = Cache::store('database')->get($key);
if ($data !== null) {
// 重新设置上级缓存
Cache::store('redis')->set($key, $data, 1800);
Cache::store('file')->set($key, $data, 3600);
return $data;
}

return null;
}

/**
* 智能缓存设置(根据数据大小选择驱动)
* @param string $key 缓存键
* @param mixed $data 缓存数据
* @param int $expire 过期时间
* @return bool
*/
public function smartSet(string $key, $data, int $expire = 3600): bool
{
$serialized = serialize($data);
$size = strlen($serialized);

// 小于1MB使用Redis
if ($size < 1024 * 1024) {
return Cache::store('redis')->set($key, $data, $expire);
}

// 1MB-10MB使用文件缓存
if ($size < 10 * 1024 * 1024) {
return Cache::store('file')->set($key, $data, $expire);
}

// 大于10MB使用数据库缓存
return Cache::store('database')->set($key, $data, $expire);
}
}

缓存标签管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* 缓存标签管理服务
*/
class CacheTagService
{
/**
* 用户相关缓存管理
* @param int $userId 用户ID
* @param array $userData 用户数据
* @return bool
*/
public function setUserCache(int $userId, array $userData): bool
{
$userTag = 'user_' . $userId;

// 设置用户基础信息缓存
Cache::tag($userTag)->set("user_info_{$userId}", $userData['info'], 3600);

// 设置用户权限缓存
Cache::tag([$userTag, 'permissions'])->set("user_permissions_{$userId}", $userData['permissions'], 1800);

// 设置用户偏好设置缓存
Cache::tag($userTag)->set("user_preferences_{$userId}", $userData['preferences'], 7200);

return true;
}

/**
* 清除用户相关缓存
* @param int $userId 用户ID
* @return bool
*/
public function clearUserCache(int $userId): bool
{
$userTag = 'user_' . $userId;
return Cache::tag($userTag)->clear();
}

/**
* 批量清除权限相关缓存
* @return bool
*/
public function clearPermissionCache(): bool
{
return Cache::tag('permissions')->clear();
}

/**
* 商品分类缓存管理
* @param int $categoryId 分类ID
* @param array $products 商品列表
* @return bool
*/
public function setCategoryProductCache(int $categoryId, array $products): bool
{
$tags = ['category', 'products', "category_{$categoryId}"];

// 设置分类商品列表缓存
Cache::tag($tags)->set("category_products_{$categoryId}", $products, 1800);

// 设置分类商品数量缓存
Cache::tag($tags)->set("category_count_{$categoryId}", count($products), 3600);

return true;
}

/**
* 清除分类相关缓存
* @param int $categoryId 分类ID
* @return bool
*/
public function clearCategoryCache(int $categoryId = null): bool
{
if ($categoryId) {
return Cache::tag("category_{$categoryId}")->clear();
}

// 清除所有分类缓存
return Cache::tag('category')->clear();
}
}

缓存预热和更新策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* 缓存预热服务
*/
class CacheWarmupService
{
/**
* 系统配置缓存预热
* @return bool
*/
public function warmupSystemConfig(): bool
{
try {
// 预热系统配置
$configs = Db::name('system_config')->select()->toArray();
$configData = [];
foreach ($configs as $config) {
$configData[$config['key']] = $config['value'];
}
Cache::tag('system')->set('system_config', $configData, 86400);

// 预热菜单配置
$menus = Db::name('admin_menu')->where('status', 1)->order('sort')->select()->toArray();
Cache::tag('system')->set('admin_menus', $menus, 3600);

// 预热权限配置
$permissions = Db::name('admin_permission')->select()->toArray();
Cache::tag('system')->set('admin_permissions', $permissions, 3600);

return true;
} catch (\Exception $e) {
Log::error('系统配置缓存预热失败: ' . $e->getMessage());
return false;
}
}

/**
* 热门商品缓存预热
* @return bool
*/
public function warmupHotProducts(): bool
{
try {
// 获取热门商品
$hotProducts = Db::name('products')
->where('is_hot', 1)
->where('status', 1)
->order('sales desc')
->limit(100)
->select()
->toArray();

Cache::tag(['products', 'hot'])->set('hot_products', $hotProducts, 1800);

// 按分类预热热门商品
$categories = Db::name('categories')->where('status', 1)->column('id');
foreach ($categories as $categoryId) {
$categoryHotProducts = array_filter($hotProducts, function($product) use ($categoryId) {
return $product['category_id'] == $categoryId;
});

if (!empty($categoryHotProducts)) {
Cache::tag(['products', 'hot', "category_{$categoryId}"])
->set("hot_products_category_{$categoryId}", array_values($categoryHotProducts), 1800);
}
}

return true;
} catch (\Exception $e) {
Log::error('热门商品缓存预热失败: ' . $e->getMessage());
return false;
}
}

/**
* 定时缓存更新
* @return bool
*/
public function scheduledUpdate(): bool
{
// 更新统计数据缓存
$this->updateStatisticsCache();

// 更新排行榜缓存
$this->updateRankingCache();

// 清理过期缓存
$this->cleanExpiredCache();

return true;
}

/**
* 更新统计数据缓存
* @return bool
*/
private function updateStatisticsCache(): bool
{
$stats = [
'total_users' => Db::name('users')->count(),
'total_orders' => Db::name('orders')->count(),
'total_products' => Db::name('products')->where('status', 1)->count(),
'today_orders' => Db::name('orders')->whereTime('created_at', 'today')->count(),
'today_sales' => Db::name('orders')->whereTime('created_at', 'today')->sum('total_amount'),
];

return Cache::tag('statistics')->set('site_statistics', $stats, 3600);
}

/**
* 更新排行榜缓存
* @return bool
*/
private function updateRankingCache(): bool
{
// 销量排行榜
$salesRanking = Db::name('products')
->field('id,name,sales,price')
->where('status', 1)
->order('sales desc')
->limit(50)
->select()
->toArray();

Cache::tag('ranking')->set('sales_ranking', $salesRanking, 1800);

// 用户积分排行榜
$pointsRanking = Db::name('users')
->field('id,nickname,points')
->where('status', 1)
->order('points desc')
->limit(100)
->select()
->toArray();

Cache::tag('ranking')->set('points_ranking', $pointsRanking, 3600);

return true;
}

/**
* 清理过期缓存
* @return bool
*/
private function cleanExpiredCache(): bool
{
// 清理临时缓存
Cache::tag('temp')->clear();

// 清理过期的用户会话缓存
$expiredSessions = Cache::getTagItems('user_session');
foreach ($expiredSessions as $sessionKey) {
if (Cache::get($sessionKey) === null) {
Cache::delete($sessionKey);
}
}

return true;
}
}

性能优化策略

缓存性能监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* 缓存性能监控服务
*/
class CacheMonitorService
{
/**
* 缓存命中率统计
* @param string $key 缓存键
* @param bool $hit 是否命中
* @return void
*/
public function recordHitRate(string $key, bool $hit): void
{
$date = date('Y-m-d');
$hourKey = "cache_stats_{$date}_" . date('H');

// 记录总请求数
Cache::inc($hourKey . '_total');

// 记录命中数
if ($hit) {
Cache::inc($hourKey . '_hits');
}

// 记录具体键的统计
$keyStatsKey = "cache_key_stats_{$date}";
$keyStats = Cache::get($keyStatsKey, []);

if (!isset($keyStats[$key])) {
$keyStats[$key] = ['total' => 0, 'hits' => 0];
}

$keyStats[$key]['total']++;
if ($hit) {
$keyStats[$key]['hits']++;
}

Cache::set($keyStatsKey, $keyStats, 86400);
}

/**
* 获取缓存统计报告
* @param string $date 日期
* @return array
*/
public function getStatsReport(string $date = null): array
{
$date = $date ?: date('Y-m-d');
$report = [
'date' => $date,
'hourly_stats' => [],
'total_requests' => 0,
'total_hits' => 0,
'hit_rate' => 0,
'top_keys' => []
];

// 获取小时统计
for ($hour = 0; $hour < 24; $hour++) {
$hourKey = "cache_stats_{$date}_" . sprintf('%02d', $hour);
$total = Cache::get($hourKey . '_total', 0);
$hits = Cache::get($hourKey . '_hits', 0);

$report['hourly_stats'][$hour] = [
'total' => $total,
'hits' => $hits,
'hit_rate' => $total > 0 ? round($hits / $total * 100, 2) : 0
];

$report['total_requests'] += $total;
$report['total_hits'] += $hits;
}

// 计算总命中率
$report['hit_rate'] = $report['total_requests'] > 0
? round($report['total_hits'] / $report['total_requests'] * 100, 2)
: 0;

// 获取热门缓存键
$keyStatsKey = "cache_key_stats_{$date}";
$keyStats = Cache::get($keyStatsKey, []);

// 按请求次数排序
uasort($keyStats, function($a, $b) {
return $b['total'] - $a['total'];
});

$report['top_keys'] = array_slice($keyStats, 0, 20, true);

return $report;
}

/**
* 缓存性能分析
* @return array
*/
public function performanceAnalysis(): array
{
$analysis = [
'memory_usage' => [],
'slow_operations' => [],
'recommendations' => []
];

// Redis内存使用分析
if (Cache::store('redis')->handler()) {
$redis = Cache::store('redis')->handler();
$info = $redis->info('memory');

$analysis['memory_usage'] = [
'used_memory' => $info['used_memory_human'] ?? 'N/A',
'used_memory_peak' => $info['used_memory_peak_human'] ?? 'N/A',
'memory_fragmentation_ratio' => $info['mem_fragmentation_ratio'] ?? 'N/A'
];
}

// 慢操作检测
$slowKeys = Cache::get('slow_cache_operations', []);
$analysis['slow_operations'] = array_slice($slowKeys, 0, 10);

// 性能建议
$analysis['recommendations'] = $this->generateRecommendations();

return $analysis;
}

/**
* 生成性能优化建议
* @return array
*/
private function generateRecommendations(): array
{
$recommendations = [];

// 检查命中率
$todayStats = $this->getStatsReport();
if ($todayStats['hit_rate'] < 80) {
$recommendations[] = [
'type' => 'hit_rate',
'message' => '缓存命中率较低(' . $todayStats['hit_rate'] . '%),建议优化缓存策略',
'priority' => 'high'
];
}

// 检查内存使用
if (isset($this->performanceAnalysis()['memory_usage']['mem_fragmentation_ratio'])) {
$fragmentation = floatval($this->performanceAnalysis()['memory_usage']['mem_fragmentation_ratio']);
if ($fragmentation > 1.5) {
$recommendations[] = [
'type' => 'memory',
'message' => 'Redis内存碎片率较高(' . $fragmentation . '),建议重启Redis',
'priority' => 'medium'
];
}
}

return $recommendations;
}
}

缓存优化中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* 缓存优化中间件
*/
class CacheOptimizeMiddleware
{
/**
* 处理请求
* @param Request $request
* @param \Closure $next
* @return Response
*/
public function handle(Request $request, \Closure $next)
{
$startTime = microtime(true);

// 检查是否可以使用页面缓存
if ($this->shouldCachePage($request)) {
$cacheKey = $this->generatePageCacheKey($request);
$cachedResponse = Cache::get($cacheKey);

if ($cachedResponse) {
// 记录缓存命中
app(CacheMonitorService::class)->recordHitRate($cacheKey, true);
return response($cachedResponse['content'], $cachedResponse['code'], $cachedResponse['headers']);
}
}

$response = $next($request);

// 缓存页面响应
if ($this->shouldCachePage($request) && $response->getCode() == 200) {
$cacheKey = $this->generatePageCacheKey($request);
$cacheData = [
'content' => $response->getContent(),
'code' => $response->getCode(),
'headers' => $response->getHeader()
];

Cache::set($cacheKey, $cacheData, 300); // 缓存5分钟
}

// 记录响应时间
$responseTime = microtime(true) - $startTime;
if ($responseTime > 1) { // 超过1秒的慢请求
$slowKey = 'slow_cache_operations';
$slowOps = Cache::get($slowKey, []);
$slowOps[] = [
'url' => $request->url(),
'time' => $responseTime,
'timestamp' => time()
];

// 只保留最近100条慢操作记录
if (count($slowOps) > 100) {
$slowOps = array_slice($slowOps, -100);
}

Cache::set($slowKey, $slowOps, 86400);
}

return $response;
}

/**
* 判断是否应该缓存页面
* @param Request $request
* @return bool
*/
private function shouldCachePage(Request $request): bool
{
// 只缓存GET请求
if (!$request->isGet()) {
return false;
}

// 不缓存带有用户认证的请求
if ($request->header('Authorization') || $request->cookie('user_token')) {
return false;
}

// 不缓存管理后台页面
if (strpos($request->pathinfo(), 'admin/') === 0) {
return false;
}

return true;
}

/**
* 生成页面缓存键
* @param Request $request
* @return string
*/
private function generatePageCacheKey(Request $request): string
{
$key = 'page_cache:' . md5($request->url() . serialize($request->param()));
return $key;
}
}

实战应用案例

电商商品缓存策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
* 商品缓存服务
*/
class ProductCacheService
{
/**
* 获取商品详情(多级缓存)
* @param int $productId 商品ID
* @return array|null
*/
public function getProductDetail(int $productId): ?array
{
$cacheKey = "product_detail_{$productId}";

// L1: Redis缓存(热点数据)
$product = Cache::store('redis')->get($cacheKey);
if ($product) {
return $product;
}

// L2: 文件缓存(温数据)
$product = Cache::store('file')->get($cacheKey);
if ($product) {
// 重新设置Redis缓存
Cache::store('redis')->set($cacheKey, $product, 1800);
return $product;
}

// L3: 数据库查询
$product = Db::name('products')
->alias('p')
->leftJoin('product_categories c', 'p.category_id = c.id')
->leftJoin('brands b', 'p.brand_id = b.id')
->field('p.*, c.name as category_name, b.name as brand_name')
->where('p.id', $productId)
->where('p.status', 1)
->find();

if ($product) {
// 获取商品图片
$product['images'] = Db::name('product_images')
->where('product_id', $productId)
->order('sort')
->column('image_url');

// 获取商品规格
$product['skus'] = Db::name('product_skus')
->where('product_id', $productId)
->where('status', 1)
->select()
->toArray();

// 设置多级缓存
Cache::store('redis')->set($cacheKey, $product, 1800);
Cache::store('file')->set($cacheKey, $product, 3600);

// 设置标签缓存
Cache::tag(['products', "product_{$productId}", "category_{$product['category_id']}"])
->set($cacheKey, $product, 1800);
}

return $product;
}

/**
* 批量预热商品缓存
* @param array $productIds 商品ID数组
* @return bool
*/
public function batchWarmup(array $productIds): bool
{
foreach ($productIds as $productId) {
$this->getProductDetail($productId);
}

return true;
}

/**
* 更新商品缓存
* @param int $productId 商品ID
* @param array $productData 商品数据
* @return bool
*/
public function updateProductCache(int $productId, array $productData): bool
{
$cacheKey = "product_detail_{$productId}";

// 清除旧缓存
Cache::tag("product_{$productId}")->clear();

// 设置新缓存
Cache::store('redis')->set($cacheKey, $productData, 1800);
Cache::store('file')->set($cacheKey, $productData, 3600);

// 清除相关列表缓存
Cache::tag("category_{$productData['category_id']}")->clear();

return true;
}
}

最佳实践总结

1. 缓存设计原则

  • 分层缓存:使用多级缓存提高命中率
  • 合理过期:根据数据特性设置合适的过期时间
  • 标签管理:使用标签实现精确的缓存清理
  • 监控告警:建立完善的缓存监控体系

2. 性能优化建议

  • 预热策略:系统启动时预热热点数据
  • 异步更新:使用队列异步更新缓存
  • 压缩存储:大数据使用压缩算法
  • 连接池:使用连接池减少连接开销

3. 安全注意事项

  • 数据加密:敏感数据缓存前加密
  • 访问控制:限制缓存访问权限
  • 防止穿透:使用布隆过滤器防止缓存穿透
  • 限流保护:对缓存操作进行限流

4. 运维监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 缓存健康检查
class CacheHealthCheck
{
public function check(): array
{
$health = [
'redis' => $this->checkRedis(),
'file' => $this->checkFile(),
'memory_usage' => $this->getMemoryUsage(),
'hit_rate' => $this->getHitRate()
];

return $health;
}

private function checkRedis(): bool
{
try {
Cache::store('redis')->set('health_check', time(), 10);
return Cache::store('redis')->get('health_check') !== null;
} catch (\Exception $e) {
return false;
}
}

private function checkFile(): bool
{
try {
Cache::store('file')->set('health_check', time(), 10);
return Cache::store('file')->get('health_check') !== null;
} catch (\Exception $e) {
return false;
}
}
}

ThinkPHP的缓存系统功能强大且灵活,通过合理的配置和优化策略,可以显著提升应用性能。在实际项目中,应该根据业务特点选择合适的缓存驱动和策略,并建立完善的监控和运维体系。

本站由 提供部署服务