Вот проблема, с которой мы столкнулись в течение последних нескольких недель.
1/Наша настройка
- PHP 5.4 + MySQL
- 2 выделенных сервера с балансировкой нагрузки
- Сессии реплицируются между двумя серверами с помощью memcached
- 3 приложения, работающие на этих серверах:
- Одно настраиваемое приложение, использующее настройки сеанса php по умолчанию.
- Другое настраиваемое приложение, использующее разные настройки сеанса (имя файла cookie, путь)
- Один Wordpress CMS
2/Проблема
Проблема возникает в нашем первом приложении.
Некоторые из наших пользователей сообщили, что они иногда отключаются через несколько минут (когда сеанс настроен на 3 часа). Это может произойти с ними несколько раз в тот же день, а затем без отключения в течение нескольких дней, но проблема всегда возвращается. Пока доля влияния пользователей небольшая, но я хотел бы решить эту проблему до того, как она "распространится" на других пользователей.
Проблема, по-видимому, возникает в разных местах приложения, хотя мы определили 3 сценария, в которых происходит большинство ошибок:
- Некоторые из них включают представление формы (переменная $_SESSION изменена)
- Другие просто включают открытие всплывающей страницы без изменения данных сеанса.
Мы попытались воспроизвести различные сценарии, описанные пользователями: иногда мы были в состоянии, но большую часть времени у нас нет проблем, что затрудняет отладку.
Другие примечания:
- Проблема в последнее время, это приложение работало годами без каких-либо проблем.
- Это не похоже на нашу загрузку на сервере, потому что проблема все еще возникала во время летнего перерыва, когда наш трафик был низким.
- Это влияет только на один сеанс/пользователей за раз: все остальные пользователи, входящие в систему одновременно, не испытывают этой проблемы.
- Проблема возникла во всех браузерах (IE, Firefox, Chrome).
3/Технический анализ
Когда происходит отключение, пользователь перенаправляется на страницу "Ваш сеанс истек или у вас нет права на просмотр". Когда эта страница загружена, мы получаем техническое письмо с дампом переменной $_SESSION.
Когда сеанс заканчивается обычным способом, полученное письмо показывает, что переменная $_SESSION пуста (нормальное поведение). Когда происходит неожиданное отключение, интересно, что $_SESSION не является полностью пустым: из 20 элементов, содержащихся в массиве, остается только один (всегда один и тот же).
Таким образом, это означает, что сеанс не истек, но недостаточно данных для "идентификации" пользователя, поэтому отображается страница "без прав". В качестве подтверждения, когда это происходит, мы можем проверить memcached, что этот сеанс по-прежнему содержит некоторые данные.
Это потенциальная проблема, которую мы выявили до сих пор, и что мы сделали, чтобы исключить их:
- Memcached указывает между 70 и 80% freespace, поэтому мы не думаем, что это проблема.
- Мы удалили Memcached и вернулись к использованию общего каталога NFS для файлов сеанса: проблема действительно ухудшилась. Это указывает на аппликативную ошибку, поскольку NFS медленнее записывает данные, потеря сеанса будет происходить чаще.
- Мы просмотрели все различные форумы (включая SO), рассказывая о потере данных сеанса PHP, и рассмотрели наш код соответственно. База кода большая, но мы использовали автоматические инструменты и скрипты, чтобы не пропускать файл.
- session_start() вызывается в начале каждой страницы.
- exit() вызывается после каждого заголовка ( "Местоположение..." )
- register_globals отключен
- Мы проверили возможные перерывы между нашими двумя другими приложениями и проблемными, хотя они не разделяют никакой обработки кода, базы данных или сеанса. Там ничего не было.
- Мы проанализировали наши журналы доступа во время разрывов, чтобы проверить шаблоны поведения: вам тоже не повезло.
Итак, мы понятия не имеем, что вызывает эту проблему, поскольку это происходит случайно, поэтому мои вопросы:
- Проблема может исходить из нашего кода: мы пропустили что-нибудь, чтобы проверить? Это решение кажется маловероятным, поскольку код работает в большинстве случаев для всех наших пользователей, но я все еще рассматриваю его.
- Проблема может возникнуть из другого приложения/процесса, который будет "пустым" частью массива переменных сеанса. Мы также рассмотрели код из других приложений, но не нашли ничего, что могло бы вызвать это. И если другой процесс делает это, почему он должен только пустить несколько сеансов, а не все из них?
Спасибо за вашу помощь.