You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel缓存优化:保留旧缓存直至新缓存生成的实现方案

Laravel 文件缓存实现新旧缓存无缝切换的方案

一、原生推荐方案:版本化缓存键

不用清理整个缓存池,给目标缓存键加上版本标识,生成新缓存时使用新版本键,完成后再切换当前生效的版本号,全程保留旧缓存直到新缓存完全就绪。

代码示例

生成新缓存

// 生成唯一版本号(用时间戳或自增ID都可以)
$newVersion = time();
// 将新数据存入带版本号的缓存键
Cache::forever(static::DATA_STRUCTURE . '_v' . $newVersion, json_encode($tree));
// 更新当前生效的版本号
Cache::forever('DATA_STRUCTURE_CURRENT_VERSION', $newVersion);

// 可选:异步清理旧版本缓存(避免阻塞主流程)
$oldVersion = Cache::get('DATA_STRUCTURE_CURRENT_VERSION', null);
if ($oldVersion && $oldVersion !== $newVersion) {
    Cache::forget(static::DATA_STRUCTURE . '_v' . $oldVersion);
}

读取缓存

// 获取当前生效的版本号
$currentVersion = Cache::get('DATA_STRUCTURE_CURRENT_VERSION', 0);
$targetCacheKey = static::DATA_STRUCTURE . '_v' . $currentVersion;
$treeData = Cache::get($targetCacheKey);

// 兜底逻辑:如果缓存不存在(首次部署或版本切换异常),重新生成
if (!$treeData) {
    $tree = // 从数据库拉取数据结构的业务逻辑
    Cache::forever($targetCacheKey, json_encode($tree));
    Cache::forever('DATA_STRUCTURE_CURRENT_VERSION', $currentVersion);
}

这个方案完全基于Laravel原生Cache组件实现,无需修改缓存驱动,还能避免cache:clear清空所有缓存的副作用,只针对目标缓存做版本管理,逻辑简单可靠。

二、目录替换思路的优化实现

如果坚持用目录替换的方式,可以临时切换文件缓存的存储路径,生成新缓存后再替换原目录:

use Illuminate\Support\Facades\File;

// 临时指定新缓存目录
config(['cache.stores.file.path' => storage_path('framework/cache/data_new')]);
// 生成新缓存到临时目录
Cache::store('file')->forever(static::DATA_STRUCTURE, json_encode($tree));

// 替换旧缓存目录
$oldCachePath = storage_path('framework/cache/data');
$newCachePath = storage_path('framework/cache/data_new');

// 先删除旧目录,再重命名新目录(注意:替换瞬间可能有请求读不到缓存)
File::deleteDirectory($oldCachePath);
File::move($newCachePath, $oldCachePath);

注意事项

  • 替换目录的瞬间,若有请求正在读取缓存,可能出现短暂的缓存缺失
  • 需确保Laravel进程对缓存目录有读写权限
  • 该方案会影响所有文件缓存的键,不像版本化方案只针对目标缓存

三、耗时缓存的异步生成方案

如果缓存生成逻辑耗时较长,可以把生成逻辑放到Laravel队列中异步执行,后台完成后再切换版本,完全不阻塞前端请求:

// 触发异步缓存生成任务
GenerateDataStructureCache::dispatch();

// 队列任务类的handle方法
public function handle()
{
    $newVersion = time();
    $tree = // 从数据库拉取数据结构的业务逻辑
    Cache::forever(static::DATA_STRUCTURE . '_v' . $newVersion, json_encode($tree));
    
    // 先记录旧版本,再切换新版本
    $oldVersion = Cache::get('DATA_STRUCTURE_CURRENT_VERSION', null);
    Cache::forever('DATA_STRUCTURE_CURRENT_VERSION', $newVersion);
    
    // 延迟清理旧缓存,避免刚切换就有请求还在读旧缓存
    if ($oldVersion) {
        Cache::put('DATA_STRUCTURE_OLD_VERSION', $oldVersion, now()->addHour());
        // 可以再开一个延迟任务清理旧缓存
        CleanOldDataStructureCache::dispatch($oldVersion)->delay(now()->addHour());
    }
}

// 清理旧缓存的延迟任务
public function handle($oldVersion)
{
    Cache::forget(static::DATA_STRUCTURE . '_v' . $oldVersion);
    Cache::forget('DATA_STRUCTURE_OLD_VERSION');
}

内容的提问来源于stack exchange,提问作者Denissio Inkognito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:25:21