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

Laravel 8 基于文件缓存的高并发请求计数无丢失存储方案咨询

Laravel文件缓存高并发请求计数丢失解决方案

问题根因

计数丢失问题核心来自两个层面:

  1. 竞态条件:Laravel文件缓存的读写操作是非原子性的,高并发下多个请求同时执行「读缓存-改数值-写回缓存」的流程时,多个请求会读到相同的旧值,各自修改后写回的结果会互相覆盖,最终导致计数丢失。
  2. 现有实现缺陷:
    • 用数组存储计数完全冗余,额外增加了序列化/反序列化、计数统计的性能开销
    • 定时任务全量执行Cache::flush()会误删同步过程中新写入的缓存数据
    • 数据库操作直接拼接SQL存在注入风险,且先查后改的非原子操作也可能导致数据库计数丢失

不更换缓存驱动的优化方案

如果暂时无法更换文件缓存驱动,可以通过加锁、优化逻辑解决计数丢失问题:

1. 计数逻辑改造

使用Laravel自带的缓存锁保证同一时间只有一个请求修改对应计数,同时将数组存储改为直接存储整数计数:

$countKey = $key.'Count';
// 给对应计数key加独占锁,锁超时时间设为5秒避免死锁
$lock = Cache::lock($countKey.'_lock', 5);

if ($lock->get()) {
    $currentCount = Cache::get($countKey, 0);
    Cache::put($countKey, $currentCount + 1, env('CACHE_TIMER_IN_SECONDS', 300));
    $lock->release();
}

2. 定时任务逻辑改造

删除全量缓存清空逻辑,改用原子性的数据库增量更新,仅删除已同步完成的缓存key:

$schedule->call(function () {
    $clients = Cache::get('consumed_clients', []);
    if (empty($clients[0])) {
        return;
    }
    foreach ($clients[0] as $clientKey) {
        $clientObj = Cache::get($clientKey);
        if (empty($clientObj[0])) {
            continue;
        }
        $countKey = $clientObj[0]->risk_api_key.'Count';
        $lock = Cache::lock($countKey.'_lock', 10);
        if ($lock->get()) {
            $cacheCount = Cache::get($countKey, 0);
            if ($cacheCount > 0) {
                // 直接用数据库原子增量更新,省去查询步骤也避免计数冲突
                DB::table('clients')
                    ->where('key', $clientObj[0]->key)
                    ->increment('num_of_consumed_requests', $cacheCount);
                // 仅删除已同步的计数key
                Cache::forget($countKey);
            }
            $lock->release();
        }
    }
    // 仅清空已处理的客户端列表,不清空全量缓存
    Cache::forget('consumed_clients');
})->everyTwoMinutes();

更优方案:更换Redis缓存驱动

文件缓存本身不适用于高并发计数场景,更换为Redis驱动可以从根本上解决竞态问题,性能提升可达数十倍:
Laravel原生支持Redis的原子递增操作,无需手动加锁,计数逻辑一行代码即可完成:

// increment是原子操作,高并发下不会出现计数覆盖
Cache::increment($key.'Count', 1, env('CACHE_TIMER_IN_SECONDS', 300));

定时任务逻辑可以直接沿用上面改造后的代码,无需额外加锁也能保证计数准确,可轻松应对数千QPS的请求量。

注意事项

  • 若坚持使用文件缓存,需确保缓存目录挂载在SSD磁盘上,避免IO瓶颈导致锁超时、计数丢失
  • 可根据业务情况适当调高定时任务执行频率(比如1分钟一次),减少单次同步的数据量,降低风险
  • 禁止全量执行Cache::flush(),避免误删未同步的缓存数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:54:04