+7 495 008 8452 пн.-пт. 10:00 – 17:00
Если у вас возникли какие либо вопросы которые вы не смогли решить по нашим публикациям самостоятельно,
то ждем ваше обращение в нашей службе тех поддержки.


Кардинально ускоряем Bitrix+MSSQL

В этом посте я хотел бы рассказать о своём опыте оптимизации работы Битрикса, работающего на Windows-платформе под MSSQL.



Начать разбираться с производительностью такой связки меня побудило исключительно появление версии 8.5 с переработанным модулем "Производительность". Именно возможность получить оценку своего хостинга и сравнить с другими площадками дала толчок этому исследованию.

Итак, как только вышла версия 8.5, то я первым делом полез в панель производительности, чтобы увидеть заветные цифры. Радость обновления Битрикса сменилась горечью результата: где-то в районе 4-6 на не самом плохом оборудовании.

Оптимизация №1

При анализе и игре с настройками php и Битрикса я заметил упоминание про WinCache, о котором раньше не слышал. Немного поиска выдало хорошие рекомендации "лучших собаководов" и красивые графики роста производительности. Настройка и установка прошли легко и их итог хорошо виден тут:

Более детально про Wincache можно прочитать тут

Радоваться можно было уже от этого результата, все показатели разом улучшились где-то в 2 раза, сайт и админка стали заметно быстрее загружаться. Однако было грустно от полученных значений БД, особенно чтения. 1000-1200 -- это совсем не то, что может выдавать выделенный MSSQL сервер, поэтому...

Оптимизация №2

Первым делом был разобран сам модуль производительности и из него был извлечён модуль оценки БД. Для него я подстроил имевшийся в запасниках мини класс для работы с базой данных, но через драйвер sqlsrv. Запуск в консоли показал интересный результат в 3200+ запросов на чтение, что было в 3(!) раза больше, чем в тесте Битрикса(скриншот выше). Использование аналогичного мини класса, но на odbc, показало значение около 1200.

Неужели драйвер odbc так сильно проигрывает драйверу от Microsoft? Возможно, но корень зла оказался немного в другом.

Получив такой неожиданный результат появился профессиональный азарт "перебрать двигатель" Битрикса, а именно его класс работы с БД в
/bitrix/modules/main/classes/mssql/database.php
и перевести его на рельсы sqlsrv. Эта задача не такая и сложная, все вызовы очень похожи, лишь немного переделан код получения данных:
function __fetch_array($rownumber=false, $result=false)
{
....
$row=array();
$numfields=sqlsrv_num_fields($result);
$fieldmeta = sqlsrv_field_metadata($result);        

for ($i=0; $i<$numfields; $i++)
{
  if ( $fieldmeta[$i]['Type'] == SQLSRV_SQLTYPE_IMAGE )
    $row[$fieldmeta[$i]['Name']] = sqlsrv_get_field($result, $i, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY));
  else            
    $row[$fieldmeta[$i]['Name']] = sqlsrv_get_field($result, $i, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
}
....
}
Так же стоит отметить, что
  • При хранении сессий в базе данных нужно аналогично отредактировать /bitrix/modules/security/classes/mssql/session.php (других мест прямых вызов odbc найдено не было)
  • в dbconn.php нужно будет исправить $DBHost, чтобы он указывал сразу на сервер
Единственный тонкий момент, который возник, это постраничный забор данных(в NavQuery), который был решён использованием SQLSRV_CURSOR_STATIC. Всё казалось готовым к старту, ключ зажигания включен и вроде бы взлетели: сайт вёл себя адекватно, проблем вроде не замечено. Вот только особого ускорения не почувствовалось, что подтвердили тесты: общая производительность поднялась где-то на 1-2 балла, и количество чтений БД выросло лишь "в пределах погрешности измерений".

"Так не бывает и должно быть разумное объяснение" крутилось в голове и оно было найдено... после отключения SQLSRV_CURSOR_STATIC:


Корень зла оказался в курсорах. По умолчанию в odbc выбран статический курсор (SQL_CURSOR_STATIC), который позволяет произвольно перемещаться вперёд-назад по выборке. Драйвер sqlsrv наоборот по умолчанию задаёт тип последовательный курсор(SQLSRV_CURSOR_FORWARD), способный двигаться только вперёд. Во всём коде database.php есть лишь одно место, где реально используются переходы курсоров, а именно в NavQuery. Там пролистываются результаты до нужной страницы, если не установлен NavShowAll. Более того, записи листаются исключительно вперёд.

Возникает вопрос к разработчикам Битрикса: а так ли необходимо использовать *_CURSOR_STATIC, серьёзно терять в производительности, и всё ради мнимого удобства переключения на N-ую запись? Может лучше быстро сделать sqlsrv_fetch или odbc_fetch_row нужное количество раз?

Из тех 20-50+ запросов, что делает Битрикс, не более десяти реально будут использовать навигацию, в то время как остальные тратят драгоценные ресурсы на создание статических курсоров.

Итог

Достигнутый результат полностью удовлетворяет. Производительность поднялась кардинально, что отражает скачок оценки от ~5 до ~21, страницы стали загружаться ощутимо быстрее, время отклика упало с ~900мс до ~300мс.

P.S. Попытка сделать последовательный курсор в ODBC успехом не увенчалась, возможно я что-то делал не так, но желания копаться уже нет.

P.P.S. Применение второго метода оптимизации конечно же предлагается в варианте "As Is" без каких либо гарантий.


Назад в раздел

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












CAPTCHA