Еще немного про сессии MODX, компонент smartSessions

Всем привет!

Небольшая предыстория
Когда я на свой VPS сервер закинул очередной более-менее крупный сайт (в базе около 25 тыс. товаров), у меня начались проблемы с нехваткой памяти, mysql ее нещадно отъедал.

В процессе оптимизации я начал понимать, что у половины сайтов в базе большую часть объема занимает пресловутая таблица modx_sessions, где, как известно, лежат сессии посетителей.

Но… почему? У сайта посещаемость 150-200 человек в сутки, сессии хранятся 7 дней (да, я проверил, они действительно очищаются), но в таблице почему-то 200000 записей, хотя по логике вещей должно быть 200*7=1400+. Реальность расходится с теорией не на 5-10%, а в десятки раз!
В итоге таблица весит полгигабайта, сайтов штук 10, каждому дай памяти, вот VPS и падает периодически… непорядок!




Самый старый и известный материал на эту тему у нас здесь:
bezumkin.ru/sections/tips_and_tricks/2422/
Есть еще куча вопросов на этом сайте на предмет размера таблицы, да и вообще, все давно-давно терто-перетерто… вывод из всего — проверять, что сессии очищаются, уменьшать время хранения, но вот какая-то недосказанность все равно есть, что происходит понятно, а что с этим делать — не очень.

Нет, ну можно правда чистить таблицу с сессиями почаще, раз в 3 дня к примеру (настройка session_gc_maxlifetime), будет в целом терпимо. Но что делать, если я хочу, чтобы мой интернет-магазин хранил сессии месяц? Вот не хочу я пользователей заставлять постоянно вводить логин/пароль (или код из смс)!

И тут я наткнулся на статью lectoria.pro/read/sessii-v-php-i-modx-revolution.html и затем видео www.youtube.com/watch?v=GyzkQu_-vSI
Ба! Да все придумано уже, только вот реализации не нашел, готовый пакет почему-то так и не собран.

[smartSessions]
В общем собрал все в пакет, назвал smartSessions, вот иходники github.com/createit-ru/smartSessions

В чем суть работы:
— для сессий создана новая таблица modx_smart_sessions, которая повторяет родную modx_sessions, но добавлены колонки user_agent, ip, user_id
— написан свой обработчик сессий smartSessionHandler, который унаследован от родного modSessionHandler

Что сейчас может:
— можно отдельно установить время жизни сессий (настройка smartsessions_authorized_users_gc_maxlifetime ) для авторизованных пользователей.
— можно отдельно установить время жизни сессий (настройка smartsessions_bots_gc_maxlifetime) для различных ботов.
— в настройке smartsessions_bot_signatures можно указать перечень сигнатур этих самых ботов (будет произведен поиск LIKE по полю user_agent, например Googlebot|YandexBot|DotBot|bingbot|Mail.RU_Bot|PetalBot|MegaIndex.ru).

Как попробовать
— установите пакет из репозитория modstore;
— укажите в настройке session_handler_class значение smartSessionHandler;
— проверьте, что данные начали собираться в таблицу modx_smart_sessions. При этом таблицу modx_sessions можно очистить (не удалить, а очистить :)), она больше не нужна.

Благодаря расширенной таблице сессий я смог узнать кое-что новое о записях сессий.
Оказывается, что больше 95% записей в ней — это сессии различных ботов, и причем далеко не всегда это привычные Яндекс и Гугл, есть еще десятки других ботов, которые активно ходят по нашим сайтам.
Ситуация, когда в таблице 10000 записей сессий ботов и 200 записей реальных посетителей — обычная!

Например на своем сайте я настроил хранение сессий авторизованных пользователей 30 дней, неавторизованных 7 дней, а сессий ботов — 3 часа.
Результат — количество записей в таблице сессий снизилось в разы, нагрузка на mysql упала.

В качестве примера, выгрузка сессий, сгруппированных и отсортированных по user_agent за несколько часов.
SELECT `user_agent`, COUNT(*) 
FROM `modx_smart_sessions` 
GROUP BY `user_agent` 
ORDER BY `COUNT(*)` DESC

Выделил сессии ботов, как видно их подавляющее большинство:


Дополнение доступно в ModStore:
modstore.pro/packages/utilities/smartsessions
Наумов Алексей
28 июля 2021, 10:51
modx.pro
14
3 893
+29

Комментарии: 38

Sergey (Sentinel)
28 июля 2021, 10:59
+2
Спасибо Алексей!

или, может, я его когда-то опубликую, если будет интерес
интерес есть, было бы классно ;-)
Александр Мельник
28 июля 2021, 19:27
0
Ох уж эти сессии. Да, в modx хранение сессий в базе приводит к тому, что таблица с сессиями занимает огромное место. У меня есть посещаемый сайт и там только таблица с сессиями занимает 17 гигабайт.
Сейчас работаю над закрытым порталом для сотрудников одной крупной мировой компанией и тоже пришлось глубоко погрузится в мир сессий.
К моему счастью, раз в сутки в 3 часа ночи происходит полное обновление данных о сотрудниках и я могу просто запустить скрипт по удалению файлов сессии. Это позволяет разлогинить всех сотрудников, чтобы утром каждый вошел (если не уволен за ночь) с новыми правами и плюс, не заводить кучу файлов сессий. Раз в сутки все файлы просто удаляются.
    Роман
    29 июля 2021, 17:18
    +1
    Есть же возможность хранить сессии в файлах? Или это не правильно?
      Евгений Шеронов
      01 августа 2021, 13:00
      0
      Ещё правильнее хранить сессии в Redis.
      При правильных настройках — у активных пользователей сессия не будет слетать (так как часто запрашивается).
      А менее популярные сессии анонимов при большом размере кеша будут выталкиваться.

      Так и при установке MODX на два сервера и более репликация Redis позволит не слетать авторизациям между запросами на разные сервера (именно тут у сессий в БД и было преимущество над файлами, где тоже можно было настроить репликацию БД между серверами).

      Но я не знаю и не делал сайтов на MODX, работающих одновременно на двух серверах)
        Александр Мельник
        01 августа 2021, 14:14
        0
        Ещё правильнее хранить сессии в Redis.
        Ну тут Евгений, наверное стоит заметить, что сайты разрабатываемые на modx как правило размещаются на очень недорогих хостингаx, где нет возможности установить redis. Как это по русски — каждый сверчок знай свой шесток.
        При правильных настройках — у активных пользователей сессия не будет слетать (так как часто запрашивается).
        А менее популярные сессии анонимов при большом размере кеша будут выталкиваться.
        У вас нет ссылок на примеры реализации? Просто я буквально неделю назад углубленно вникал в работу redis и скажем так — не нашел redis очень удобным для хранения сессий. Применил redis для хранения временных токенов, для доступа у определенным ресурсам — вот тут прям идеально применение redis поскольку программа имеет возможность установки времени жизни записи и сама следит за ее удалением.
        Так и при установке MODX на два сервера и более
        неужели кто-то так делает? MODX это возможность за 6 дней сделать неплохо работающий сайт, лендинг, небольшой магазин без амбиций. Но распылять MODX на несколько серверов… Мне кажется это из области фантастики. Здесь на форуме собраны лучшие разработчики на MODX в России и бывших странах СССР — кто так делал?
          Евгений Шеронов
          02 августа 2021, 14:51
          1
          +2
          У вас нет ссылок на примеры реализации?
          Я делал. Для начала нужно установить на сервер github.com/phpredis/phpredis

          В MODX нужно всего лишь очистить системную настройку session_handler_class — в этом случае за сессии будет отвечать PHP и по умолчанию будет хранить их в файлах.

          Для хранения их в redis нужно в php.ini указать:
          session.save_handler = redis
          session.save_path = "tcp://host1:6379?weight=1, tcp://host2:6379?weight=2&timeout=2.5, tcp://host3:6379?weight=2&read_timeout=2.5"
          ; а для тех кто, как и я предпочитает подключение по сокету в пределах одной машины: 
          session.save_path = "unix:///var/run/redis/redis.sock?persistent=1&weight=1&database=0"
          ; но в этом случае нужно ещё в redis.conf указать этот же путь в unixcocket

          И теперь уже PHP будет отвечать за хранение сессий в redis.
          Более подробнее уже несложно нагуглить)
            Александр Мельник
            02 августа 2021, 16:30
            0
            Да спасибо Евгений, примерно по такому пути и я смотрел.
            Правда не стал использовать phpredis а взял вот эту программу cheprasov/php-redis-client
            Но дело ведь в том, что редис сам по себе не гарантирует сохранность данных.
            Если мы храним сессии в файлах, то они там и остаются. Храним сессии в базе — они там и остаются. А редис это все таки хранилище которое живет в оперативной памяти и при выключении питания на сервере к примеру — все будет потеряно. Да редис умеет периодически сбрасывать данные на жесткий диск, но все это не гарантируется разработчиком.
              Евгений Шеронов
              03 августа 2021, 19:35
              +1
              Если мы храним сессии в файлах, то они там и остаются. Храним сессии в базе — они там и остаются.
              А если жёсткий диск полетит?)

              все будет потеряно
              А в сессии ничего важного и не должно быть. Максимальные потери здесь — содержимое корзины да и выход из аккаунта. А если настроить сохранение на диск, то и потеряется только сессионные данные за последние n секунд)
                Иван Климчук
                04 августа 2021, 16:21
                +1
                У Redis есть режим персистентности, так что данные не будут потеряны. У нас в огромном проекте (не MODX) редис активно используется именно для сессий, потому что по другому не получается. К тому же кластер редиса хорошо масштабируется и позволяет запускать по 10 и более инстансов приложения, при этом пользователь не теряет своей сессии, даже если балансировщик подсунул ему другую машину.
                  Александр Мельник
                  04 августа 2021, 19:55
                  0
                  Уверен вы правы. Просто я еще не дорос до проектов, у которых есть балансировщики нагрузки и сопутствующие им проблемы.
                    Иван Климчук
                    04 августа 2021, 21:51
                    +2
                    Вопрос не в дорос или нет, просто увидел в посте заблуждение, которое стало личным убеждением, и постарался его развеять.
                      Александр Мельник
                      05 августа 2021, 11:31
                      0
                      я имел ввиду, что выбор инструмента для решения задачи исходит из самой задачи. Возможно для таких систем как ваша, где запрос пользователя случайным образом отправляется на разные сервера, то выбор redis является правильным и удобным инструментом. Хотя не совсем понимаю, как это устроено. Редис работает одновременно на всех серверах и везде данные синхронизированы?
                        Иван Климчук
                        05 августа 2021, 13:48
                        0
                        редис работает как единый сервис в amazon, а уже отдельные серверы с приложением к нему подключаются. Т.е. там одна общая база для всех.
    Сергей Шлоков
    30 июля 2021, 07:33
    +5
    Выступлю в роли Николая Ланца… Идея отличная!!! Но к реализации очень много вопросов.
    — для сессий создана новая таблица modx_smart_sessions, которая повторяет родную modx_sessions
    Зачем? Теперь лишняя таблица в базе болтается. Для таких целей используют миграции. В MODX их нет, но можно расширить схему.

    Писать в базу нефильтрованный USER_AGENT — это чтобы пощекотать себе нервы?

    Ну и про наследование в ООП советовал бы почитать.

    Режим «Николай Ланец» OFF. ))
      Наумов Алексей
      30 июля 2021, 09:20
      +2
      Так у меня и только beta версия только выпущена)))
      Но за здравую критику — спасибо
      Иван
      30 июля 2021, 12:44
      0
      Вообще хорошо бы понимать, что сессии должны создаваться только для авторизованных пользователей. Вряд ли все эти посетители, которые заходят на ваш сайт, регистрируются и авторизуются. Более разумно просто отказаться от использования таких дополнений как AjaxForm, который для каждого посетителя создает сессию. Тогда таблица вообще не будет пухнуть.
        Иван
        30 июля 2021, 13:10
        0
        Дополнение. Прочитал по ссылке и ужаснулся:
        При посещении какой-либо веб-страницы сайта, созданного на PHP, создается сессия.
        Видимо автор этого текста изучает PHP только в совокупности с MODX (и AjaxForm).

        В сессии хранятся данные, которые присущи только вашему визиту. Например, корзина товаров, информация о том, авторизовались ли вы для входа в личный кабинет и так далее.
        А если я не авторизовался и ничего не положил в корзину, то и сессия мне не нужна. На нормальных сайтах именно так и происходит.
          Наумов Алексей
          30 июля 2021, 14:38
          0
          Что значит только для авторизованных?..
          А корзина товаров? А если я товар «отложил», а если я перешел по реферальной ссылке на сайт, а если у нас правда что-то работает через ajax?
          Правильнее бы конечно создавать сессии когда они действительно нужны. Но MODX работает на своей волне, а кажется именно его мы здесь и обсуждаем.

          Более разумно просто отказаться от использования таких дополнений как AjaxForm, который для каждого посетителя создает сессию.

          Давайте делать статичные странички на html!
            Иван
            30 июля 2021, 15:59
            0
            А корзина товаров? А если я товар «отложил»...
            Про это я уже написал. Зачем повторяться? Какой процент всех посетителей использует корзину товаров? Я думаю меньше 50%.

            а если у нас правда что-то работает через ajax?
            Для аякса необходимы сессии? Это что-то новенькое)

            Правильнее бы конечно создавать сессии когда они действительно нужны. Но MODX работает на своей волне
            Не MODX, а указанное дополнение.

            Давайте делать статичные странички на html!
            Ну да, переписать дополнение или использовать другое не нужно. А нужно к этому дополнению городить кучу костылей))
              Иван
              30 июля 2021, 17:03
              0
              Уточню что я имею ввиду. Да, в MODX есть особенность, что если отключить «anonymous_sessions», то сессии будут работать только у авторизованных пользователей. В некоторых случаях это подходит (заставлять авторизовываться). Но важен также размер хранящейся информации в таблице сессии. Его нужно свести к минимуму + уменьшить время жизни сессии до суток (или даже 12 часов). Этого вполне достаточно для большинства сайтов. Но по-хорошему эту особенность с «anonymous_sessions» нужно исправить. Сессии должны создаваться только тогда, когда они нужны.
                Наумов Алексей
                02 августа 2021, 07:46
                0
                Так вот компонент и решает задачу:
                1. отдельно управлять временем жизни сессий для авторизованных пользователей (например, поставить им месяц);
                2. отдельно управлять временем жизни сессий ботов (к примеру, поставить им 3 часа);
                3. У всех остальных — ну пусть будет стандартная неделя.

                И на моих сайтах, за счет п.2. размер таблицы и объем данных уменьшился в десятки раз, т.к. именно сессии различных ботов составляли 90% записей в таблице.
                Дима Сайт old см. профиль
                01 августа 2021, 16:12
                0
                Ну да, переписать дополнение или использовать другое не нужно. А нужно к этому дополнению городить кучу костылей))
                @Иван хоть вы на первый взгляд и детально объяснили что там как должно быть на нормальных по вашему мнению сайтах, все же не понятно какую проблему вы видите в дополнении? Какие необходимые к нему костыли вы имеете в виду?

                Во времена повсеместного бума интернет-приватности и частичного отказа от cookies я вот хочу перенести в сессии некоторые настройки персонализации для незарегистрированных посетителей сайта (например открыто или закрыто боковое меню) и вообще сводить к минимуму использование cookies там где возможно.

                Короче, ИМХО тренд сейчас в сторону увеличения времени жизни сессий, а не уменьшению.

                Поэтому, если не «плакаться» что «anonymous_sessions» работает не так как хочется, а так, как решил мейнтейнер (хотя может и открыть ещё один issue для обсуждения?), то проблему с растущей базой надо как-то решать всё равно, а идея проверять user-agent и через него фильтровать сессии ботов это же прям похоже на решение!
                  Иван
                  03 августа 2021, 14:56
                  0
                  Я писал про дополнение «AjaxForm» (может ещё какое-то есть), которое очень популярно. Этот сниппет для каждого посетителя сайта (в т.ч. для ботов) создает записи в сессии, где хранит параметры сниппетов. Представляете какой это объём информации для сайта с хорошей посещаемостью? Сталкивался с сайтами, где на одну страницу минимум 5 раз используется AjaxForm.
                  Во времена повсеместного бума интернет-приватности и частичного отказа от cookies я вот хочу перенести в сессии некоторые настройки персонализации для незарегистрированных посетителей сайта (например открыто или закрыто боковое меню) и вообще сводить к минимуму использование cookies там где возможно.
                  К Вашему сведению, сессия работает через куку, где хранится её ID. Так что переводить на сессию в Вашем случае смысла нет. Лучше используйте в JS LocalStorage или SessionStorage. Технологии нужно использовать по их назначению, тогда и проблем не будет.
            Бывает же такое, как раз ищу инфу по уменьшению размер таблицы с сессиями (на одном проекте 3.2гб уже), нахожу массу вариантов из поиска, включая статью про сессии на bezumkin.ru (кстати она от 2014 г и спустя 7 лет, в ubuntu значение session.gc_probability и сейчас по-умолчанию = 0 ).

            Ну подправил настройки PHP и довольный по привычке перехожу на главную modx.pro глянуть как дела и вижу тут большой новый пост про сессии (0_о)… уже заподозрил что рекламные-таргет-технологии добрались до портала и подкладывают рекомендации на основе истории поиска :)

            Оказалось, совпадение…

            P.S. Автору большое спасибо! Конечно, готовые решения намного лучше когда в пакетах!
              Семён Кудрявцев
              03 августа 2021, 15:08
              0
              Потестил компонент, не работает функционал «Завершить все сеансы» — может быть имело смысл не создавать свою таблицу, а расширить существующую и тогда бы это работало. В итоге получаем ошибку —
              А так затея интересная, автору респект.
                Наумов Алексей
                03 августа 2021, 15:10
                0
                Точно, будем фиксить в следующих версиях)
                  Наумов Алексей
                  03 августа 2021, 15:49
                  0
                  Просто не выйдет…
                  MODX не умеет очищать сессии, если используется иной, отличный от modSessionHandler класс.

                  В процессоре проверяется настройка session_handler_class, и если там указано что-то не стандартное — сразу ошибка.

                  Как вариант — сделать свой пункт в меню для очистки сессий, а стандартный скрыть… ну и тогда нужно дописать процессор и т.п.
                    Сергей Шлоков
                    03 августа 2021, 17:08
                    +2
                    MODX не умеет очищать сессии, если используется иной, отличный от modSessionHandler класс.
                    Вот это шляпа. По хорошему нужно править это.
                    Самый простой выход — через js в админке менять хандлер у этого пункта меню, в котором указать свой процессор (поправленную копию системного процессора).
                      Наумов Алексей
                      04 августа 2021, 10:01
                      0
                      А самый правильный — интерфейс ISessionHandler с методом flushSessions, от которого наследуется уже modSessionHandler, и что бы именно он вызывался в процессоре.
                        Сергей Шлоков
                        04 августа 2021, 10:21
                        0
                        Правильный — да, реальный — нет. В двойку это не добавят, а тройка никогда не выйдет. Поэтому нужно рулить в рамках пакета.

                        П.С. К слову, я не сторонник С-ишных названий с префиксом I. Да и суффикс Interface, наверно, всё-таки лишний. По-современному должно быть так — интерфейс SessionHandler, а реализации — modSessionHandler, AntibotSessionHandler и т.п.
                          Наумов Алексей
                          04 августа 2021, 10:39
                          0
                          А абстрактный класс тогда как назвать, если SessionHandler занято интерфейсом? BaseSessionHandler?
                          Я с C# много работал N лет назад, в голове все это еще прочно сидит)
                            Сергей Шлоков
                            04 августа 2021, 10:46
                            0
                            BaseSessionHandler?
                            Подойдёт. Таким образом есть понимание, где интерфейс, а где реализация (при DI). Но как правило, одновременно интерфейсы и абстрактные классы используют редко. Для проекта достаточно абстрактного класса, для библиотеки — интерфейса. В общих случаях. Ну и пространства имён никто не отменял (для одинаковых названий).
                              Иван Климчук
                              04 августа 2021, 16:26
                              +2
                              Вам PSR о чем-нибудь говорит? www.php-fig.org/bylaws/psr-naming-conventions/ — первые 3 пункта.
                  Василий Наумкин
                  04 августа 2021, 10:19
                  0
                  Отличная идея для дополнения!

                  Но я тоже за расширение оригинальной таблицы modx_sessions через свой плагин для добавления колонок.
                    Andrey
                    05 августа 2021, 17:55
                    +2
                    Госпаде! Спасибо Вам святой Вы человек! Пусть мана небесная сыплется бесконечно! Это реально ускоряет работу сайта, прям глаза открыли :DDD

                    П.С.
                    А еще закинул чуть чуть рублс для стимуляции подвигов, а это без сомнений подвиг!
                      Наумов Алексей
                      06 августа 2021, 09:52
                      +1
                      Ого, спасибо)
                        Andrey
                        11 августа 2021, 16:13
                        0
                        заметил один баг, он не прям совсем неприятный, но когда добавляешь допустим пользователя в определенную группу, например был он в группе: Users, а нужно еще добавить добавить в Bussines, то раньше при чистке КЕШа и перезагрузке прав, помогало не перелогиниваться пользователю и сразу пользоваться преимуществами новой группы, а сейчас нужно в базе удалять сессию.

                        Я может конечно чет не так понял… но это случилось после того как перешел на этот обработчик! Не подскажите в чем может быть проблемс?
                      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                      38