Error unable to obtain session lock что это такое

Ошибка Bitrix — Unable to get session lock within 60 seconds Столкнулся с ошибкой в Bitrix, связанной с сессиями. Особенностью данной установки, осложнившей решение проблемы, было то, что сессии хранились в Memcache. В общем случае есть очень много причин, по которым может возникать подобная ошибка. Расскажу о тех, что мне известны. В моем случае […]

Содержание

  1. Ошибка Bitrix — Unable to get session lock within 60 seconds
  2. Hardware and performance
  3. Moodle on cloud with Redis Cache: Unable to obtain session lock
  4. Moodle on cloud with Redis Cache: Unable to obtain session lock
  5. Настройка балансировки SQL-запросов через ProxySQL для Bitrix
  6. Ахтунг!
  7. Теория
  8. Архитектура
  9. RUNTIME
  10. MEMORY (main)
  11. CONFIG FILE
  12. Запуск
  13. Установка
  14. Конфигурирование
  15. Подготовка
  16. Добавление backend-серверов
  17. Настройка мониторинга
  18. Настройка таблицы для распределения запросов
  19. Настройка пользователей
  20. Настройка правил запросов
  21. Возникающие ошибки:

Ошибка Bitrix — Unable to get session lock within 60 seconds

Столкнулся с ошибкой в Bitrix, связанной с сессиями. Особенностью данной установки, осложнившей решение проблемы, было то, что сессии хранились в Memcache. В общем случае есть очень много причин, по которым может возникать подобная ошибка. Расскажу о тех, что мне известны.

В моем случае ошибка выглядела следующим образом:

Ошибка эта с большой долей вероятности будет возникать на очень долгих запросах. Логично начать решение проблемы именно с этой стороны и по возможности упростить или ускорить запрос. Но может оказаться так, что нет возможности ускорить запрос, так как его выполняет какой-то готовый модуль или его выполнение связано с какими-то сторонними зависимостями и приходится ждать ответа.

Решение ошибки Unable to get session lock within 60 seconds будет зависеть от того, где у вас хранятся сессии. Если в базе данных, то нужно увеличить таймаут ожидания ответа от базы данных. Для этого надо добавить в параметры Mysql сервера следующую настройку:

Не забудьте перезапустить mysql сервер после этого. Если не помогло, то проверьте настройки php. Там тоже можно упереться в ограничение таймаутов в минуту и больше. Увеличьте таймауты в следующих параметрах:

Далее проверяем настройки nginx и таймауты ожидания ответа от backend:

Если ошибка с session lock не проходит, то двигаемся дальше. Если у вас сессии хранятся в memcache, то вас ждёт сюрприз. Параметр lockWait для memcache задан жестко в коде bitrix и так просто вы его не найдёте. Подсказываю сразу, где искать:

Меняем на 600 секунд:

Если уж и это не поможет, то разбирайтесь с самим запросом. 10 минут ждать его завершения слишком долго. Увеличивать таймауты еще больше не имеет смысла.

Источник

Hardware and performance

Moodle on cloud with Redis Cache: Unable to obtain session lock

Moodle on cloud with Redis Cache: Unable to obtain session lock

Hello everyone, in various pages of my moodle, both reserved for the administrator and for public access, I get:
error/Unable to obtain session lock

My setup is as follows:
Moodle 3.9.4+ 20210211
PHP 7.2.20
Apache/2.4.6(Server MPM: prefork)
MySQL 5.7.28 (on cluster)
Redis server (for application cache) v=6.0.9
Redis server (for session cache) v=6.2.0
O.S. CentOS Linux release 7.5
shared Network File System for moodle files and moodledata no SSD

(Some configurations, as prefork, are bound by company policies)

I have a large DB (105 GB) and about 60000 users with over 2600 courses
4 virtual machine on cloud behind a V.I.P. and a load balancer, every v.m. with 12 vCPU (Intel Xeon CPU X5650 2.67GHz) and 9 GB of RAM
1 v.m. with Redis for application cache (8 vCPU (Intel Xeon CPU X5650 2.67GHz) and 8 GB of RAM)
1 v.m. with Redis for session cache (8 vCPU (Intel Xeon CPU X5650 2.67GHz) and 8 GB of RAM)
1 v.m. only for crontab every minutes (12 vCPU (Intel Xeon CPU X5650 2.67GHz) and 9 GB of RAM)
1 v.m. for MySQL DB as a Service (4 Cpu (3.2 GHz), 8 Gb ram)

Some examples on log files:
Cannot obtain session lock for sid: cphrrvj5kvc5ou11ueptoabi8p within 120 seconds. It is likely another page ([pid 4708] /course/view.php?id=123794) has a long session lock, or the session lock was never released.
Cannot obtain session lock for sid: jugh67eg4591fe4l87ngnptf2l within 120 seconds. It is likely another page ([pid 9690] /mod/lesson/view.php?id=92443) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/view.php?id=123456
Cannot obtain session lock for sid: d6ekd6a8mbkmj7mgpni5aq12uk, referer: https://xxxxxxxx/mod/quiz/review.php?attempt=1199680&cmid=101507
Cannot obtain session lock for sid: e7ijkt4dthsmclf4mkaromncj7 within 120 seconds. It is likely another page ([pid 1544] /admin/category.php?category=users) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/
Cannot obtain session lock for sid: 7cl4kh6e9dpmoniro6peign6oc, referer: https://xxxxxxxx/mod/scorm/player.php
Cannot obtain session lock for sid: 0ab2kt5vk0h7tr3ns296cg2ngc within 120 seconds. It is likely another page ([pid 30065] /course/index.php?categoryid=123) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/index.php?categoryid=123
Cannot obtain session lock for sid: lnb5hfjfd8affontfk8n9300oj within 120 seconds. It is likely another page ([pid 20917] /admin/category.php?category=modules) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/
Cannot obtain session lock for sid: emv3hrqa0b5grtu1m64jfu3ffa within 120 seconds. It is likely another page ([pid 6231] /course/view.php?id=123123) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/login/index.php
Cannot obtain session lock for sid: 9oq3tadrb5lmgp2jj709suun24 within 120 seconds. It is likely another page ([pid 11245] /report/progress/index.php?course=123321&silast=R) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/index.php?categoryid=123
Cannot obtain session lock for sid: eg549ic50eikmc2di4l52c2g7i within 120 seconds. It is likely another page ([pid 14670] /mod/customcert/my_certificates.php?userid=xxx&certificateid=xxx&downloadcert=1) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/mod/customcert/my_certificates.php?userid=xxx

Our config.php is as follows:
$CFG->enable_read_only_sessions = true;
$CFG->preventfilelocking = true;
$CFG->session_handler_class = ‘coresessionredis’;
$CFG->session_redis_host = ‘xx.xxx.xx.x’;
$CFG->session_redis_port = 6379; // Optional.
$CFG->session_redis_database = 0; // Optional, default is db 0.
$CFG->session_redis_auth = ‘xyz’; // Optional, default is don’t set one.
$CFG->session_redis_prefix = »; // Optional, default is don’t set one.
$CFG->session_redis_acquire_lock_timeout = 120;
$CFG->session_redis_lock_expire = 7200;
$CFG->session_redis_lock_retry = 10;
$CFG->session_redis_acquire_lock_retry = 10;

$CFG->local_redislock_redis_server = ‘xx.xxx.xx.x’;
$CFG->lock_factory = ‘\local_redislock\lock\redis_lock_factory’;
$CFG->local_redislock_auth = »;

On /etc/httpd/conf.d/php.conf
php_value session.save_handler «redis»
php_value session.save_path «tcp://xx.xxx.xx.x:6379»

On /etc/php.ini
session.save_handler = redis
session.save_path = «tcp://xx.xxx.xx.x:6379»

On /etc/httpd/config_vhosts/www.xxxxxxxx_443/php.conf
php_admin_value session.save_path tcp://xx.xxx.xx.x:6379

On /etc/redis.conf
‘appendonly yes’
‘appendfsync everysec’

Anyone have any ideas or suggestions to overcome the problem? Thanks in advance, have a nice day.

Источник

Настройка балансировки SQL-запросов через ProxySQL для Bitrix

Исходная проблема, из-за которой я пришёл к ProxySQL, состояла в том, что на одном из проектов, где используется старый Bitrix (установлен на RHEL 6), модуль “веб-кластер” с багами. Через него была настроена репликация Master-Slave, и периодически слейвы переставали видеться через модуль и все запросы шли на master-базу, тем самым загружая основной сервер с БД, что приводило к диким cpu iowait и как следствие – к недоступности порталов проекта. В силу того, что обновить кастомный битрикс возможности нет, как и времени на допиливание разработчиками модуля для устранения ошибок, было решено попробовать использовать стороннее решение для организации балансировки SQL-запросов для схемы Master-Slave.

В теории, изначально можно было бы использовать Nginx и TCP-балансировку, но в таком случае Nginx не воспринимал бы запросы SQL как таковые, т.к. он не умеет различать MySQL, а потому разделить их на те, которые адресованы для Slave, а которые для Master, нормальной возможности не было, используя Nginx.

Изучив инструменты, которые могли бы подойти для решения задачи, я остановился на ProxySQL, т.к. по отзывам и документации он самый стабильный и производительный.

Ахтунг!

То, как ниже описана примитивная реализация проксирования запросов до Master и Slave совсем не true-way, а костыли, но такой вариант тоже имеет право на существование при наличии всяческих обстоятельств.

Согласно документации, для продуктивного контура нужно использовать тонкую и более тщательную настройку проксирования запросов на основе статистики (время выполнения или частота вызова, например). Здесь же сделано всё “в лоб” с небольшой доработкой, нужно иметь это ввиду.

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

Теория

ProxySQL – ПО с открытым исходным кодом (GPL license) для проксирования SQL-запросов. Представляет собой высокопроизводительный инструмент, который можно применять для HA.

Поддерживает MySQL и его форки (Percona, Maria & etc).

Развитие ProxySQL обусловлено отсутствием прокси с открытым исходным кодом, которые обеспечивают высокую производительность.

Архитектура

Имеет весьма сложную, но простую в использовании систему конфигурации.

  • умеет обновлять динамически конфиги, что полезно для HA и нулевого времени простоя;
  • поддерживает возможность изменения элементов конфигурации, не требуя рестарта процесса ProxySQL;
  • позволяет производить легкий откат конфигов.

Официальная схема взаимодействия уровней (слоёв):

RUNTIME

Представляет структуры данных ProxySQL в памяти, содержит всю информацию для проксирования запросов

MEMORY (main)

Является базой данных в памяти, доступ к которой осуществляется через MySQL-клиент.

База содержит следующие таблицы:

  • mysql_servers – список внутренних серверов, к которым подключается ProxySQL;
  • mysql_users – список пользователей и их учетные данные, которые подключаются к ProxySQL и внутренним серверам;
  • mysql_query_rules – список правил запросов, которые анализируются при маршрутизации трафика;
  • global_variables – список глобальных переменных. Полезно для конфигурирования во время выполнения;
  • mysql_collations – список сопоставлений MySQL, доступных для работы с прокси. Извлекаются из клиентской библиотеки.

Представляет собой базу данных SQLite3 на диске. Располагается в $(DATADIR)/proxysql.db.

При перезапуске сервиса ProxySQL, все конфиги, которые правились в Memory, будут очищены. Поэтому очень важно сохранять все конфигурации в слой DISK, откуда уже идёт загрузка в MEMORY.

CONFIG FILE

Является классическим инструментом конфигурации.

Запуск

При обычном запуске, ProxySQL ищет свой конфигурационный файл, в котором определяется рабочая директория. Что произойдёт далее, зависит от наличия или отсутствия файла БД (DISK) в директории, которая указана в конфиге.

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

Если файла с БД нет, то он генерится на основе конфига и загружается в MEMORY и RUNTIME.

Установка

Для установки добавить репозиторий, заменив в baseurl …/centos/$releasever на нужную цифру, в данном случае RHEL 6, т.к. иначе выдаст 404 ошибку:

Во избежание ошибки Unable to parse unknown SET query я установил версию ProxySQL version 2.0.5-37-gc8e32ee, т.к. при выполнении некоторых запросов после настройки были глюки. Тема обсуждалась тут.

Проверить, что успешно запустился:

Для управления через консольного клиента mysql нужно его установить:

И проверить, что само подключение устаналивается:

Командой ниже можно проверить список имеющихся таблиц. В данном случае это уровень абстракции MEMORY, т.е. БД в памяти.

Отсюда происходит перемещение конфигурации между уровнями посредством различных команд (написаны ниже). Цифра в начале команды для наглядности соответствует абстрактному уровню, представленному в официальной схеме взаимодействия (в начале статьи в разделе Архитектура):

  • [1] LOAD MYSQL USERS FROM MEMORY / LOAD MYSQL USERS TO RUNTIME
    • загружает пользователей MySQL из БД в памяти в структуры данных RUNTIME или наоборот
  • [2] SAVE MYSQL USERS TO MEMORY / SAVE MYSQL USERS FROM RUNTIME
    • сохраняет пользователей MySQL из RUNTIME в MEMORY
  • [3] LOAD MYSQL USERS TO MEMORY / LOAD MYSQL USERS FROM DISK
    • загружает постоянных пользователей MySQL из базы данных на диске в базу данных в памяти
  • [4] SAVE MYSQL USERS FROM MEMORY / SAVE MYSQL USERS TO DISK
    • сохраняет пользователей MySQL из базы данных в памяти в базу данных на диске
  • [5] LOAD MYSQL USERS FROM CONFIG
    • загружает из файла конфигурации пользователей в базу данных в памяти

Конфигурирование

Подготовка

На этом хватит теории и для полного понимания и закрепления пора переходить к практике. Исходные данные для понимания:

10.15.61.141 – ProxySQL & App
10.126.253.45 – SLAVE
10.126.253.46 – MASTER

Репликация в MySQL уже настроена. Перед началом хочу заметить, что лучше исключить из репликации таблицы b_sec_session, если сессии хранятся в БД, т.к. сами битриксы говорят, что это вызывает глюки при большой нагрузке.

Перед началом удобнее сразу создать двух пользователей на master и slave базах для доступа с сервера ProxySQL:

  • пользователь monitor , предварительно убедившись, что учетка monitor уже не используется для мониторинга самих слейвов. Через неё ProxySQL будет делать healthcheck:
  • пользователя, через которого подключается приложение к БД. В данном случае, т.к. ProxySQL находится на веб-ноде, где и само приложение, пользователь app_user уже должен быть с нужными правами:

И ещё важный момент. ProxySQL в дальнейшем должен понимать, в какую группу отнести сервера: для чтения или для записи. Изначально я подумал, что это назначается вручную, но это была ошибка. ProxySQL, используя учётку monitoring, подключается к backend и смотрит значение переменной read_only в самом MySQL. Если значение 1, то запись в БД могут вносить только пользователи с привилегиями SUPER. Таким образом, можно быть уверенным, что на слейв придут запросы на изменение только со стороны мастера (если нет иных юзеров с правами SUPER). Этакий best practice. Поэтому для слейва нужно изменить значение этой переменной глобально и потом добавить его в конфиг:

Добавление backend-серверов

Далее нужно залогиниться в консоль управления ProxySQL и добавить backend-сервера БД в нужный hostgroup:

Да, здесь не опечатка, изначально и мастер и слейв сервера добавляются с одним hostgroup_id. Можно выбрать следующие поля (остальные пока не интересуют) и проверить:

Настройка мониторинга

В подготовительном этапе на мастере и слейве был создан пользователь monitor. Теперь, чтобы прокси мог подключаться, нужно указать учетные данные в его конфиге.

Чтобы эти значения подгрузились, нужно внести их в рантайм и на диск:

Теперь если выполнить команду ниже, можно увидеть, что ProxySQL успешно “пингует” бэкенды и в поле connect_error значение NULL – значит всё ок:

Настройка таблицы для распределения запросов

Теперь нужно поработать с этой таблицей, которая пока пустая:

С её помощью, перечисленные в ней hostgroups могут быть настроены для для направления запросов до мастера или до слейва, как раз-таки на основе значения read_only.

В строке выше была добавлена запись с writer_hostgroup (10) и reader_hostgroup (20). В последней пока нет узлов – они туда будут помещены автоматически (благодаря проверке read_only).

Если у сервера read_only = 0, он будет перемещен в группу хостов 10, т.к. это Master
Если у сервера read_only = 1, он будет перемещен в группу хостов 20, т.к. это Slave

И для применения этого осталось выполнить загрузку в рантайм:

Теперь если выполнить команду ниже, видно, что в таблице сменился hostgroup_id на нужный:

Для проверки, что всё сохранилось и загружается, я делал рестарт сервиса ProxySQL и смотрел, не изменились ли записи в таблицах. Если нет, то всё ок, можно настраивать далее.

Настройка пользователей

Осталось добавить пользователя app_user, который будет подключаться к прокси, а тот уже, в свою очередь, обращаться в нужную базу.

Стоит обратить внимание, что пользователю указывается default_hostgroup – группа, в которой мастер сервер.

Проверка, что пользователь добавлен:

И проверить, что можно подключиться (консольным клиентом с сервера приложений):

А также последняя проверка ещё раз, что ProxySQL может конектиться к бэку:

На этом всё готово и можно переходить к самой сложной и важной части – настройки проксирования запросов.

Настройка правил запросов

Осталось настроить таблицу, в которой содержатся правила, на основе которых запросы будут отправляться в ту или иную группу:

P.S. В оф. документации не указан пользователь (поле username) при наполнении таблицы mysql_query_rules. Без этого поля (без добавления оно будет NULL) у меня возникали непонятные ошибки и глюки.

Проверка, что по созданным правилам запросов выше есть хиты, т.е. всё работает:

Теперь всё минимально настроено и в настройках приложения можно переключаться на инстанс ProxySQL, который слушает локально на том же сервере, где и само приложение на порту 6033 – 127.0.0.1:6033

После открытия портала, побегав по страницам, можно выполнить запрос и увидеть, что поле Queries растёт в нужной hostgroup, а значит всё ок:

В общем и целом на этом настройка закончена. В админке битрикса лучше заранее перед настройкой ProxySQL выпилить старые настройки слейвов в модуле “Веб-кластер”, а также перезапустить сервис кеширования (memcached в моём случае), если таковой используется.

По-хорошему, при использовании данного решения в продакшене, нужно ещё будет дополнительно настроить slave_lag, чтобы в случае разъехавшейся репликации, запросы перекидывались на мастер.

Возникающие ошибки:

В процессе настройки приложение себя вело странным образом, выдавая те или иные ошибки. При решении всегда смотреть в /var/lib/proxysql/proxysql.log

  • Unable to get session lock within 60 seconds (в браузере)
  • ERROR 2013 (HY000): Lost connection to MySQL server during query (в proxysql.log)

Данные ошибки были связаны с некорректными таймаутами в настройках серверов MySQL, на мастере и слейве в my.cnf:

wait_timeout – таймаут ожидания необходим, чтобы защищать приложением в том случае, когда клиенты ничего не делают, кроме как поглощают соединение. По истечении 600 сек бездействующих клиентов отключает по таймауту;

interactive_timeout – используется только для соединений с интерактивными клиентами, такими как клиенты MySQL из командной строки, с этим вроде как понятно. Обычно значение устанавливается как и wait_timeout , но в отдельных случаях может быть изменено.

net_read_timeout – количество секунд ожидания для получения дополнительных данных из соединения перед прекращением чтения. Аналогично и для клиентов, ведущих запись.

connection_timeout – сколько ждать ответа сервера перед тем, как выдать ошибку о том, что сервер не отвечает. Именно с данным параметром, значение которого увеличил с 30 до 600, ошибка Unable to get session lock within 60 seconds перестала появляться.

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

Источник

Hello everyone, in various pages of my moodle, both reserved for the administrator and for public access, I get:
error/Unable to obtain session lock

My setup is as follows:
Moodle 3.9.4+ 20210211
PHP 7.2.20
Apache/2.4.6(Server MPM: prefork)
MySQL 5.7.28 (on cluster)
Redis server (for application cache) v=6.0.9
Redis server (for session cache) v=6.2.0
O.S. CentOS Linux release 7.5
shared Network File System for moodle files and moodledata no SSD

(Some configurations, as prefork, are bound by company policies)

I have a large DB (105 GB) and about 60000 users with over 2600 courses
4 virtual machine on cloud behind a V.I.P. and a load balancer, every v.m. with 12 vCPU (Intel Xeon CPU X5650 2.67GHz) and 9 GB of RAM
1 v.m. with Redis for application cache (8 vCPU (Intel Xeon CPU X5650 2.67GHz) and 8 GB of RAM)
1 v.m. with Redis for session cache (8 vCPU (Intel Xeon CPU X5650 2.67GHz) and 8 GB of RAM)
1 v.m. only for crontab every minutes (12 vCPU (Intel Xeon CPU X5650 2.67GHz) and 9 GB of RAM)
1 v.m. for MySQL DB as a Service (4 Cpu (3.2 GHz), 8 Gb ram)

Some examples on log files:
Cannot obtain session lock for sid: cphrrvj5kvc5ou11ueptoabi8p within 120 seconds. It is likely another page ([pid 4708] /course/view.php?id=123794) has a long session lock, or the session lock was never released.
Cannot obtain session lock for sid: jugh67eg4591fe4l87ngnptf2l within 120 seconds. It is likely another page ([pid 9690] /mod/lesson/view.php?id=92443) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/view.php?id=123456
Cannot obtain session lock for sid: d6ekd6a8mbkmj7mgpni5aq12uk, referer: https://xxxxxxxx/mod/quiz/review.php?attempt=1199680&cmid=101507
Cannot obtain session lock for sid: e7ijkt4dthsmclf4mkaromncj7 within 120 seconds. It is likely another page ([pid 1544] /admin/category.php?category=users) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/
Cannot obtain session lock for sid: 7cl4kh6e9dpmoniro6peign6oc, referer: https://xxxxxxxx/mod/scorm/player.php
Cannot obtain session lock for sid: 0ab2kt5vk0h7tr3ns296cg2ngc within 120 seconds. It is likely another page ([pid 30065] /course/index.php?categoryid=123) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/index.php?categoryid=123
Cannot obtain session lock for sid: lnb5hfjfd8affontfk8n9300oj within 120 seconds. It is likely another page ([pid 20917] /admin/category.php?category=modules) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/
Cannot obtain session lock for sid: emv3hrqa0b5grtu1m64jfu3ffa within 120 seconds. It is likely another page ([pid 6231] /course/view.php?id=123123) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/login/index.php
Cannot obtain session lock for sid: 9oq3tadrb5lmgp2jj709suun24 within 120 seconds. It is likely another page ([pid 11245] /report/progress/index.php?course=123321&silast=R) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/course/index.php?categoryid=123
Cannot obtain session lock for sid: eg549ic50eikmc2di4l52c2g7i within 120 seconds. It is likely another page ([pid 14670] /mod/customcert/my_certificates.php?userid=xxx&certificateid=xxx&downloadcert=1) has a long session lock, or the session lock was never released., referer: https://xxxxxxxx/mod/customcert/my_certificates.php?userid=xxx

Our config.php is as follows:
$CFG->enable_read_only_sessions = true;
$CFG->preventfilelocking = true;
$CFG->session_handler_class = ‘coresessionredis’;
$CFG->session_redis_host = ‘xx.xxx.xx.x’;
$CFG->session_redis_port = 6379;  // Optional.
$CFG->session_redis_database = 0;  // Optional, default is db 0.
$CFG->session_redis_auth = ‘xyz’; // Optional, default is don’t set one.
$CFG->session_redis_prefix = »; // Optional, default is don’t set one.
$CFG->session_redis_acquire_lock_timeout = 120;
$CFG->session_redis_lock_expire = 7200;
$CFG->session_redis_lock_retry = 10;
$CFG->session_redis_acquire_lock_retry = 10;

$CFG->local_redislock_redis_server = ‘xx.xxx.xx.x’;
$CFG->lock_factory = ‘\local_redislock\lock\redis_lock_factory’;
$CFG->local_redislock_auth = »;

On /etc/httpd/conf.d/php.conf
  php_value session.save_handler «redis»
  php_value session.save_path    «tcp://xx.xxx.xx.x:6379»

  On /etc/php.ini
  session.save_handler = redis
  session.save_path = «tcp://xx.xxx.xx.x:6379»

  On /etc/httpd/config_vhosts/www.xxxxxxxx_443/php.conf
  php_admin_value session.save_path tcp://xx.xxx.xx.x:6379

On /etc/redis.conf
  ‘appendonly yes’
  ‘appendfsync everysec’

Anyone have any ideas or suggestions to overcome the problem? Thanks in advance, have a nice day.

Giuseppe


Проблема с дублированием тестов

  • ◄ Удаление ненужных курсов
  • Не загружаются видеолекции ►

Проблема с дублированием тестов

Number of replies: 2

Здравствуйте. 

Последнее время при попытке дублировать тест со случайными вопросами moodle  зависает и в данном браузере больше не открывается.

Пишет ошибку error/Unable to obtain session lock.

Тест в результате в 99% случаев не дублируется.

Это связано со слишком большой базой тестов?

курс Физическая химия Булидоровой Г.В.

In reply to Булидорова Галина Викторовна

Re: Проблема с дублированием тестов

Сейчас, почищу, генерируемые вопросы при каждом копировании удваиваются в количестве, сейчас их 15 млн.
Автоматически система их чистит, но когда делается много копирований курса, не успевает.

In reply to Богомолов Владислав Афанасьевич

Re: Проблема с дублированием тестов

  • ◄ Удаление ненужных курсов
  • Не загружаются видеолекции ►
 

Пользователь 223662

Заглянувший

Сообщений: 27
Баллов: 1
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 30.10.2013

#1

0

25.12.2013 18:17:00

Приветствую. После восстановления сайта с резервной копии, сайт стал на порядок медленнее работать и периодично выдавать такую ошибку:

Код
[ErrorException] E_USER_ERROR
Unable to get session lock within 60 seconds. (0)
/var/www/bitrix/bitrix/modules/security/classes/general/session.php:71
#0: trigger_error("Unable to get s...hin 60 seconds." (45), 256)
   /var/www/bitrix/bitrix/modules/security/classes/general/session.php:71
#1: CSecuritySession::triggerFatalError("Unable to get s...hin 60 seconds." (45))
   /var/www/bitrix/bitrix/modules/security/classes/general/session_db.php:42
#2: CSecuritySessionDB::read("lvavp8lff3dkjc1gqq1oco6sf0")
   
#3: session_start()
   /var/www/bitrix/bitrix/modules/main/include.php:294
#4: require_once("/var/www/bitrix...ain/include.php" (47))
   /var/www/bitrix/bitrix/modules/main/include/prolog_admin_before.php:18
#5: require_once("/var/www/bitrix...dmin_before.php" (67))
   /var/www/bitrix/bitrix/modules/main/admin/cache.php:11
#6: require_once("/var/www/bitrix...admin/cache.php" (51))
   /var/www/bitrix/bitrix/admin/cache.php:1
 

Время загрузки сайта на локальной машине достигает минуты. Бизнес 14.0.6.
Прошу скорее помочь с решением проблемы.

 

Пользователь 223662

Заглянувший

Сообщений: 27
Баллов: 1
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 30.10.2013

#2

0

26.12.2013 10:03:04

/var/www/bitrix/bitrix/modules/security/classes/general/sess­ion.php:71

Код
    class CSecuritySession

    /**
    * @param string $pMessage
    */
   public static function triggerFatalError($pMessage = "")
   {
      CHTTP::SetStatus("500 Internal Server Error");
      trigger_error($pMessage, E_USER_ERROR); //// <===71
      die();
   }

/var/www/bitrix/bitrix/modules/security/classes/general/sess­ion_db.php:42

Код
 class CSecuritySessionDB

  /**
   * @param string $id - session id, must be valid hash
   * @return string
   */
  public static function read($id)
  {
    if(!self::isValidId($id))
      return "";

    if(!CSecurityDB::Lock($id, 60/*TODO: timelimit from php.ini?*/))
      CSecuritySession::triggerFatalError('Unable to get session lock within 60 seconds.');// <===42

    $rs = CSecurityDB::Query("
      select SESSION_DATA
      from b_sec_session
      where SESSION_ID = '".$id."'
    ", "Module: security; Class: CSecuritySession; Function: read; File: ".__FILE__."; Line: ".__LINE__);
    $ar = CSecurityDB::Fetch($rs);
    if($ar)
    {
      $res = base64_decode($ar["SESSION_DATA"]);
      return $res;
    }

    return "";
  }

CSecurityDB::Lock

Код
   function Lock($id, $timeout = 60)
   {
      static $lock_id = "";

      if($id === false)
      {
         if($lock_id)
            $rsLock = CSecurityDB::Query("DO RELEASE_LOCK('".$lock_id."')", "Module: security; Class: CSecurityDB; Function: Lock; File: ".__FILE__."; Line: ".__LINE__);
      }
      else
      {
         $rsLock = CSecurityDB::Query("SELECT GET_LOCK('".md5($id)."', ".intval($timeout).") as L", "Module: security; Class: CSecurityDB; Function: Lock; File: ".__FILE__."; Line: ".__LINE__);
         if($rsLock)
         {
            $arLock = CSecurityDB::Fetch($rsLock);
            if($arLock["L"]=="0")
               return false;
            else
               $lock_id = md5($id);
         }
      }
      return is_resource($rsLock);
   }
 

Пользователь 156811

Заглянувший

Сообщений: 6
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 05.02.2013

Добрый день! Столкнулся с аналогичной проблемой.

De

, удалось ли вам решить? Если да, то как?

 

Пользователь 223662

Заглянувший

Сообщений: 27
Баллов: 1
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 30.10.2013

 

Пользователь 223662

Заглянувший

Сообщений: 27
Баллов: 1
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 30.10.2013

Вернее да, но Сталинским методом. Просто снес битрикс на радость нервам и серверу.

 

Пользователь 33158

Заглянувший

Сообщений: 13
Авторитет:

0

Рейтинг пользователя:

0

Регистрация: 18.11.2008

А что представители Битрикс  молчат?
С 14 версией началась постоянная проблема:
«При выполнении скрипта возникла ошибка. Включить расширенный вывод ошибок можно в файле настроек .settings.php«
после какого-то кустарного скрипта который нужно было самому где-то найти и установить, появилась  эта проблема:
[ErrorException] E_USER_ERROR
Unable to get session lock within 60 seconds. (0)
/home/h/hitorg/public_html/bitrix/modules/security/classes/g­eneral/session.php:71
#0: trigger_error(string, integer)

…..
Что с проблемой то делать? некоторые стандартные  функции неработают!
Не редактируются компоненты, не могу изменить заказ клиента в админке…

 

Пользователь 234561

Заглянувший

Сообщений: 18
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 30.12.2013

#7

0

20.05.2014 15:44:54

Добрый день!
Кто то уже получил ответ по данной проблеме?

Код
[ErrorException] E_USER_ERROR
Unable to get session lock within 60 seconds. (0)
/home/bitrix/www/bitrix/modules/security/classes/general/session.php:71
#0: trigger_error(string, integer)
   /home/bitrix/www/bitrix/modules/security/classes/general/session.php:71
#1: CSecuritySession::triggerFatalError(string)
   /home/bitrix/www/bitrix/modules/security/classes/general/session_db.php:42
#2: CSecuritySessionDB::read(string)
   
#3: session_start()
   /home/bitrix/www/bitrix/modules/main/include.php:298
#4: require_once(string)
   /home/bitrix/www/bitrix/modules/main/include/prolog_before.php:14
#5: require_once(string)
   /home/bitrix/www/bitrix/modules/main/include/prolog.php:11
#6: require_once(string)
   /home/bitrix/www/bitrix/header.php:1
#7: require(string)
   /home/bitrix/www/catalog/detail_section.php:2
#8: include_once(string)
   /home/bitrix/www/bitrix/modules/main/include/urlrewrite.php:152
#9: include_once(string)
   /home/bitrix/www/bitrix/urlrewrite.php:2 
 

Пользователь 80243

Заглянувший

Сообщений: 14
Авторитет:

0

Рейтинг пользователя:

0

Регистрация: 05.01.2011

Выставите  max_execution_time = 60

 

Пользователь 80802

Заглянувший

Сообщений: 44
Баллов: 2
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 14.01.2011

#9

0

20.08.2014 00:59:47

Аналогичная проблема и так же при переносе.

Цитата
Горев Кирилл пишет:
Выставите max_execution_time = 60

Это как больной зуб лечить обезболивающим.

Ни кто не нашел больше решения?

 

Пользователь 105275

Заглянувший

Сообщений: 3
Авторитет:

0

Рейтинг пользователя:

0

Регистрация: 24.11.2011

#10

0

29.08.2014 15:11:15

Отключите хранение сессий в БД модуля безопасности.

 

Пользователь 57829

Гуру

Сообщений: 3754
Баллов: 320
Авторитет:

0

Рейтинг пользователя:

2

Регистрация: 17.02.2010

#11

0

29.08.2014 19:57:03

т.е. обратится в тп так никто и не удосужился?

 

Администратор

Сообщений: 10
Баллов: 3
Авторитет:

1

Рейтинг пользователя:

1

Регистрация: 08.05.2009

#12

0

06.10.2014 12:44:56

Эта ошибка говорит о том, что пользователь уже один раз обращался к сайту и запустил какой-то долгий процесс. При повторном обращении к сайту, когда выполняется еще первый запрос, выводится эта ошибка.
Необходимо определить, что именно делал пользователь, что при повторном обращении у него возникла эта проблема. Например, при переходе в список товаров этот список выводится больше минуты.

 

Пользователь 129527

Заглянувший

Сообщений: 11
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 21.05.2012

#13

0

18.12.2014 11:44:13

Цитата
Александр Корякин написал:
Эта ошибка говорит о том, что пользователь уже один раз обращался к сайту и запустил какой-то долгий процесс. При повторном обращении к сайту, когда выполняется еще первый запрос, выводится эта ошибка.
Необходимо определить, что именно делал пользователь, что при повторном обращении у него возникла эта проблема. Например, при переходе в список товаров этот список выводится больше минуты.

Пользователя зовут 1С и admin и это печаль :(
Процесс импорта и экспорта данных занимает в любом (моем) случае не менее 60 сек.
Будем игнорировать рекомендуемые настройки для безопасности — отключаем хранения сессий в БД.

Бизнес – это легко. А если случается так, что трудно, то это не означает, что невозможно.

 

Пользователь 303016

Заглянувший

Сообщений: 4
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 04.01.2015

#14

0

28.03.2015 00:32:23

Цитата
Павел Пешков написал:
отключаем хранения сессий в БД.

а как отключить, если в админку уже не войти?

 

Пользователь 303016

Заглянувший

Сообщений: 4
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 04.01.2015

#15

0

28.03.2015 08:09:16

 

Пользователь 129527

Заглянувший

Сообщений: 11
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 21.05.2012

#16

0

28.03.2015 15:00:01

Александр Егорин

, попробуй посмотреть в конфигурационных файлах системы dbconn.php или .settings.php
Если нет, тогда в БД нужно искать.

Бизнес – это легко. А если случается так, что трудно, то это не означает, что невозможно.

 

Пользователь 164017

Заглянувший

Сообщений: 2
Авторитет:

5

Рейтинг пользователя:

0

Регистрация: 25.04.2013

#17

0

20.06.2018 17:43:44

На дворе 2018 г., ошибка имеет место быть(((

 

Пользователь 302684

Постоянный посетитель

Сообщений: 94
Баллов: 11
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 25.12.2014

#18

0

26.06.2018 17:30:07

Аналогичная проблема на версии

18.0.1

при попытке открыть одновременно несколько страниц на которых впервые выполняется метод CFile::ResizeImageGet(), который соответственно вешает страницу, пока выполняется.

Если сообщение было для Вас полезным, лучшая благодарность это кнопка «Мне нравится» ;)

 

Пользователь 302684

Постоянный посетитель

Сообщений: 94
Баллов: 11
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 25.12.2014

#19

0

26.06.2018 17:32:45

Цитата
Александр Егорин написал:

Цитата
Павел Пешков  написал:
отключаем хранения сессий в БД.

а как отключить, если в админку уже не войти?

Вообще когда медленный запрос завершит свою работу, сайт должно отпустить. Или надо зайти с другого компа.

Если сообщение было для Вас полезным, лучшая благодарность это кнопка «Мне нравится» ;)

 

Пользователь 1388849

Заглянувший

Сообщений: 5
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 07.09.2017

#20

0

24.09.2020 10:27:02

Аналогичная ошибка, на тестовом сервере, где никто не особо не сидит :-

 

Пользователь 1388849

Заглянувший

Сообщений: 5
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 07.09.2017

#21

0

24.09.2020 12:40:56

Цитата
Андрей Дедов написал:
Аналогичная ошибка, на тестовом сервере, где никто не особо не сидит :-

Решили, ошибка была связана с отсутствием места на сервере БД.

 

Пользователь 13618

Эксперт

Сообщений: 1137
Баллов: 184
Авторитет:

10

Рейтинг пользователя:

0

Регистрация: 05.04.2011

Сертифицированный партнер

#22

0

08.05.2021 04:54:48

 

Пользователь 5557684

Заглянувший

Сообщений: 6
Авторитет:

0

Рейтинг пользователя:

0

Регистрация: 09.09.2021

#23

0

16.09.2021 12:25:44

Такая же ошибка сейчас и место на сервере есть? Кто решил?

 

Пользователь 8393

Заглянувший

Сообщений: 1
Авторитет:

1

Рейтинг пользователя:

0

Регистрация: 09.01.2007

#24

0

20.09.2021 17:34:31

Цитата
АЛЛА написал:
Такая же ошибка сейчас и место на сервере есть? Кто решил?

Проверьте размер таблицы b_user_session. Если её размер исчисляется гигабайтами, то попробуйте очистить её (все авторизованные пользователи разлогинятся).
Либо отключите хранение сессий в базе данных. Тут

https://dev.1c-bitrix.ru/user_help/settings/security/security_session.php

написано как.

 

Пользователь 2370559

Заглянувший

Сообщений: 6
Авторитет:

0

Рейтинг пользователя:

0

Регистрация: 08.08.2018

#25

0

23.01.2023 01:58:16

Ошибка ушла после того, как исправили настройки таймаутов MySQL.

Было так:  

PHP – 60 сек
Nginx – 300 сек
Mysql – 10 сек (connect_timeout) — это слишком мало.

Исходная проблема, из-за которой я пришёл к ProxySQL, состояла в том, что на одном из проектов, где используется старый Bitrix (установлен на RHEL 6), модуль “веб-кластер” с багами. Через него была настроена репликация Master-Slave, и периодически слейвы переставали видеться через модуль и все запросы шли на master-базу, тем самым загружая основной сервер с БД, что приводило к диким cpu iowait и как следствие – к недоступности порталов проекта. В силу того, что обновить кастомный битрикс возможности нет, как и времени на допиливание разработчиками модуля для устранения ошибок, было решено попробовать использовать стороннее решение для организации балансировки SQL-запросов для схемы Master-Slave.

В теории, изначально можно было бы использовать Nginx и TCP-балансировку, но в таком случае Nginx не воспринимал бы запросы SQL как таковые, т.к. он не умеет различать MySQL, а потому разделить их на те, которые адресованы для Slave, а которые для Master, нормальной возможности не было, используя Nginx.

Изучив инструменты, которые могли бы подойти для решения задачи, я остановился на ProxySQL, т.к. по отзывам и документации он самый стабильный и производительный.

Содержание

  1. Ахтунг!
  2. Теория
  3. Архитектура
  4. RUNTIME
  5. MEMORY (main)
  6. DISK
  7. CONFIG FILE
  8. Запуск
  9. Установка
  10. Конфигурирование
  11. Подготовка
  12. Добавление backend-серверов
  13. Настройка мониторинга
  14. Настройка таблицы для распределения запросов
  15. Настройка пользователей
  16. Настройка правил запросов
  17. Возникающие ошибки:
  18. Используемые источники

Ахтунг!

То, как ниже описана примитивная реализация проксирования запросов до Master и Slave совсем не true-way, а костыли, но такой вариант тоже имеет право на существование при наличии всяческих обстоятельств.

Согласно документации, для продуктивного контура нужно использовать тонкую и более тщательную настройку проксирования запросов на основе статистики (время выполнения или частота вызова, например). Здесь же сделано всё “в лоб” с небольшой доработкой, нужно иметь это ввиду.

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

Теория

ProxySQL – ПО с открытым исходным кодом (GPL license) для проксирования SQL-запросов. Представляет собой высокопроизводительный инструмент, который можно применять для HA.

Поддерживает MySQL и его форки (Percona, Maria & etc).

Развитие ProxySQL обусловлено отсутствием прокси с открытым исходным кодом, которые обеспечивают высокую производительность.

Архитектура

Имеет весьма сложную, но простую в использовании систему конфигурации.

ProxySQL:

  • умеет обновлять динамически конфиги, что полезно для HA и нулевого времени простоя;
  • поддерживает возможность изменения элементов конфигурации, не требуя рестарта процесса ProxySQL;
  • позволяет производить легкий откат конфигов.

Официальная схема взаимодействия уровней (слоёв):

+-------------------------+
|         RUNTIME         |
+-------------------------+
       /|          |
        |           |
    [1] |       [2] |
        |          |/
+-------------------------+
|         MEMORY          |
+-------------------------+ _
       /|          |      |
        |           |        
    [3] |       [4] |          [5]
        |          |/         
+-------------------------+  +-------------------------+
|          DISK           |  |       CONFIG FILE       |
+-------------------------+  +-------------------------+

RUNTIME

Представляет структуры данных ProxySQL в памяти, содержит всю информацию для проксирования запросов

MEMORY (main)

Является базой данных в памяти, доступ к которой осуществляется через MySQL-клиент.

База содержит следующие таблицы:

  • mysql_servers – список внутренних серверов, к которым подключается ProxySQL;
  • mysql_users – список пользователей и их учетные данные, которые подключаются к ProxySQL и внутренним серверам;
  • mysql_query_rules – список правил запросов, которые анализируются при маршрутизации трафика;
  • global_variables – список глобальных переменных. Полезно для конфигурирования во время выполнения;
  • mysql_collations – список сопоставлений MySQL, доступных для работы с прокси. Извлекаются из клиентской библиотеки.

DISK

Представляет собой базу данных SQLite3 на диске. Располагается в $(DATADIR)/proxysql.db.

При перезапуске сервиса ProxySQL, все конфиги, которые правились в Memory, будут очищены. Поэтому очень важно сохранять все конфигурации в слой DISK, откуда уже идёт загрузка в MEMORY.

CONFIG FILE

Является классическим инструментом конфигурации.

Запуск

При обычном запуске, ProxySQL ищет свой конфигурационный файл, в котором определяется рабочая директория. Что произойдёт далее, зависит от наличия или отсутствия файла БД (DISK) в директории, которая указана в конфиге.

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

Если файла с БД нет, то он генерится на основе конфига и загружается в MEMORY и RUNTIME.

Установка

Для установки добавить репозиторий, заменив в baseurl …/centos/$releasever на нужную цифру, в данном случае RHEL 6, т.к. иначе выдаст 404 ошибку:

cat <<EOF | tee /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL YUM repository
baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.0.x/centos/6
gpgcheck=1
gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key
EOF

Во избежание ошибки Unable to parse unknown SET query я установил версию ProxySQL version 2.0.5-37-gc8e32ee, т.к. при выполнении некоторых запросов после настройки были глюки. Тема обсуждалась тут.

Проверить, что успешно запустился:

# service proxysql start
Starting ProxySQL: 2019-11-08 10:09:02 [INFO] Using config file /etc/proxysql.cnf
2019-11-08 10:09:02 [INFO] No SSL keys/certificates found in datadir (/var/lib/proxysql). Generating new keys/certificates.
DONE!

# service proxysql status
ProxySQL is running (10100).

Для управления через консольного клиента mysql нужно его установить:

yum install mysql

И проверить, что само подключение устаналивается:

mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '

Командой ниже можно проверить список имеющихся таблиц. В данном случае это уровень абстракции MEMORY, т.е. БД в памяти.

mysql> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_aws_aurora_hostgroups                |
| mysql_collations                           |
| mysql_galera_hostgroups                    |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_aws_aurora_hostgroups        |
| runtime_mysql_galera_hostgroups            |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
24 rows in set (0.00 sec)

Отсюда происходит перемещение конфигурации между уровнями посредством различных команд (написаны ниже). Цифра в начале команды для наглядности соответствует абстрактному уровню, представленному в официальной схеме взаимодействия (в начале статьи в разделе Архитектура):

  • [1] LOAD MYSQL USERS FROM MEMORY / LOAD MYSQL USERS TO RUNTIME
    • загружает пользователей MySQL из БД в памяти в структуры данных RUNTIME или наоборот
  • [2] SAVE MYSQL USERS TO MEMORY / SAVE MYSQL USERS FROM RUNTIME
    • сохраняет пользователей MySQL из RUNTIME в MEMORY
  • [3] LOAD MYSQL USERS TO MEMORY / LOAD MYSQL USERS FROM DISK
    • загружает постоянных пользователей MySQL из базы данных на диске в базу данных в памяти
  • [4] SAVE MYSQL USERS FROM MEMORY / SAVE MYSQL USERS TO DISK
    • сохраняет пользователей MySQL из базы данных в памяти в базу данных на диске
  • [5] LOAD MYSQL USERS FROM CONFIG
    • загружает из файла конфигурации пользователей в базу данных в памяти

Конфигурирование

Подготовка

На этом хватит теории и для полного понимания и закрепления пора переходить к практике. Исходные данные для понимания:

10.15.61.141 – ProxySQL & App
10.126.253.45 – SLAVE
10.126.253.46 – MASTER

Репликация в MySQL уже настроена. Перед началом хочу заметить, что лучше исключить из репликации таблицы b_sec_session, если сессии хранятся в БД, т.к. сами битриксы говорят, что это вызывает глюки при большой нагрузке.

Перед началом удобнее сразу создать двух пользователей на master и slave базах для доступа с сервера ProxySQL:

  • пользователь monitor , предварительно убедившись, что учетка monitor уже не используется для мониторинга самих слейвов. Через неё ProxySQL будет делать healthcheck:
GRANT REPLICATION SLAVE ON . TO 'monitor'@'10.15.61.141' IDENTIFIED BY 'monitor_pass';
  • пользователя, через которого подключается приложение к БД. В данном случае, т.к. ProxySQL находится на веб-ноде, где и само приложение, пользователь app_user уже должен быть с нужными правами:
GRANT ALL PRIVILEGES ON . TO 'app_user'@'10.15.61.141' identified by 'app_user_pass';

И ещё важный момент. ProxySQL в дальнейшем должен понимать, в какую группу отнести сервера: для чтения или для записи. Изначально я подумал, что это назначается вручную, но это была ошибка. ProxySQL, используя учётку monitoring, подключается к backend и смотрит значение переменной read_only в самом MySQL. Если значение 1, то запись в БД могут вносить только пользователи с привилегиями SUPER. Таким образом, можно быть уверенным, что на слейв придут запросы на изменение только со стороны мастера (если нет иных юзеров с правами SUPER). Этакий best practice. Поэтому для слейва нужно изменить значение этой переменной глобально и потом добавить его в конфиг:

mysql> 

SET @@GLOBAL.read_only=1;
my.cnf:

GLOBAL.read_only=1;

Добавление backend-серверов

Далее нужно залогиниться в консоль управления ProxySQL и добавить backend-сервера БД в нужный hostgroup:

mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt='Admin> '
INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'10.126.253.46',3306); # master
INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'10.126.253.45',3306); # slave

Да, здесь не опечатка, изначально и мастер и слейв сервера добавляются с одним hostgroup_id. Можно выбрать следующие поля (остальные пока не интересуют) и проверить:

SELECT hostgroup_id,hostname,port,status FROM mysql_servers;
+--------------+---------------+------+--------+
| hostgroup_id | hostname      | port | status |
+--------------+---------------+------+--------+
| 10           | 10.126.253.46 | 3306 | ONLINE |
| 10           | 10.126.253.45 | 3306 | ONLINE |
+--------------+---------------+------+--------+

Сохранение серверов:

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

Настройка мониторинга

В подготовительном этапе на мастере и слейве был создан пользователь monitor. Теперь, чтобы прокси мог подключаться, нужно указать учетные данные в его конфиге.

Логин:

UPDATE global_variables SET variable_value='monitor' WHERE variable_name='mysql-monitor_username';

Пароль:

UPDATE global_variables SET variable_value='monitor_pass' WHERE variable_name='mysql-monitor_password';

Чтобы эти значения подгрузились, нужно внести их в рантайм и на диск:

LOAD MYSQL VARIABLES TO RUNTIME;
SAVE MYSQL VARIABLES TO DISK;

Теперь если выполнить команду ниже, можно увидеть, что ProxySQL успешно “пингует” бэкенды и в поле connect_error значение NULL – значит всё ок:

SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 10;
+---------------+------+------------------+-------------------------+---------------+
| hostname      | port | time_start_us    | connect_success_time_us | connect_error |
+---------------+------+------------------+-------------------------+---------------+
| 10.126.253.45 | 3306 | 1573802777382753 | 1222                    | NULL          |
| 10.126.253.46 | 3306 | 1573802776718565 | 1490                    | NULL          |

Настройка таблицы для распределения запросов

Теперь нужно поработать с этой таблицей, которая пока пустая:

SHOW CREATE TABLE mysql_replication_hostgroupsG
*************************** 1. row ***************************
       table: mysql_replication_hostgroups
Create Table: CREATE TABLE mysql_replication_hostgroups (
    writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY,
    reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>=0),
    check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only','innodb_read_only','super_read_only','read_only|innodb_read_only','read_only&innodb_read_only')) NOT NULL DEFAULT 'read_only',
    comment VARCHAR NOT NULL DEFAULT '', UNIQUE (reader_hostgroup))

С её помощью, перечисленные в ней hostgroups могут быть настроены для для направления запросов до мастера или до слейва, как раз-таки на основе значения read_only.

INSERT INTO mysql_replication_hostgroups(writer_hostgroup, reader_hostgroup, comment) VALUES (10,20,'production'); 

В строке выше была добавлена запись с writer_hostgroup (10) и reader_hostgroup (20). В последней пока нет узлов – они туда будут помещены автоматически (благодаря проверке read_only).

Если у сервера read_only = 0, он будет перемещен в группу хостов 10, т.к. это Master
Если у сервера read_only = 1, он будет перемещен в группу хостов 20, т.к. это Slave

И для применения этого осталось выполнить загрузку в рантайм:

LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;

Теперь если выполнить команду ниже, видно, что в таблице сменился hostgroup_id на нужный:

SELECT hostgroup_id,hostname,port,status FROM mysql_servers;
+--------------+---------------+------+--------+
| hostgroup_id | hostname      | port | status |
+--------------+---------------+------+--------+
| 10           | 10.126.253.46 | 3306 | ONLINE |
| 20           | 10.126.253.45 | 3306 | ONLINE |
+--------------+---------------+------+--------+

Для проверки, что всё сохранилось и загружается, я делал рестарт сервиса ProxySQL и смотрел, не изменились ли записи в таблицах. Если нет, то всё ок, можно настраивать далее.

Настройка пользователей

Осталось добавить пользователя app_user, который будет подключаться к прокси, а тот уже, в свою очередь, обращаться в нужную базу.

INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('app_user','app_user_pass','10');

Стоит обратить внимание, что пользователю указывается default_hostgroup – группа, в которой мастер сервер.

Применение:

LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;

Проверка, что пользователь добавлен:

SELECT username,password,active,default_hostgroup,default_schema,max_connections,max_connections FROM mysql_users;

И проверить, что можно подключиться (консольным клиентом с сервера приложений):

mysql -u app_user -p'app_user' -h 127.0.0.1 -P6033 -e "SELECT @@server_id"

+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+

А также последняя проверка ещё раз, что ProxySQL может конектиться к бэку:

 select * from monitor.mysql_server_ping_log order by time_start_us desc limit 3;

На этом всё готово и можно переходить к самой сложной и важной части – настройки проксирования запросов.

Настройка правил запросов

Осталось настроить таблицу, в которой содержатся правила, на основе которых запросы будут отправляться в ту или иную группу:

INSERT INTO mysql_query_rules (rule_id,active,username,match_digest,destination_hostgroup,apply) VALUES (1,1,'user_app','^SELECT.*FOR UPDATE$',10,1),(2,1,'user_app','^.*b_sec_session.*',20,1),(3,1,'user_app','^SELECT',20,1);

Проверка:

SELECT rule_id,active, username, match_digest, destination_hostgroup, apply, multiplex FROM mysql_query_rules;
+---------+--------+----------+----------------------+-----------------------+-------+-----------+
| rule_id | active | username | match_digest         | destination_hostgroup | apply | multiplex |
+---------+--------+----------+----------------------+-----------------------+-------+-----------+
| 1       | 1      | trp3     | ^SELECT.*FOR UPDATE$ | 10                    | 1     | NULL      |
| 2       | 1      | trp3     | ^.*b_sec_session.*   | 10                    | 1     | NULL      |
| 3       | 1      | trp3     | ^SELECT              | 20                    | 1     | NULL      |
+---------+--------+----------+----------------------+-----------------------+-------+-----------+

P.S. В оф. документации не указан пользователь (поле username) при наполнении таблицы mysql_query_rules. Без этого поля (без добавления оно будет NULL) у меня возникали непонятные ошибки и глюки.

Проверка, что по созданным правилам запросов выше есть хиты, т.е. всё работает:

SELECT rule_id, hits, destination_hostgroup hg FROM mysql_query_rules NATURAL JOIN stats_mysql_query_rules;

Сохранение:

LOAD MYSQL QUERY RULES TO RUNTIME;
SAVE MYSQL QUERY RULES TO DISK;

Теперь всё минимально настроено и в настройках приложения можно переключаться на инстанс ProxySQL, который слушает локально на том же сервере, где и само приложение на порту 6033 – 127.0.0.1:6033

После открытия портала, побегав по страницам, можно выполнить запрос и увидеть, что поле Queries растёт в нужной hostgroup, а значит всё ок:

select hostgroup,srv_host,status,Queries,Bytes_data_sent,Latency_us from stats_mysql_connection_pool where hostgroup in (20,10);
+-----------+---------------+--------+---------+-----------------+------------+
| hostgroup | srv_host      | status | Queries | Bytes_data_sent | Latency_us |
+-----------+---------------+--------+---------+-----------------+------------+
| 10        | 10.126.253.46 | ONLINE | 42256   | 4810810         | 311        |
| 20        | 10.126.253.45 | ONLINE | 12276   | 3022946         | 416        |
+-----------+---------------+--------+---------+-----------------+------------+

В общем и целом на этом настройка закончена. В админке битрикса лучше заранее перед настройкой ProxySQL выпилить старые настройки слейвов в модуле “Веб-кластер”, а также перезапустить сервис кеширования (memcached в моём случае), если таковой используется.

По-хорошему, при использовании данного решения в продакшене, нужно ещё будет дополнительно настроить slave_lag, чтобы в случае разъехавшейся репликации, запросы перекидывались на мастер.

Возникающие ошибки:

В процессе настройки приложение себя вело странным образом, выдавая те или иные ошибки. При решении всегда смотреть в /var/lib/proxysql/proxysql.log

  • Unable to get session lock within 60 seconds (в браузере)
  • ERROR 2013 (HY000): Lost connection to MySQL server during query (в proxysql.log)

Данные ошибки были связаны с некорректными таймаутами в настройках серверов MySQL, на мастере и слейве в my.cnf:

net_read_timeout=600
interactive_timeout=600
wait_timeout=600
connect_timeout=600

wait_timeout – таймаут ожидания необходим, чтобы защищать приложением в том случае, когда клиенты ничего не делают, кроме как поглощают соединение. По истечении 600 сек бездействующих клиентов отключает по таймауту;

interactive_timeout – используется только для соединений с интерактивными клиентами, такими как клиенты MySQL из командной строки, с этим вроде как понятно. Обычно значение устанавливается как и wait_timeout , но в отдельных случаях может быть изменено.

net_read_timeout – количество секунд ожидания для получения дополнительных данных из соединения перед прекращением чтения. Аналогично и для клиентов, ведущих запись.

connection_timeout – сколько ждать ответа сервера перед тем, как выдать ошибку о том, что сервер не отвечает. Именно с данным параметром, значение которого увеличил с 30 до 600, ошибка Unable to get session lock within 60 seconds перестала появляться.

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

Используемые источники

  • https://habr.com/ru/company/bitrix/blog/147098/
  • https://github.com/sysown/proxysql/wiki/ProxySQL-Configuration
  • https://github.com/sysown/proxysql/issues/1903

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Error unable to obtain session lock перевод
  • Error unable to normalize symbol name for the following short stack
  • Error unclosed character literal java
  • Error unable to match delimiters перевод
  • Error unclean shutdown

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии