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

Laravel 10 Redis标签缓存并发刷新异常问题求助

问题:Laravel 10标签缓存高并发下数据不一致及标签损坏问题

我开发了一个Laravel 10应用,支持候选人投票并展示按票数排序的候选人列表。该列表从数据库获取计算后,以标签形式存入Redis缓存(实际含多个标签,但单个标签也存在问题)。用户投票后会刷新该标签下的所有缓存数据,后续列表请求会重新从数据库拉取数据并写入带标签的Redis缓存。低流量时一切正常:缓存能正确刷新,用户看到最新数据;无投票时从缓存读取提升性能。

Laravel标签缓存的Redis存储机制

Laravel 10处理标签缓存的代码如下:

Cache::tags(['object-1'])->put('cand-votes', $votes, $TTL);

执行后会在Redis中生成两个键:

  • prefix:tag:tagName:entries:存储该标签下所有缓存键的信息,用于刷新整个标签时定位需清除的键
  • prefix:uniqid:cacheKey:存储实际缓存数据

低流量正常状态

Redis键列表:

keys app_cache*
1) "app_cache:tag:object-1:entries"
2) "app_cache:6461bc79646c190a1c986d8ca1ab917e8ddf0d8f:cand-votes"

app_cache:tag:object-1:entries的内容:

zscan app_cache:tag:object-1:entries 0
1) "0"
2) 1) "6461bc79646c190a1c986d8ca1ab917e8ddf0d8f:cand-votes"
   2) "1689766717"

此时能明确标签下的缓存键及其TTL,读取数据正常:

get app_cache:6461bc79646c190a1c986d8ca1ab917e8ddf0d8f:cand-votes
"150"

高流量异常表现

当并发量达到约15次投票/秒(即15次Redis刷新请求/秒)时出现问题:Redis中的标签损坏,无法通过标签刷新清除数据,只能用artisan cache:clear清空整个缓存。

8秒内15位用户投票150次后的异常状态:
Redis键列表仅剩数据键:

keys app_cache*
1) "app_cache:6461bc79646c190a1c986d8ca1ab917e8ddf0d8f:cand-votes"

读取该键得到旧数据:

get app_cache:6461bc79646c190a1c986d8ca1ab917e8ddf0d8f:cand-votes
"38"

此时仅存存储数据的缓存键(已过期),存储缓存键列表的entries键丢失。

应用内调用:

Cache::tags(['object-1'])->get('cand-votes');

始终返回错误数据;调用:

Cache::tags(['object-1'])->flush();

无法清除该键(因entries键丢失),导致旧数据在TTL周期内无法清除,仅能通过artisan cache:clear解决。

推测是缓存写入操作重建了刚被删除的键,但entries键随即被删除。

已尝试方案

  • 为投票流程添加缓存锁:略有改善但会导致请求等待变慢甚至失败
  • 为缓存标签刷新操作添加Redis事务:无明显效果

临时Workaround

  • 高负载时禁用缓存,实时刷新数据
  • 将缓存刷新和预热操作移入队列,降低并发

但这些方案都不够理想,属于临时措施。请问有使用标签缓存遇到类似问题的吗?寻求处理缓存并发刷新场景的解决方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:52:45