使用 silber/bouncer-rc5 从 laravel 5.7 更新到 laravel 5.8 后检查权限时明显增加了时间

Noticeable time increase when checking permissions after updating from laravel 5.7 to laravel 5.8 using silber/bouncer-rc5

我正在使用 bouncer 来满足我的 ACL 需求,自从将我的项目从 laravel 5.7 升级到 5.8 后,我注意到处理请求所需的时间显着增加。

我正在处理两个模型(我们称它们为 ParentChild),以及经过身份验证的用户对它们的权限。

// Takes about 110ms. Eager loads various nested relationships and counters with specific constraints
$parents = Parent::myScope(...)->get();

// Bottleneck. Takes 5 minutes (!). Used to take about 40 seconds on laravel 5.7
$parents->each(function ($parent) {
    $parent->permissions = [
        'edit' => auth()->user()->can('edit', $parent),
        'delete' => auth()->user()->can('delete', $parent),
        'restore' => auth()->user()->can('restore', $parent)
    ];
    $parent->children()->each(function ($child) {
        $child->permissions = [
            'edit' => auth()->user()->can('edit', $child),
            'delete' => auth()->user()->can('delete', $child),
            'restore' => auth()->user()->can('restore', $child)
        ];
    }
}

我像这样附加权限,因为 $parents 变量将作为 json 发送到前端。我很确定这个实现是错误的,并且必须有更好的选择,但真正的问题是加载时间莫名其妙地增加了五倍。

时间是使用 Debugbar 措施获得的。

使用 redis-cli 中的 monitor 命令(我使用 Redis 来缓存权限),我注意到 GET 请求比以前更慢。事实上,即使我停止加载页面 (ESC),对 Redis 的 GET 请求也不会立即停止。我不确定这是否是正常行为。

我试图检查 bouncer 回购中的问题,但我没有找到任何东西。

您给 auth()->user() 打了数百次电话。你能试试只调用一次吗?

$user = auth()->user();

$parents->each(function ($parent) use ($user) {
    $parent->permissions = [
        'edit' => $user->can('edit', $parent),
        'delete' => $user->can('delete', $parent),
        'restore' => $user->can('restore', $parent)
    ];

    $parent->children()->each(function ($child) {
        $child->permissions = [
            'edit' => $user->can('edit', $child),
            'delete' => $user->can('delete', $child),
            'restore' => $user->can('restore', $child)
        ];
    }
}

此外,由于您正在急切加载 children,因此您不应在每次循环迭代中再次获取它们:

$parent->children()->each(function ($child) {
//               ^^ remove these parentheses
    $child->permissions = [
        'edit' => $user->can('edit', $child),
        'delete' => $user->can('delete', $child),
        'restore' => $user->can('restore', $child)
    ];
}

经过一些测试,找到了解决方案。事实证明,代码完全没有问题。

服务器出了点问题。我们不知道究竟是什么,但试图 运行 新安装的机器上的项目摆脱了那些可怕的处理时间。 (现在第一次请求时间为 15 秒)

从 laravel 5.7 迁移到 5.8 后,服务器的问题巧合地变得更糟,这让我无所事事。

附录

罪魁祸首是 Xdebug。我们用它来进行代码覆盖率分析,但性能太差了,我们最终改用了 phpdbg。