php - Laravel 缓存返回损坏的数据(redis 驱动程序)

标签 php laravel caching redis

我有一个用 Laravel 编写的 API。里面有如下代码:

public function getData($cacheKey)
{
    if(Cache::has($cacheKey)) {
        return Cache::get($cacheKey);
    }

    // if cache is empty for the key, get data from external service
    $dataFromService = $this->makeRequest($cacheKey);
    $dataMapped = array_map([$this->transformer, 'transformData'], $dataFromService);

    Cache::put($cacheKey, $dataMapped);

    return $dataMapped;
}

在 getData() 中,如果缓存包含必要的键,则从缓存返回数据。 如果缓存没有必要的键,则从外部 API 获取数据,处理并放入缓存,然后返回。

问题是:当对该方法有很多并发请求时,数据会损坏。我想,由于竞争条件,数据被错误地写入缓存。

最佳答案

您似乎遇到了某种临界区问题。但事情是这样的。 Redis 操作是原子操作,但 Laravel 在调用 Redis 之前会自行检查。

这里的主要问题是,所有的并发请求都会引起一个请求,然后所有的请求都会把结果写入缓存(这肯定不好)。我建议对您的代码实现一个简单的互斥锁。

用以下内容替换您当前的方法体:

public function getData($cacheKey)
{
    $mutexKey = "getDataMutex";
    if (!Redis::setnx($mutexKey,true)) {
       //Already running, you can either do a busy wait until the cache key is ready or fail this request and assume that another one will succeed 
       //Definately don't trust what the cache says at this point
    }

    $value = Cache::rememberForever($cacheKey, function () { //This part is just the convinience method, it doesn't change anything
        $dataFromService = $this->makeRequest($cacheKey); 
        $dataMapped = array_map([$this->transformer, 'transformData'], $dataFromService);

        return $dataMapped;
    });
    Redis::del($mutexKey);
    return $value;
}

setnx是一个 native redis 命令,如果它不存在则设置一个值。这是以原子方式完成的,因此它可用于实现简单的锁定机制,但是(如手册中所述)如果您使用的是 redis 集群,则将不起作用。在那种情况下,redis 手册描述了 a method to implement distributed locks

关于php - Laravel 缓存返回损坏的数据(redis 驱动程序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46128080/

相关文章:

php - 将时间传输到 mySQL 数据库(定义为 "Thu, 14 Apr 2011 22:44:33 +0000")给我语法错误

php - Laravel 5.4 搜索邮政区通配符

php - 检查行是否存在,Laravel

php - MethodNotAllowedHttpException laravel-4

php - 使用 mySQL 在 PHP 中上传图像

php - 使用php将csv文件导入数据库

android无法从缓存目录打开pdf

android - GreenDao queryBuilder().list() 返回删除的实体

php - 如何获取每个类别的最新文章日期

c# - WCF:如何在客户端缓存来自 OData 的集合