Миграция Laravel сессий из БД в Редис
Обычный, казалось бы, день начался с сообщений Датадога. Увеличилось среднее время ответа нашего приложения. Покопавшись логах я понял, что дело в базе и таблице сессий. Только когда нагрузка растет вспоминаешь, что работать с сессиями в базе плохая идея.
Мы не хотели терять активных пользователей и решили найти способ, как всё починить и оставить людей в их аккаунтах.
Готово решения я найти не смог. Штош, проблемы изобрели, теперь их стоит решить.
Собираем информацию
Покопавшись во внутренностях работы стандартного модуля сессии я нашел пару интересных штук.
Как закодированы сессии в базе и Редисе?
Когда из БД извлекаем сессию, делаем base64_decode
|
|
А когда из cache based — делаем unserialize
|
|
|
|
Как хранятся сессии в Редисе?
Теперь надо понять в каком виде сессии хранятся в Редисе. Пришлось локально поставить Редис как драйвер сессий. У каждой сессии свой ключ в формате laravel:%session_id%
. А то что значение этого ключа — сериализованный ПХП пэйлод, мы узнали чуть раньше при погружении в кишки Ларавела.
План вышел таким. Даже не знаю чего я ожидал :)
- Выделить под сессии базу в Редисе, чтобы изолировать данные
- Перенести сессии из БД в Редис с учетом кодирования
- Поменять драйвер
Реализуем миграцию
Выделяем под сессии базу в Редисе
Имя базы в Редисе — это целое число от 1 до 16. Я этого не знал и бахнул 99. Пришлось погуглить почему же оно не работает :)
|
|
Проверяем как надо менять драйвер и соединение.
|
|
Переносим сессии из БД в Редис
Команда по миграции вышла небольшой, но делает команда несколько вещей:
- Декодирует base64 сессии из БД
- Сериализует сессии стандартным ПХП serialize
- Формирует команды на добавления новых ключей в Редисе
В Редис команда не пишет, она читает из БД и выводит много SET-ов. Не забудь подрубить команду в консольном Кернеле.
|
|
Наконец-то мигрируем! Правда надо вспомнить номер базы, которую выделили в Редисе под сессии. В моём примере это 13.
Запускаем царскую команду и кайфуем:
$ php artisan sessions:migrate_database_to_redis | redis-cli -n 13 --pipe
Команда выводит SET-ы, мы их подсовываем Редису с выбранной правильной базой.
Меняем драйвер
Настраиваем переменные окружения и чистим кеш.
# .env
SESSION_DRIVER=redis
SESSION_CONNECTION=sessions
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
$ php artisan cache:clear
$ php artisan config:cache
Вместо итогов
Немного покопавшись во внутреннем устройстве Laravel мы не потеряли сессии миллионов пользователей и снизили нагрузку на базу данных.
Челлендж выполнен, команда спит спокойно, а пользователи продолжают пользоваться продуктом.
P.S. Свежие посты публикуются в телеграме. Если чувствуешь, что они полезны, то подпишись.