Заметное увеличение времени при проверке разрешений после обновления с laravel 5.7 до laravel 5.8 с использованием silber/bouncer-rc5

Я использую bouncer для своих нужд ACL и с тех пор, как обновил свой проект с laravel 5.7 до 5.8, я заметил значительное увеличение времени обработки моих запросов.

Я имею дело с двумя моделями (назовем их Parent и Child), а также с разрешениями, которые имеет над ними аутентифицированный пользователь.

// 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 мер.

Используя команду monitor в redis-cli (я использую Redis для кэширования разрешений), я заметил, что запросы GET приходят медленнее, чем раньше. На самом деле, даже после того, как я остановил загрузку страницы (ESC), запросы GET к Redis не прекращаются немедленно. Я не уверен, нормальное ли это поведение или нет.

Я пытался проверить проблемы в репозитории вышибалы, но ничего не нашел.


person IGP    schedule 24.04.2019    source источник
comment
Настроен ли Bouncer на кэшировать свои запросы?   -  person Joseph Silber    schedule 25.04.2019
comment
Да, он кэшируется в AppServiceProvider, поэтому 2 SQL-запроса, которые выполняет Bouncer, не повторяются при каждом запросе. Однако время, которое они занимают, незначительно.   -  person IGP    schedule 25.04.2019


Ответы (2)


Вы звоните 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)
    ];
}
person Joseph Silber    schedule 25.04.2019
comment
Спасибо за внимание. После вашего совета время обработки сократилось на 2 минуты, но в целом это все еще занимает 3 минуты. Даже с помощью tinker проверка простого разрешения занимает около полсекунды. Я вернусь к laravel 5.7 в другой ветке и сообщу о результатах. - person IGP; 25.04.2019

После некоторого тестирования решение было найдено. Оказывается, с кодом вообще не было проблем.

Что-то не так с сервером. Мы не знаем точно, что именно, но попытка запустить проект на свежеустановленных машинах избавила от этих ужасных времен обработки. (Сейчас время составляет 15 секунд по первому запросу)

Проблема с сервером случайно ухудшилась после перехода с laravel 5.7 на 5.8, что привело меня к этой погоне за дикими гусями.

ДОПОЛНЕНИЕ

Виновником был Xdebug. Мы использовали его для анализа покрытия кода, но производительность была настолько низкой, что в итоге мы переключились на phpdbg.

person IGP    schedule 25.04.2019