0

我将此代码放在一个Route::get()方法中只是为了更快地测试它。这就是它的外观:

use Illuminate\Support\Facades\Cache;

Route::get('/cache', function(){

  $lock = Cache::lock('test', 4);

  if($lock->get()){
    Cache::put('name', 'SomeName'.now());
    dump(Cache::get('name'));
    sleep(5);
    // dump('inside get');
  }else{
    dump('locked');
  }
  // $lock->release();
});

如果您(几乎)同时从两个浏览器到达这条路线。他们都会以dump(Cache::get('name'));. 第二个浏览器响应不应该被“锁定”吗?因为当它调用时$lock->get()应该返回false?那是因为当第二个浏览器试图到达这条路线时,锁应该仍然被设置。

如果执行之后的代码所需的时间$lock = Cache::lock('test', 4)小于 4,则相同的代码可以正常工作。如果您在 $sec<4 时设置 sleep($sec),您将看到到达此路由的第一个浏览器将响应第二个浏览器的结果Cache::get('name')将按预期响应“锁定”。

谁能解释为什么会这样?是不是假设该锁的任何get()方法(除了第一个方法)在设置锁的那段时间内返回 false 吗?我使用了 2 个不同的浏览器,但它也适用于来自同一浏览器的 2 个选项卡。

4

1 回答 1

0

引用 5.6 文档https://laravel.com/docs/5.6/cache#atomic-locks

要利用此功能,您的应用程序必须使用memcachedredis缓存驱动程序作为您的应用程序的默认缓存驱动程序。此外,所有服务器都必须与同一个中央缓存服务器进行通信。

引用 5.8 文档https://laravel.com/docs/5.8/cache#atomic-locks

要利用此功能,您的应用程序必须使用memcacheddynamodbredis缓存驱动程序作为您的应用程序的默认缓存驱动程序。此外,所有服务器都必须与同一个中央缓存服务器进行通信。

引用 8.0 文档https://laravel.com/docs/8.x/cache#atomic-locks

要利用此功能,您的应用程序必须使用memcachedredisdynamodbdatabasefilearray缓存驱动程序作为您的应用程序的默认缓存驱动程序。此外,所有服务器都必须与同一个中央缓存服务器进行通信。

显然,他们一直在添加对更多驱动程序的支持以利用此锁定功能。检查您正在使用的缓存驱动程序,以及它是否适合您的 Laravel 版本的支持列表。

这里可能存在原子性问题,您正在使用的缓存驱动程序无法以原子方式锁定文件。应该发生的是,当一个进程(即 php 请求)正在写入锁定文件时,所有其他需要锁定文件的进程至少应该等到该锁定文件可以再次读取。如果不是,他们会在锁定文件被写入之前读取它,这显然会导致竞争条件。

于 2022-01-14T13:25:47.430 回答