Skip to content

缓存配置

Dux PHP Admin 基于 DuxLite 框架的缓存系统,采用 Symfony Cache 组件,支持文件和 Redis 两种缓存驱动,实现了 PSR-16 简单缓存接口标准。

支持的缓存驱动

文件缓存(默认)

  • 存储位置: data/cache/ 目录
  • 适用场景: 开发环境、小型应用
  • 特点: 无需额外依赖,配置简单

Redis 缓存

  • 存储位置: Redis 服务器
  • 适用场景: 生产环境、高并发应用
  • 特点: 高性能、支持分布式、丰富的数据结构

缓存配置

基础配置

config/use.toml 中配置缓存:

toml
[cache]
# 缓存类型:file(文件缓存)或 redis(Redis缓存)
type = "file"

# 缓存前缀(避免命名冲突)
prefix = "duxlite_"

# 默认缓存生存时间(秒,0表示永不过期)
defaultLifetime = 3600

文件缓存配置

toml
[cache]
type = "file"
prefix = "app_cache_"
defaultLifetime = 7200

存储目录: data/cache/

  • 目录会自动创建
  • 确保 Web 服务器有读写权限

Redis 缓存配置

toml
[cache]
type = "redis"
prefix = "cache:"
defaultLifetime = 3600

需要在 config/database.toml 中配置 Redis 连接:

toml
[redis.drivers.default]
host = "localhost"
port = 6379
password = ""
database = 1
timeout = 2.5
optPrefix = "cache_"

缓存使用

获取缓存实例

php
use Core\App;

// 获取默认缓存(从配置文件读取类型)
$cache = App::cache();

// 获取指定类型的缓存
$fileCache = App::cache('file');
$redisCache = App::cache('redis');

基本操作

设置缓存

php
$cache = App::cache();

// 设置缓存,默认生存时间
$cache->set('user:123', $userData);

// 设置缓存,指定生存时间(秒)
$cache->set('user:123', $userData, 3600); // 1小时

// 永久缓存
$cache->set('config:site', $siteConfig, 0);

获取缓存

php
// 获取缓存
$userData = $cache->get('user:123');

// 获取缓存,设置默认值
$userData = $cache->get('user:123', []);

// 检查缓存是否存在
if ($cache->has('user:123')) {
    $userData = $cache->get('user:123');
}

删除缓存

php
// 删除单个缓存
$cache->delete('user:123');

// 清空所有缓存
$cache->clear();

批量操作

php
// 批量获取
$keys = ['user:123', 'user:456', 'user:789'];
$users = $cache->getMultiple($keys);

// 批量设置
$values = [
    'user:123' => $userData1,
    'user:456' => $userData2
];
$cache->setMultiple($values, 3600);

// 批量删除
$cache->deleteMultiple(['user:123', 'user:456']);

缓存实践

应用缓存示例

用户数据缓存

php
<?php

namespace App\System\Service;

use Core\App;
use App\System\Models\SystemUser;

class UserCacheService
{
    private $cache;

    public function __construct()
    {
        $this->cache = App::cache();
    }

    public function getUserById(int $id): ?array
    {
        $key = "user:{$id}";
        
        // 尝试从缓存获取
        $user = $this->cache->get($key);
        
        if ($user === null) {
            // 缓存未命中,从数据库获取
            $userModel = SystemUser::find($id);
            
            if ($userModel) {
                $user = $userModel->toArray();
                // 缓存 2 小时
                $this->cache->set($key, $user, 7200);
            }
        }
        
        return $user;
    }

    public function updateUser(int $id, array $data): bool
    {
        // 更新数据库
        $result = SystemUser::where('id', $id)->update($data);
        
        if ($result) {
            // 删除缓存,下次访问时重新缓存
            $this->cache->delete("user:{$id}");
        }
        
        return $result;
    }
}

配置数据缓存

php
<?php

namespace App\System\Service;

use Core\App;
use App\System\Models\Config;

class ConfigCacheService
{
    private $cache;

    public function __construct()
    {
        $this->cache = App::cache();
    }

    public function getConfig(string $key, $default = null)
    {
        $cacheKey = "config:{$key}";
        
        $value = $this->cache->get($cacheKey);
        
        if ($value === null) {
            $config = Config::where('key', $key)->first();
            $value = $config ? $config->value : $default;
            
            // 配置缓存 24 小时
            $this->cache->set($cacheKey, $value, 86400);
        }
        
        return $value;
    }

    public function setConfig(string $key, $value): bool
    {
        // 更新数据库
        $result = Config::updateOrCreate(
            ['key' => $key],
            ['value' => $value]
        );
        
        if ($result) {
            // 更新缓存
            $this->cache->set("config:{$key}", $value, 86400);
        }
        
        return (bool)$result;
    }

    public function clearConfigCache(): void
    {
        // 这里需要实现清除所有配置缓存的逻辑
        // 简单方式是清除全部缓存
        $this->cache->clear();
    }
}

缓存键命名规范

建议使用统一的命名规范:

php
class CacheKeys
{
    // 用户相关
    public const USER_INFO = 'user:%d';                    // user:123
    public const USER_PERMISSIONS = 'user:%d:permissions'; // user:123:permissions
    public const USER_MENU = 'user:%d:menu';              // user:123:menu
    
    // 角色相关
    public const ROLE_INFO = 'role:%d';                    // role:1
    public const ROLE_PERMISSIONS = 'role:%d:permissions'; // role:1:permissions
    
    // 配置相关
    public const CONFIG = 'config:%s';                     // config:site_name
    public const MENU_TREE = 'menu:tree';                  // 菜单树
    
    // 统计相关
    public const STATS_USERS = 'stats:users';              // 用户统计
    public const STATS_TODAY = 'stats:today';              // 今日统计

    public static function userInfo(int $id): string
    {
        return sprintf(self::USER_INFO, $id);
    }

    public static function userPermissions(int $id): string
    {
        return sprintf(self::USER_PERMISSIONS, $id);
    }

    public static function config(string $key): string
    {
        return sprintf(self::CONFIG, $key);
    }
}

缓存生存时间策略

php
class CacheTTL
{
    // 时间常量(秒)
    public const MINUTE = 60;
    public const HOUR = 3600;
    public const DAY = 86400;
    public const WEEK = 604800;

    // 业务缓存时间
    public const USER_INFO = self::HOUR * 2;        // 用户信息:2小时
    public const USER_PERMISSIONS = self::HOUR * 6; // 用户权限:6小时
    public const CONFIG_DATA = self::DAY;            // 配置数据:1天
    public const MENU_DATA = self::DAY;              // 菜单数据:1天
    public const STATS_DATA = self::HOUR;            // 统计数据:1小时
    public const SESSION_DATA = self::MINUTE * 30;   // 会话数据:30分钟
}

缓存管理命令

虽然框架没有内置缓存管理命令,但可以通过 app:cache 命令清理应用缓存:

bash
# 清理应用缓存
php dux app:cache

自定义缓存管理

可以在控制器中实现缓存管理功能:

php
<?php

namespace App\System\Admin;

use Core\App;
use Core\Resources\Attribute\Resource;
use Core\Resources\Attribute\Action;

#[Resource(app: 'admin', route: '/cache', name: 'cache')]
class CacheController
{
    #[Action(methods: 'DELETE', route: '/clear')]
    public function clear(): array
    {
        $cache = App::cache();
        $cache->clear();
        
        return [
            'message' => '缓存已清理'
        ];
    }

    #[Action(methods: 'GET', route: '/info')]
    public function info(): array
    {
        $config = App::config('use');
        $cacheType = $config->get('cache.type', 'file');
        
        $info = [
            'type' => $cacheType,
            'prefix' => $config->get('cache.prefix', ''),
            'defaultLifetime' => $config->get('cache.defaultLifetime', 3600)
        ];
        
        if ($cacheType === 'file') {
            $cacheDir = base_path('data/cache');
            $info['directory'] = $cacheDir;
            $info['writable'] = is_writable($cacheDir);
        }
        
        return $info;
    }
}

性能优化

缓存预热

在系统启动或定期任务中预热重要缓存:

php
class CacheWarmer
{
    private $cache;

    public function __construct()
    {
        $this->cache = App::cache();
    }

    public function warmUp(): void
    {
        // 预热系统配置
        $this->warmUpConfigs();
        
        // 预热菜单数据
        $this->warmUpMenus();
        
        // 预热活跃用户数据
        $this->warmUpActiveUsers();
    }

    private function warmUpConfigs(): void
    {
        $configs = Config::all();
        foreach ($configs as $config) {
            $key = CacheKeys::config($config->key);
            $this->cache->set($key, $config->value, CacheTTL::CONFIG_DATA);
        }
    }

    private function warmUpMenus(): void
    {
        $menus = Menu::with('children')->where('parent_id', 0)->get();
        $this->cache->set(CacheKeys::MENU_TREE, $menus->toArray(), CacheTTL::MENU_DATA);
    }

    private function warmUpActiveUsers(): void
    {
        $activeUsers = SystemUser::where('status', 1)
            ->where('last_login_at', '>=', now()->subDays(7))
            ->limit(100)
            ->get();

        foreach ($activeUsers as $user) {
            $key = CacheKeys::userInfo($user->id);
            $this->cache->set($key, $user->toArray(), CacheTTL::USER_INFO);
        }
    }
}

缓存穿透防护

php
class CacheGuard
{
    private $cache;

    public function __construct()
    {
        $this->cache = App::cache();
    }

    public function remember(string $key, callable $callback, int $ttl = 3600)
    {
        $value = $this->cache->get($key);
        
        if ($value === null) {
            $value = $callback();
            
            if ($value !== null) {
                $this->cache->set($key, $value, $ttl);
            } else {
                // 缓存空值,防止缓存穿透
                $this->cache->set($key . ':null', true, 300); // 5分钟
            }
        }
        
        return $value;
    }

    public function has(string $key): bool
    {
        return $this->cache->has($key) || $this->cache->has($key . ':null');
    }
}

常见问题

1. 文件缓存权限问题

bash
# 检查缓存目录权限
ls -la data/cache/

# 设置正确权限
chmod -R 755 data/cache/
chown -R www-data:www-data data/cache/

2. Redis 连接问题

bash
# 检查 Redis 服务状态
redis-cli ping

# 检查配置文件
cat config/database.toml | grep -A 10 "\[redis"

3. 缓存不生效

php
// 测试缓存功能
$cache = App::cache();
$cache->set('test_key', 'test_value', 60);
$value = $cache->get('test_key');
echo $value; // 应该输出 'test_value'

4. 内存使用过高

  • 检查缓存键命名是否合理
  • 避免缓存大对象
  • 设置合适的过期时间
  • 定期清理过期缓存

通过合理配置和使用缓存系统,可以显著提升应用性能和响应速度。